mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-28 22:49:43 +02:00
jz4740 asoc: Add new internel codec driver.
Add qi lb60 board support. Remove unneeded files.
This commit is contained in:
parent
299c9e29ef
commit
8bb63272c3
939
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.c
Executable file → Normal file
939
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.c
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
16
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.h
Executable file → Normal file
16
target/linux/xburst/files-2.6.31/sound/soc/codecs/jzcodec.h
Executable file → Normal file
@ -1,22 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
|
||||||
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _ICODEC_H
|
#ifndef _ICODEC_H
|
||||||
#define _ICODEC_H
|
#define _ICODEC_H
|
||||||
|
|
||||||
/* jzcodec register space */
|
|
||||||
#define ICODEC_1_LOW 0x00 /* bit0 -- bit15 in CDCCR1 */
|
|
||||||
#define ICODEC_1_HIGH 0x01 /* bit16 -- bit31 in CDCCR1 */
|
|
||||||
#define ICODEC_2_LOW 0x02 /* bit0 -- bit16 in CDCCR2 */
|
|
||||||
#define ICODEC_2_HIGH 0x03 /* bit16 -- bit31 in CDCCR2 */
|
|
||||||
|
|
||||||
#define JZCODEC_CACHEREGNUM 4
|
|
||||||
#define JZCODEC_SYSCLK 0
|
#define JZCODEC_SYSCLK 0
|
||||||
|
|
||||||
extern struct snd_soc_dai jzcodec_dai;
|
extern struct snd_soc_dai jz_codec_dai;
|
||||||
extern struct snd_soc_codec_device soc_codec_dev_jzcodec;
|
extern struct snd_soc_codec_device soc_codec_dev_jzcodec;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,981 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/ac97_codec.h>
|
|
||||||
#include <sound/initval.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
#include <sound/soc-dapm.h>
|
|
||||||
|
|
||||||
#include "../jz4750/jz4750-pcm.h"
|
|
||||||
#include "jzdlv.h"
|
|
||||||
|
|
||||||
#define AUDIO_NAME "jzdlv"
|
|
||||||
#define JZDLV_VERSION "1.0"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Debug
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define JZDLV_DEBUG 0
|
|
||||||
|
|
||||||
#ifdef JZDLV_DEBUG
|
|
||||||
#define dbg(format, arg...) \
|
|
||||||
printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
|
|
||||||
#else
|
|
||||||
#define dbg(format, arg...) do {} while (0)
|
|
||||||
#endif
|
|
||||||
#define err(format, arg...) \
|
|
||||||
printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
|
|
||||||
#define info(format, arg...) \
|
|
||||||
printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
|
|
||||||
#define warn(format, arg...) \
|
|
||||||
printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
|
|
||||||
|
|
||||||
struct snd_soc_codec_device soc_codec_dev_jzdlv;
|
|
||||||
|
|
||||||
/* codec private data */
|
|
||||||
struct jzdlv_priv {
|
|
||||||
unsigned int sysclk;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* jzdlv register cache
|
|
||||||
*/
|
|
||||||
static u16 jzdlv_reg[JZDLV_CACHEREGNUM];
|
|
||||||
|
|
||||||
int read_codec_file(int addr)
|
|
||||||
{
|
|
||||||
while (__icdc_rgwr_ready());
|
|
||||||
__icdc_set_addr(addr);
|
|
||||||
mdelay(1);
|
|
||||||
return(__icdc_get_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printk_codec_files(void)
|
|
||||||
{
|
|
||||||
int cnt, val;
|
|
||||||
|
|
||||||
//printk("\n");
|
|
||||||
#if 0
|
|
||||||
printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR);
|
|
||||||
printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR);
|
|
||||||
printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR);
|
|
||||||
printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR);
|
|
||||||
printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR);
|
|
||||||
printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR);
|
|
||||||
printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR);
|
|
||||||
printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA);
|
|
||||||
#endif
|
|
||||||
for (cnt = 0; cnt < JZDLV_CACHEREGNUM ; cnt++) {
|
|
||||||
val = read_codec_file(cnt);
|
|
||||||
jzdlv_reg[cnt] = val;
|
|
||||||
//printk(" ( %d : 0x%x ) ",cnt ,jzdlv_reg[cnt]);
|
|
||||||
}
|
|
||||||
//printk("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_codec_file(int addr, int val)
|
|
||||||
{
|
|
||||||
while (__icdc_rgwr_ready());
|
|
||||||
__icdc_set_addr(addr);
|
|
||||||
__icdc_set_cmd(val); /* write */
|
|
||||||
mdelay(1);
|
|
||||||
__icdc_set_rgwr();
|
|
||||||
mdelay(1);
|
|
||||||
//jzdlv_reg[addr] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_codec_file_bit(int addr, int bitval, int mask_bit)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
while (__icdc_rgwr_ready());
|
|
||||||
__icdc_set_addr(addr);
|
|
||||||
mdelay(1);
|
|
||||||
val = __icdc_get_value(); /* read */
|
|
||||||
|
|
||||||
val &= ~(1 << mask_bit);
|
|
||||||
if (bitval == 1)
|
|
||||||
val |= 1 << mask_bit;
|
|
||||||
#if 0
|
|
||||||
while (__icdc_rgwr_ready());
|
|
||||||
__icdc_set_addr(addr);
|
|
||||||
__icdc_set_cmd(val); /* write */
|
|
||||||
mdelay(1);
|
|
||||||
__icdc_set_rgwr();
|
|
||||||
mdelay(1);
|
|
||||||
#else
|
|
||||||
write_codec_file(addr, val);
|
|
||||||
#endif
|
|
||||||
while (__icdc_rgwr_ready());
|
|
||||||
__icdc_set_addr(addr);
|
|
||||||
val = __icdc_get_value(); /* read */
|
|
||||||
|
|
||||||
if (((val >> mask_bit) & bitval) == bitval)
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* read jzdlv register cache
|
|
||||||
*/
|
|
||||||
static inline unsigned int jzdlv_read_reg_cache(struct snd_soc_codec *codec,
|
|
||||||
unsigned int reg)
|
|
||||||
{
|
|
||||||
u16 *cache = codec->reg_cache;
|
|
||||||
|
|
||||||
if (reg >= JZDLV_CACHEREGNUM)
|
|
||||||
return -1;
|
|
||||||
return cache[reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int jzdlv_read(struct snd_soc_codec *codec,
|
|
||||||
unsigned int reg)
|
|
||||||
{
|
|
||||||
u8 data;
|
|
||||||
data = reg;
|
|
||||||
if (codec->hw_write(codec->control_data, &data, 1) != 1)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (codec->hw_read(codec->control_data, &data, 1) != 1)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write jzdlv register cache
|
|
||||||
*/
|
|
||||||
static inline void jzdlv_write_reg_cache(struct snd_soc_codec *codec,
|
|
||||||
unsigned int reg, u16 value)
|
|
||||||
{
|
|
||||||
u16 *cache = codec->reg_cache;
|
|
||||||
|
|
||||||
if (reg >= JZDLV_CACHEREGNUM) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cache[reg] = value;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* write to the jzdlv register space
|
|
||||||
*/
|
|
||||||
static int jzdlv_write(struct snd_soc_codec *codec, unsigned int reg,
|
|
||||||
unsigned int value)
|
|
||||||
{
|
|
||||||
jzdlv_write_reg_cache(codec, reg, value);
|
|
||||||
if(codec->hw_write)
|
|
||||||
codec->hw_write(&value, NULL, reg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *jzdlv_input_select[] = {"Line In", "Mic"};
|
|
||||||
static const char *jzdlv_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
|
|
||||||
|
|
||||||
static const struct soc_enum jzdlv_enum[] = {
|
|
||||||
SOC_ENUM_SINGLE(0x04, 2, 2, jzdlv_input_select),
|
|
||||||
SOC_ENUM_SINGLE(0x05, 1, 4, jzdlv_deemph),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* set Audio data replay */
|
|
||||||
void set_audio_data_replay(void)
|
|
||||||
{
|
|
||||||
write_codec_file(9, 0xff);
|
|
||||||
write_codec_file(8, 0x20);// only CCMC
|
|
||||||
mdelay(10);
|
|
||||||
|
|
||||||
/* DAC path */
|
|
||||||
write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0
|
|
||||||
write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
|
|
||||||
write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
|
|
||||||
|
|
||||||
write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
|
|
||||||
write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1
|
|
||||||
|
|
||||||
write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
|
|
||||||
mdelay(100);
|
|
||||||
write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
|
|
||||||
write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
|
|
||||||
write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
|
|
||||||
mdelay(100);
|
|
||||||
write_codec_file_bit(1, 0, 5);//DAC_MUTE->0
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unset Audio data replay */
|
|
||||||
void unset_audio_data_replay(void)
|
|
||||||
{
|
|
||||||
write_codec_file_bit(1, 1, 5);//DAC_MUTE->1
|
|
||||||
mdelay(200);
|
|
||||||
write_codec_file_bit(5, 1, 6);//SB_OUT->1
|
|
||||||
write_codec_file_bit(5, 1, 7);//SB_DAC->1
|
|
||||||
write_codec_file_bit(5, 1, 4);//SB_MIX->1
|
|
||||||
write_codec_file_bit(6, 1, 0);//SB_SLEEP->1
|
|
||||||
write_codec_file_bit(6, 1, 1);//SB->1
|
|
||||||
|
|
||||||
write_codec_file(9, 0xff);
|
|
||||||
write_codec_file(8, 0x3f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set Record MIC input audio without playback */
|
|
||||||
static void set_record_mic_input_audio_without_playback(void)
|
|
||||||
{
|
|
||||||
/* ADC path for MIC IN */
|
|
||||||
write_codec_file_bit(1, 1, 2);
|
|
||||||
write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0
|
|
||||||
//write_codec_file_bit(1, 1, 6);//CR1.MONO->1
|
|
||||||
|
|
||||||
write_codec_file(22, 0x40);//mic 1
|
|
||||||
write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0
|
|
||||||
write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1
|
|
||||||
write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1
|
|
||||||
write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1
|
|
||||||
|
|
||||||
write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0
|
|
||||||
write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0
|
|
||||||
write_codec_file_bit(6, 1, 3);// gain set
|
|
||||||
|
|
||||||
write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0
|
|
||||||
mdelay(100);
|
|
||||||
write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0
|
|
||||||
write_codec_file(1, 0x4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unset Record MIC input audio without playback */
|
|
||||||
static void unset_record_mic_input_audio_without_playback(void)
|
|
||||||
{
|
|
||||||
/* ADC path for MIC IN */
|
|
||||||
write_codec_file_bit(5, 1, 4);//SB_ADC->1
|
|
||||||
write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1
|
|
||||||
write_codec_file(22, 0xc0);//CR3.SB_MIC1
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static irqreturn_t aic_codec_irq(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
u8 file_9 = read_codec_file(9);
|
|
||||||
u8 file_8 = read_codec_file(8);
|
|
||||||
|
|
||||||
//printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9);
|
|
||||||
if ((file_9 & 0x1f) == 0x10) {
|
|
||||||
// have hp short circuit
|
|
||||||
write_codec_file(8, 0x3f);//mask all interrupt
|
|
||||||
write_codec_file_bit(5, 1, 6);//SB_OUT->1
|
|
||||||
mdelay(300);
|
|
||||||
while ((read_codec_file(9) & 0x4) != 0x4);
|
|
||||||
while ((read_codec_file(9) & 0x10) == 0x10) {
|
|
||||||
write_codec_file(9, 0x10);
|
|
||||||
}
|
|
||||||
write_codec_file_bit(5, 0, 6);//SB_OUT->0
|
|
||||||
mdelay(300);
|
|
||||||
while ((read_codec_file(9) & 0x8) != 0x8);
|
|
||||||
write_codec_file(9, file_9);
|
|
||||||
write_codec_file(8, file_8);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_9 & 0x8)
|
|
||||||
ramp_up_end = jiffies;
|
|
||||||
else if (file_9 & 0x4)
|
|
||||||
ramp_down_end = jiffies;
|
|
||||||
else if (file_9 & 0x2)
|
|
||||||
gain_up_end = jiffies;
|
|
||||||
else if (file_9 & 0x1)
|
|
||||||
gain_down_end = jiffies;
|
|
||||||
|
|
||||||
write_codec_file(9, file_9);
|
|
||||||
if (file_9 & 0xf)
|
|
||||||
wake_up(&pop_wait_queue);
|
|
||||||
while (REG_ICDC_RGDATA & 0x100);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static irqreturn_t aic_codec_irq(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
u8 file_9 = read_codec_file(9);
|
|
||||||
u8 file_8 = read_codec_file(8);
|
|
||||||
|
|
||||||
//printk("--- 1 8:0x%x 9:0x%x ---\n",file_8,file_9);
|
|
||||||
if ((file_9 & 0x1f) == 0x10) {
|
|
||||||
write_codec_file(8, 0x3f);
|
|
||||||
write_codec_file_bit(5, 1, 6);//SB_OUT->1
|
|
||||||
mdelay(300);
|
|
||||||
while ((read_codec_file(9) & 0x4) != 0x4);
|
|
||||||
while ((read_codec_file(9) & 0x10) == 0x10) {
|
|
||||||
write_codec_file(9, 0x10);
|
|
||||||
}
|
|
||||||
write_codec_file_bit(5, 0, 6);//SB_OUT->0
|
|
||||||
mdelay(300);
|
|
||||||
while ((read_codec_file(9) & 0x8) != 0x8);
|
|
||||||
write_codec_file(9, file_9);
|
|
||||||
write_codec_file(8, file_8);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
/*if (file_9 & 0x8)
|
|
||||||
ramp_up_end = jiffies;
|
|
||||||
else if (file_9 & 0x4)
|
|
||||||
ramp_down_end = jiffies;
|
|
||||||
else if (file_9 & 0x2)
|
|
||||||
gain_up_end = jiffies;
|
|
||||||
else if (file_9 & 0x1)
|
|
||||||
gain_down_end = jiffies;*/
|
|
||||||
|
|
||||||
write_codec_file(9, file_9);
|
|
||||||
/*if (file_9 & 0xf)
|
|
||||||
wake_up(&pop_wait_queue);*/
|
|
||||||
while (REG_ICDC_RGDATA & 0x100);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int jzdlv_reset(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
/* reset DLV codec. from hibernate mode to sleep mode */
|
|
||||||
write_codec_file(0, 0xf);
|
|
||||||
write_codec_file_bit(6, 0, 0);
|
|
||||||
write_codec_file_bit(6, 0, 1);
|
|
||||||
mdelay(200);
|
|
||||||
//write_codec_file(0, 0xf);
|
|
||||||
write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
|
|
||||||
write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
|
|
||||||
mdelay(10);//wait for stability
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int jzdlv_sync(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
u16 *cache = codec->reg_cache;
|
|
||||||
int i, r = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < JZDLV_CACHEREGNUM; i++)
|
|
||||||
r |= jzdlv_write(codec, i, cache[i]);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct snd_kcontrol_new jzdlv_snd_controls[] = {
|
|
||||||
|
|
||||||
//SOC_DOUBLE_R("Master Playback Volume", 1, 1, 0, 3, 0),
|
|
||||||
SOC_DOUBLE_R("Master Playback Volume", DLV_CGR8, DLV_CGR9, 0, 31, 0),
|
|
||||||
//SOC_DOUBLE_R("MICBG", ICODEC_2_LOW, ICODEC_2_LOW, 4, 3, 0),
|
|
||||||
//SOC_DOUBLE_R("Line", 2, 2, 0, 31, 0),
|
|
||||||
SOC_DOUBLE_R("Line", DLV_CGR10, DLV_CGR10, 0, 15, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* add non dapm controls */
|
|
||||||
static int jzdlv_add_controls(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
int err, i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(jzdlv_snd_controls); i++) {
|
|
||||||
err = snd_ctl_add(codec->card,
|
|
||||||
snd_soc_cnew(&jzdlv_snd_controls[i], codec, NULL));
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Output Mixer */
|
|
||||||
static const struct snd_kcontrol_new jzdlv_output_mixer_controls[] = {
|
|
||||||
SOC_DAPM_SINGLE("Line Bypass Switch", 0x04, 3, 1, 0),
|
|
||||||
SOC_DAPM_SINGLE("Mic Sidetone Switch", 0x04, 5, 1, 0),
|
|
||||||
SOC_DAPM_SINGLE("HiFi Playback Switch", 0x04, 4, 1, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Input mux */
|
|
||||||
static const struct snd_kcontrol_new jzdlv_input_mux_controls =
|
|
||||||
SOC_DAPM_ENUM("Input Select", jzdlv_enum[0]);
|
|
||||||
|
|
||||||
static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = {
|
|
||||||
SND_SOC_DAPM_MIXER("Output Mixer", 0x06, 4, 1,
|
|
||||||
&jzdlv_output_mixer_controls[0],
|
|
||||||
ARRAY_SIZE(jzdlv_output_mixer_controls)),
|
|
||||||
//SND_SOC_DAPM_DAC("DAC", "HiFi Playback", 0x06, 3, 1),
|
|
||||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
|
||||||
SND_SOC_DAPM_OUTPUT("LHPOUT"),
|
|
||||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
|
||||||
SND_SOC_DAPM_OUTPUT("RHPOUT"),
|
|
||||||
//SND_SOC_DAPM_ADC("ADC", "HiFi Capture", 0x06, 2, 1),
|
|
||||||
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &jzdlv_input_mux_controls),
|
|
||||||
SND_SOC_DAPM_PGA("Line Input", 0x06, 0, 1, NULL, 0),
|
|
||||||
SND_SOC_DAPM_MICBIAS("Mic Bias", 0x06, 1, 1),
|
|
||||||
SND_SOC_DAPM_INPUT("MICIN"),
|
|
||||||
SND_SOC_DAPM_INPUT("RLINEIN"),
|
|
||||||
SND_SOC_DAPM_INPUT("LLINEIN"),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const struct snd_soc_dapm_route intercon[] = {
|
|
||||||
/* output mixer */
|
|
||||||
{"Output Mixer", "Line Bypass Switch", "Line Input"},
|
|
||||||
{"Output Mixer", "HiFi Playback Switch", "DAC"},
|
|
||||||
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
|
|
||||||
|
|
||||||
/* outputs */
|
|
||||||
{"RHPOUT", NULL, "Output Mixer"},
|
|
||||||
{"ROUT", NULL, "Output Mixer"},
|
|
||||||
{"LHPOUT", NULL, "Output Mixer"},
|
|
||||||
{"LOUT", NULL, "Output Mixer"},
|
|
||||||
|
|
||||||
/* input mux */
|
|
||||||
{"Input Mux", "Line In", "Line Input"},
|
|
||||||
{"Input Mux", "Mic", "Mic Bias"},
|
|
||||||
{"ADC", NULL, "Input Mux"},
|
|
||||||
|
|
||||||
/* inputs */
|
|
||||||
{"Line Input", NULL, "LLINEIN"},
|
|
||||||
{"Line Input", NULL, "RLINEIN"},
|
|
||||||
{"Mic Bias", NULL, "MICIN"},
|
|
||||||
};
|
|
||||||
|
|
||||||
static void init_codec(void)
|
|
||||||
{
|
|
||||||
/* reset DLV codec. from hibernate mode to sleep mode */
|
|
||||||
write_codec_file(0, 0xf);
|
|
||||||
write_codec_file_bit(6, 0, 0);
|
|
||||||
write_codec_file_bit(6, 0, 1);
|
|
||||||
mdelay(200);
|
|
||||||
//write_codec_file(0, 0xf);
|
|
||||||
write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
|
|
||||||
write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0
|
|
||||||
mdelay(10);//wait for stability
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_add_widgets(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
snd_soc_dapm_new_controls(codec, jzdlv_dapm_widgets,
|
|
||||||
ARRAY_SIZE(jzdlv_dapm_widgets));
|
|
||||||
|
|
||||||
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
|
|
||||||
|
|
||||||
snd_soc_dapm_new_widgets(codec);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_device *socdev = rtd->socdev;
|
|
||||||
struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
int speed = 0;
|
|
||||||
int val = 0;
|
|
||||||
|
|
||||||
/* sample channel */
|
|
||||||
switch (params_channels(params)) {
|
|
||||||
case 1:
|
|
||||||
write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* sample rate */
|
|
||||||
switch (params_rate(params)) {
|
|
||||||
case 8000:
|
|
||||||
speed = 10;
|
|
||||||
break;
|
|
||||||
case 9600:
|
|
||||||
speed = 9;
|
|
||||||
break;
|
|
||||||
case 11025:
|
|
||||||
speed = 8;
|
|
||||||
break;
|
|
||||||
case 12000:
|
|
||||||
speed = 7;
|
|
||||||
break;
|
|
||||||
case 16000:
|
|
||||||
speed = 6;
|
|
||||||
break;
|
|
||||||
case 22050:
|
|
||||||
speed = 5;
|
|
||||||
break;
|
|
||||||
case 24000:
|
|
||||||
speed = 4;
|
|
||||||
break;
|
|
||||||
case 32000:
|
|
||||||
speed = 3;
|
|
||||||
break;
|
|
||||||
case 44100:
|
|
||||||
speed = 2;
|
|
||||||
break;
|
|
||||||
case 48000:
|
|
||||||
speed = 1;
|
|
||||||
break;
|
|
||||||
case 96000:
|
|
||||||
speed = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printk(" invalid rate :0x%08x\n",params_rate(params));
|
|
||||||
}
|
|
||||||
|
|
||||||
val = (speed << 4) | speed;
|
|
||||||
jzdlv_write(codec, DLV_CCR2, val);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
//struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
//struct snd_soc_device *socdev = rtd->socdev;
|
|
||||||
//struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
|
||||||
//case SNDRV_PCM_TRIGGER_RESUME:
|
|
||||||
//case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
||||||
init_codec();
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
mdelay(1);
|
|
||||||
set_audio_data_replay();
|
|
||||||
mdelay(5);
|
|
||||||
write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
|
|
||||||
__aic_flush_fifo();
|
|
||||||
} else {
|
|
||||||
set_record_mic_input_audio_without_playback();
|
|
||||||
mdelay(10);
|
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
mdelay(20);
|
|
||||||
__aic_flush_fifo();
|
|
||||||
write_codec_file_bit(5, 1, 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
|
||||||
//case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
||||||
//case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
unset_audio_data_replay();
|
|
||||||
} else {
|
|
||||||
unset_record_mic_input_audio_without_playback();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_pcm_prepare(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_device *socdev = rtd->socdev;
|
|
||||||
struct snd_soc_codec *codec = socdev->codec; */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jzdlv_shutdown(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_device *socdev = rtd->socdev;
|
|
||||||
struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
|
|
||||||
/* deactivate */
|
|
||||||
if (!codec->active) {
|
|
||||||
udelay(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_mute(struct snd_soc_dai *dai, int mute)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = dai->codec;
|
|
||||||
u16 reg_val = jzdlv_read_reg_cache(codec, 2/*DLV_1_LOW*/);
|
|
||||||
|
|
||||||
if (mute != 0)
|
|
||||||
mute = 1;
|
|
||||||
if (mute)
|
|
||||||
reg_val = reg_val | (0x1 << 14);
|
|
||||||
else
|
|
||||||
reg_val = reg_val & ~(0x1 << 14);
|
|
||||||
|
|
||||||
//jzdlv_write(codec, DLV_1_LOW, reg_val);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|
||||||
int clk_id, unsigned int freq, int dir)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = codec_dai->codec;
|
|
||||||
struct jzdlv_priv *jzdlv = codec->private_data;
|
|
||||||
|
|
||||||
jzdlv->sysclk = freq;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Set's ADC and Voice DAC format. called by apus_hw_params() in apus.c
|
|
||||||
*/
|
|
||||||
static int jzdlv_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|
||||||
unsigned int fmt)
|
|
||||||
{
|
|
||||||
/* struct snd_soc_codec *codec = codec_dai->codec; */
|
|
||||||
|
|
||||||
/* set master/slave audio interface. codec side */
|
|
||||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
|
||||||
case SND_SOC_DAIFMT_CBM_CFM:
|
|
||||||
/* set master mode for codec */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_CBS_CFS:
|
|
||||||
/* set slave mode for codec */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* interface format . set some parameter for codec side */
|
|
||||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
|
||||||
case SND_SOC_DAIFMT_I2S:
|
|
||||||
/* set I2S mode for codec */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_RIGHT_J:
|
|
||||||
/* set right J mode */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_LEFT_J:
|
|
||||||
/* set left J mode */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_DSP_A:
|
|
||||||
/* set dsp A mode */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_DSP_B:
|
|
||||||
/* set dsp B mode */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clock inversion. codec side */
|
|
||||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
|
||||||
case SND_SOC_DAIFMT_NB_NF:
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_IB_IF:
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_IB_NF:
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_NB_IF:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* jzcodec_write(codec, 0, val); */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_dapm_event(struct snd_soc_codec *codec, int event)
|
|
||||||
{
|
|
||||||
/* u16 reg_val; */
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case SNDRV_CTL_POWER_D0: /* full On */
|
|
||||||
/* vref/mid, osc on, dac unmute */
|
|
||||||
/* u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); */
|
|
||||||
/* jzcodec_write(codec, 0, val); */
|
|
||||||
break;
|
|
||||||
case SNDRV_CTL_POWER_D1: /* partial On */
|
|
||||||
case SNDRV_CTL_POWER_D2: /* partial On */
|
|
||||||
break;
|
|
||||||
case SNDRV_CTL_POWER_D3hot: /* Off, with power */
|
|
||||||
/* everything off except vref/vmid, */
|
|
||||||
/*reg_val = 0x0800;
|
|
||||||
jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
|
|
||||||
reg_val = 0x0017;
|
|
||||||
jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
|
|
||||||
REG_ICDC_CDCCR1 = jzcodec_reg[0];
|
|
||||||
mdelay(2);
|
|
||||||
reg_val = 0x2102;
|
|
||||||
jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
|
|
||||||
reg_val = 0x001f;
|
|
||||||
jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
|
|
||||||
REG_ICDC_CDCCR1 = jzcodec_reg[0];
|
|
||||||
mdelay(2);
|
|
||||||
reg_val = 0x3302;
|
|
||||||
jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val);
|
|
||||||
reg_val = 0x0003;
|
|
||||||
jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val);
|
|
||||||
REG_ICDC_CDCCR1 = jzcodec_reg[0];*/
|
|
||||||
break;
|
|
||||||
case SNDRV_CTL_POWER_D3cold: /* Off, without power */
|
|
||||||
/* everything off, dac mute, inactive */
|
|
||||||
/*reg_val = 0x2302;
|
|
||||||
jzcodec_write(codec, ICODEC_1_LOW, reg_val);
|
|
||||||
reg_val = 0x001b;
|
|
||||||
jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
|
|
||||||
mdelay(1);
|
|
||||||
reg_val = 0x2102;
|
|
||||||
jzcodec_write(codec, ICODEC_1_LOW, reg_val);
|
|
||||||
reg_val = 0x001b;
|
|
||||||
jzcodec_write(codec, ICODEC_1_HIGH, reg_val);*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//codec->dapm_state = event;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define JZDLV_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
|
||||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
|
|
||||||
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
|
||||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_12000 |\
|
|
||||||
SNDRV_PCM_RATE_24000)
|
|
||||||
|
|
||||||
#define JZDLV_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
|
|
||||||
|
|
||||||
struct snd_soc_dai jzdlv_dai = {
|
|
||||||
.name = "JZDLV",
|
|
||||||
.playback = {
|
|
||||||
.stream_name = "Playback",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZDLV_RATES,
|
|
||||||
.formats = JZDLV_FORMATS,},
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "Capture",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZDLV_RATES,
|
|
||||||
.formats = JZDLV_FORMATS,},
|
|
||||||
.ops = {
|
|
||||||
.trigger = jzdlv_pcm_trigger,
|
|
||||||
.prepare = jzdlv_pcm_prepare,
|
|
||||||
.hw_params = jzdlv_hw_params,
|
|
||||||
.shutdown = jzdlv_shutdown,
|
|
||||||
},
|
|
||||||
.dai_ops = {
|
|
||||||
.digital_mute = jzdlv_mute,
|
|
||||||
.set_sysclk = jzdlv_set_dai_sysclk,
|
|
||||||
.set_fmt = jzdlv_set_dai_fmt,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
EXPORT_SYMBOL_GPL(jzdlv_dai);
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static int jzdlv_suspend(struct platform_device *pdev, pm_message_t state)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
|
||||||
struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
jzcodec_reg_pm[ICODEC_1_LOW] = jzcodec_read_reg_cache(codec, ICODEC_1_LOW);
|
|
||||||
jzcodec_reg_pm[ICODEC_1_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_1_HIGH);
|
|
||||||
jzcodec_reg_pm[ICODEC_2_LOW] = jzcodec_read_reg_cache(codec, ICODEC_2_LOW);
|
|
||||||
jzcodec_reg_pm[ICODEC_2_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH);
|
|
||||||
|
|
||||||
jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_resume(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
|
||||||
struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
u16 reg_val;
|
|
||||||
|
|
||||||
jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
|
|
||||||
reg_val = jzcodec_reg_pm[ICODEC_1_LOW];
|
|
||||||
jzcodec_write(codec, ICODEC_1_LOW, reg_val);
|
|
||||||
reg_val = jzcodec_reg_pm[ICODEC_1_HIGH];
|
|
||||||
jzcodec_write(codec, ICODEC_1_HIGH, reg_val);
|
|
||||||
reg_val = jzcodec_reg_pm[ICODEC_2_LOW];
|
|
||||||
jzcodec_write(codec, ICODEC_2_LOW, reg_val);
|
|
||||||
reg_val = jzcodec_reg_pm[ICODEC_2_HIGH];
|
|
||||||
jzcodec_write(codec, ICODEC_2_HIGH, reg_val);
|
|
||||||
|
|
||||||
jzcodec_dapm_event(codec, codec->suspend_dapm_state);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define jzdlv_suspend NULL
|
|
||||||
#define jzdlv_resume NULL
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* initialise the JZDLV driver
|
|
||||||
* register the mixer and dsp interfaces with the kernel
|
|
||||||
*/
|
|
||||||
static int jzdlv_init(struct snd_soc_device *socdev)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
int ret = 0, retval;
|
|
||||||
|
|
||||||
/*REG_CPM_CPCCR &= ~(1 << 31);
|
|
||||||
REG_CPM_CPCCR &= ~(1 << 30);*/
|
|
||||||
write_codec_file(0, 0xf);
|
|
||||||
|
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
__i2s_internal_codec();
|
|
||||||
__i2s_as_slave();
|
|
||||||
__i2s_select_i2s();
|
|
||||||
__aic_select_i2s();
|
|
||||||
__aic_reset();
|
|
||||||
mdelay(10);
|
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
mdelay(20);
|
|
||||||
|
|
||||||
/* power on DLV */
|
|
||||||
write_codec_file(8, 0x3f);
|
|
||||||
write_codec_file(9, 0xff);
|
|
||||||
mdelay(10);
|
|
||||||
|
|
||||||
__cpm_start_idct();
|
|
||||||
__cpm_start_db();
|
|
||||||
__cpm_start_me();
|
|
||||||
__cpm_start_mc();
|
|
||||||
__cpm_start_ipu();
|
|
||||||
|
|
||||||
codec->name = "JZDLV";
|
|
||||||
codec->owner = THIS_MODULE;
|
|
||||||
codec->read = jzdlv_read_reg_cache;
|
|
||||||
codec->write = jzdlv_write;
|
|
||||||
//codec->dapm_event = jzdlv_dapm_event;
|
|
||||||
codec->dai = &jzdlv_dai;
|
|
||||||
codec->num_dai = 1;
|
|
||||||
codec->reg_cache_size = sizeof(jzdlv_reg);
|
|
||||||
codec->reg_cache = kmemdup(jzdlv_reg, sizeof(jzdlv_reg), GFP_KERNEL);
|
|
||||||
if (codec->reg_cache == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
jzdlv_reset(codec);
|
|
||||||
/* register pcms */
|
|
||||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
|
||||||
if (ret < 0) {
|
|
||||||
printk(KERN_ERR "jzdlv: failed to create pcms\n");
|
|
||||||
goto pcm_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* power on device */
|
|
||||||
jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
|
|
||||||
jzdlv_add_controls(codec);
|
|
||||||
jzdlv_add_widgets(codec);
|
|
||||||
ret = snd_soc_register_card(socdev);
|
|
||||||
if (ret < 0) {
|
|
||||||
printk(KERN_ERR "jzcodec: failed to register card\n");
|
|
||||||
goto card_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
mdelay(10);
|
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
mdelay(20);
|
|
||||||
/* power on DLV */
|
|
||||||
write_codec_file(9, 0xff);
|
|
||||||
write_codec_file(8, 0x3f);
|
|
||||||
retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL);
|
|
||||||
if (retval) {
|
|
||||||
printk("Could not get aic codec irq %d\n", IRQ_AIC);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk_codec_files();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
card_err:
|
|
||||||
snd_soc_free_pcms(socdev);
|
|
||||||
snd_soc_dapm_free(socdev);
|
|
||||||
pcm_err:
|
|
||||||
kfree(codec->reg_cache);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct snd_soc_device *jzdlv_socdev;
|
|
||||||
|
|
||||||
static int write_codec_reg(u16 * add, char * name, int reg)
|
|
||||||
{
|
|
||||||
write_codec_file(reg, *add);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
|
||||||
struct snd_soc_codec *codec;
|
|
||||||
struct jzdlv_priv *jzdlv;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
|
||||||
if (codec == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
jzdlv = kzalloc(sizeof(struct jzdlv_priv), GFP_KERNEL);
|
|
||||||
if (jzdlv == NULL) {
|
|
||||||
kfree(codec);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
codec->private_data = jzdlv;
|
|
||||||
socdev->codec = codec;
|
|
||||||
mutex_init(&codec->mutex);
|
|
||||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
|
||||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
|
||||||
|
|
||||||
jzdlv_socdev = socdev;
|
|
||||||
|
|
||||||
/* Add other interfaces here ,no I2C connection */
|
|
||||||
codec->hw_write = (hw_write_t)write_codec_reg;
|
|
||||||
//codec->hw_read = (hw_read_t)read_codec_reg;
|
|
||||||
ret = jzdlv_init(jzdlv_socdev);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
codec = jzdlv_socdev->codec;
|
|
||||||
err("failed to initialise jzdlv\n");
|
|
||||||
kfree(codec);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* power down chip */
|
|
||||||
static int jzdlv_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
|
||||||
struct snd_soc_codec *codec = socdev->codec;
|
|
||||||
|
|
||||||
if (codec->control_data)
|
|
||||||
jzdlv_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
|
|
||||||
|
|
||||||
snd_soc_free_pcms(socdev);
|
|
||||||
snd_soc_dapm_free(socdev);
|
|
||||||
kfree(codec->private_data);
|
|
||||||
kfree(codec);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct snd_soc_codec_device soc_codec_dev_jzdlv = {
|
|
||||||
.probe = jzdlv_probe,
|
|
||||||
.remove = jzdlv_remove,
|
|
||||||
.suspend = jzdlv_suspend,
|
|
||||||
.resume = jzdlv_resume,
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(soc_codec_dev_jzdlv);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("ASoC JZDLV driver");
|
|
||||||
MODULE_AUTHOR("Richard");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _DLV_H
|
|
||||||
#define _DLV_H
|
|
||||||
|
|
||||||
/* jzdlv register space */
|
|
||||||
|
|
||||||
#define DLV_AICR 0x00
|
|
||||||
#define DLV_CR1 0x01
|
|
||||||
#define DLV_CR2 0x02
|
|
||||||
#define DLV_CCR1 0x03
|
|
||||||
#define DLV_CCR2 0x04
|
|
||||||
#define DLV_PMR1 0x05
|
|
||||||
#define DLV_PMR2 0x06
|
|
||||||
#define DLV_CRR 0x07
|
|
||||||
#define DLV_ICR 0x08
|
|
||||||
#define DLV_IFR 0x09
|
|
||||||
#define DLV_CGR1 0x0a
|
|
||||||
#define DLV_CGR2 0x0b
|
|
||||||
#define DLV_CGR3 0x0c
|
|
||||||
#define DLV_CGR4 0x0d
|
|
||||||
#define DLV_CGR5 0x0e
|
|
||||||
#define DLV_CGR6 0x0f
|
|
||||||
#define DLV_CGR7 0x10
|
|
||||||
#define DLV_CGR8 0x11
|
|
||||||
#define DLV_CGR9 0x12
|
|
||||||
#define DLV_CGR10 0x13
|
|
||||||
#define DLV_TR1 0x14
|
|
||||||
#define DLV_TR2 0x15
|
|
||||||
#define DLV_CR3 0x16
|
|
||||||
#define DLV_AGC1 0x17
|
|
||||||
#define DLV_AGC2 0x18
|
|
||||||
#define DLV_AGC3 0x19
|
|
||||||
#define DLV_AGC4 0x1a
|
|
||||||
#define DLV_AGC5 0x1b
|
|
||||||
|
|
||||||
#define JZDLV_CACHEREGNUM (DLV_AGC5+1)
|
|
||||||
#define JZDLV_SYSCLK 0
|
|
||||||
|
|
||||||
int read_codec_file(int addr);
|
|
||||||
int write_codec_file_bit(int addr, int bitval, int mask_bit);
|
|
||||||
void write_codec_file(int addr, int val);
|
|
||||||
extern struct snd_soc_dai jzdlv_dai;
|
|
||||||
extern struct snd_soc_codec_device soc_codec_dev_jzdlv;
|
|
||||||
|
|
||||||
#endif
|
|
33
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Kconfig
Executable file → Normal file
33
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Kconfig
Executable file → Normal file
@ -1,34 +1,21 @@
|
|||||||
config SND_JZ4740_SOC
|
config SND_JZ4740_SOC
|
||||||
tristate "SoC Audio for Ingenic jz4740 chip"
|
tristate "SoC Audio for Ingenic JZ4740 SoC"
|
||||||
depends on (JZ4740_PAVO || JZ4725_DIPPER || JZ4720_VIRGO) && SND_SOC
|
depends on SOC_JZ4740 && SND_SOC
|
||||||
help
|
help
|
||||||
Say Y or M if you want to add support for codecs attached to
|
Say Y or M if you want to add support for codecs attached to
|
||||||
the Jz4740 AC97, I2S or SSP interface. You will also need
|
the Jz4740 AC97, I2S or SSP interface. You will also need
|
||||||
to select the audio interfaces to support below.
|
to select the audio interfaces to support below.
|
||||||
|
|
||||||
config SND_JZ4740_SOC_PAVO
|
config SND_JZ4740_SOC_QI_LB60
|
||||||
tristate "SoC Audio support for Ingenic Jz4740 PAVO board"
|
tristate "SoC Audio support for Qi Hardware Ben Nanonote"
|
||||||
depends on SND_JZ4740_SOC
|
depends on SND_JZ4740_SOC && JZ4740_QI_LB60
|
||||||
|
select SND_JZ4740_SOC_I2S
|
||||||
|
select SND_SOC_JZCODEC
|
||||||
help
|
help
|
||||||
Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4740 PAVO board.
|
Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4740 QI_LB60 board.
|
||||||
|
|
||||||
config SND_JZ4740_AC97
|
|
||||||
tristate "select AC97 protocol and AC97 codec pcm core support"
|
|
||||||
depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO
|
|
||||||
select SND_AC97_CODEC
|
|
||||||
help
|
|
||||||
Say Y if you want to add AC97 protocol support for pcm core.
|
|
||||||
|
|
||||||
config SND_JZ4740_SOC_AC97
|
|
||||||
tristate "SoC Audio (AC97 protocol) for Ingenic jz4740 chip"
|
|
||||||
depends on SND_JZ4740_SOC && SND_JZ4740_AC97 && SND_JZ4740_SOC_PAVO
|
|
||||||
select AC97_BUS
|
|
||||||
select SND_SOC_AC97_BUS
|
|
||||||
help
|
|
||||||
Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4740 PAVO board.
|
|
||||||
|
|
||||||
config SND_JZ4740_SOC_I2S
|
config SND_JZ4740_SOC_I2S
|
||||||
depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO
|
depends on SND_JZ4740_SOC
|
||||||
tristate "SoC Audio (I2S protocol) for Ingenic jz4740 chip"
|
tristate "SoC Audio (I2S protocol) for Ingenic jz4740 chip"
|
||||||
help
|
help
|
||||||
Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4740 PAVO board.
|
Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4740 QI_LB60 board.
|
||||||
|
6
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Makefile
Executable file → Normal file
6
target/linux/xburst/files-2.6.31/sound/soc/jz4740/Makefile
Executable file → Normal file
@ -2,14 +2,12 @@
|
|||||||
# Jz4740 Platform Support
|
# Jz4740 Platform Support
|
||||||
#
|
#
|
||||||
snd-soc-jz4740-objs := jz4740-pcm.o
|
snd-soc-jz4740-objs := jz4740-pcm.o
|
||||||
snd-soc-jz4740-ac97-objs := jz4740-ac97.o
|
|
||||||
snd-soc-jz4740-i2s-objs := jz4740-i2s.o
|
snd-soc-jz4740-i2s-objs := jz4740-i2s.o
|
||||||
|
|
||||||
obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
|
obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
|
||||||
obj-$(CONFIG_SND_JZ4740_SOC_AC97) += snd-soc-jz4740-ac97.o
|
|
||||||
obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
|
obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
|
||||||
|
|
||||||
# Jz4740 Machine Support
|
# Jz4740 Machine Support
|
||||||
snd-soc-pavo-objs := pavo.o
|
snd-soc-qi-lb60-objs := qi_lb60.o
|
||||||
|
|
||||||
obj-$(CONFIG_SND_JZ4740_SOC_PAVO) += snd-soc-pavo.o
|
obj-$(CONFIG_SND_JZ4740_SOC_QI_LB60) += snd-soc-qi-lb60.o
|
||||||
|
@ -1,261 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip.
|
|
||||||
*
|
|
||||||
* Author: Richard
|
|
||||||
* Created: Dec 02, 2007
|
|
||||||
* Copyright: Ingenic Semiconductor Inc.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/wait.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/ac97_codec.h>
|
|
||||||
#include <sound/initval.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
|
|
||||||
#include <asm/irq.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <asm/hardware.h>
|
|
||||||
#include <asm/arch/audio.h>
|
|
||||||
|
|
||||||
#include "jz4740-pcm.h"
|
|
||||||
#include "jz4740-ac97.h"
|
|
||||||
|
|
||||||
static DEFINE_MUTEX(car_mutex);
|
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
|
|
||||||
static volatile long gsr_bits;
|
|
||||||
|
|
||||||
static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97,
|
|
||||||
unsigned short reg)
|
|
||||||
{
|
|
||||||
unsigned short val = -1;
|
|
||||||
volatile u32 *reg_addr;
|
|
||||||
|
|
||||||
mutex_lock(&car_mutex);
|
|
||||||
|
|
||||||
out: mutex_unlock(&car_mutex);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
|
||||||
unsigned short val)
|
|
||||||
{
|
|
||||||
volatile u32 *reg_addr;
|
|
||||||
|
|
||||||
mutex_lock(&car_mutex);
|
|
||||||
|
|
||||||
mutex_unlock(&car_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97)
|
|
||||||
{
|
|
||||||
gsr_bits = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
long status;
|
|
||||||
return IRQ_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct snd_ac97_bus_ops soc_ac97_ops = {
|
|
||||||
.read = jz4740_ac97_read,
|
|
||||||
.write = jz4740_ac97_write,
|
|
||||||
.warm_reset = jz4740_ac97_warm_reset,
|
|
||||||
.reset = jz4740_ac97_cold_reset,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = {
|
|
||||||
.name = "AC97 PCM Stereo out",
|
|
||||||
.dev_addr = __PREG(PCDR),
|
|
||||||
.drcmr = &DRCMRTXPCDR,
|
|
||||||
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
|
||||||
DCMD_BURST32 | DCMD_WIDTH4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = {
|
|
||||||
.name = "AC97 PCM Stereo in",
|
|
||||||
.dev_addr = __PREG(PCDR),
|
|
||||||
.drcmr = &DRCMRRXPCDR,
|
|
||||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
|
||||||
DCMD_BURST32 | DCMD_WIDTH4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = {
|
|
||||||
.name = "AC97 Aux PCM (Slot 5) Mono out",
|
|
||||||
.dev_addr = __PREG(MODR),
|
|
||||||
.drcmr = &DRCMRTXMODR,
|
|
||||||
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
|
||||||
DCMD_BURST16 | DCMD_WIDTH2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = {
|
|
||||||
.name = "AC97 Aux PCM (Slot 5) Mono in",
|
|
||||||
.dev_addr = __PREG(MODR),
|
|
||||||
.drcmr = &DRCMRRXMODR,
|
|
||||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
|
||||||
DCMD_BURST16 | DCMD_WIDTH2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = {
|
|
||||||
.name = "AC97 Mic PCM (Slot 6) Mono in",
|
|
||||||
.dev_addr = __PREG(MCDR),
|
|
||||||
.drcmr = &DRCMRRXMCDR,
|
|
||||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
|
||||||
DCMD_BURST16 | DCMD_WIDTH2,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static int jz4740_ac97_suspend(struct platform_device *pdev,
|
|
||||||
struct snd_soc_cpu_dai *dai)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_resume(struct platform_device *pdev,
|
|
||||||
struct snd_soc_cpu_dai *dai)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define jz4740_ac97_suspend NULL
|
|
||||||
#define jz4740_ac97_resume NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int jz4740_ac97_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out;
|
|
||||||
else
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out;
|
|
||||||
else
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
return -ENODEV;
|
|
||||||
else
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
|
||||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
|
|
||||||
SNDRV_PCM_RATE_48000)
|
|
||||||
|
|
||||||
struct snd_soc_cpu_dai jz4740_ac97_dai[] = {
|
|
||||||
{
|
|
||||||
.name = "jz4740-ac97",
|
|
||||||
.id = 0,
|
|
||||||
.type = SND_SOC_DAI_AC97,
|
|
||||||
.probe = jz4740_ac97_probe,
|
|
||||||
.remove = jz4740_ac97_remove,
|
|
||||||
.suspend = jz4740_ac97_suspend,
|
|
||||||
.resume = jz4740_ac97_resume,
|
|
||||||
.playback = {
|
|
||||||
.stream_name = "AC97 Playback",
|
|
||||||
.channels_min = 2,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "AC97 Capture",
|
|
||||||
.channels_min = 2,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.hw_params = jz4740_ac97_hw_params,},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "jz4740-ac97-aux",
|
|
||||||
.id = 1,
|
|
||||||
.type = SND_SOC_DAI_AC97,
|
|
||||||
.playback = {
|
|
||||||
.stream_name = "AC97 Aux Playback",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 1,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "AC97 Aux Capture",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 1,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.hw_params = jz4740_ac97_hw_aux_params,},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "jz4740-ac97-mic",
|
|
||||||
.id = 2,
|
|
||||||
.type = SND_SOC_DAI_AC97,
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "AC97 Mic Capture",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 1,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.hw_params = jz4740_ac97_hw_mic_params,},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4740_ac97_dai);
|
|
||||||
EXPORT_SYMBOL_GPL(soc_ac97_ops);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Richard");
|
|
||||||
MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/sound/soc/jz4740/jz4740-ac97.h
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JZ4740_AC97_H
|
|
||||||
#define _JZ4740_AC97_H
|
|
||||||
|
|
||||||
#define JZ4740_DAI_AC97_HIFI 0
|
|
||||||
#define JZ4740_DAI_AC97_AUX 1
|
|
||||||
#define JZ4740_DAI_AC97_MIC 2
|
|
||||||
|
|
||||||
extern struct snd_soc_cpu_dai jz4740_ac97_dai[3];
|
|
||||||
|
|
||||||
/* platform data */
|
|
||||||
extern struct snd_ac97_bus_ops jz4740_ac97_ops;
|
|
||||||
|
|
||||||
#endif
|
|
72
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.c
Executable file → Normal file
72
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.c
Executable file → Normal file
@ -4,13 +4,14 @@
|
|||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
* option) any later version.
|
* option) any later version.
|
||||||
*
|
*
|
||||||
|
* Jiejing Zhang(kzjeef(at)gmail.com) 2009: Make jz soc sound card
|
||||||
|
* loaded by soc-core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
@ -42,7 +43,7 @@ static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
|
|||||||
.dma_size = 2,
|
.dma_size = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int jz4740_i2s_startup(struct snd_pcm_substream *substream)
|
static int jz4740_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/
|
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/
|
||||||
@ -124,23 +125,22 @@ static void jz4740_snd_rx_ctrl(int on)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
|
static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||||
struct snd_pcm_hw_params *params)
|
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
//struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||||
int channels = params_channels(params);
|
/* int channels = params_channels(params); */
|
||||||
|
|
||||||
jz4740_snd_rx_ctrl(0);
|
jz4740_snd_rx_ctrl(0);
|
||||||
jz4740_snd_rx_ctrl(0);
|
jz4740_snd_rx_ctrl(0);
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
//cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out;
|
cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out;
|
||||||
rtd->dai->cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out;
|
/*if (channels == 1)
|
||||||
if (channels == 1)
|
|
||||||
__aic_enable_mono2stereo();
|
__aic_enable_mono2stereo();
|
||||||
else
|
else
|
||||||
__aic_disable_mono2stereo();
|
__aic_disable_mono2stereo();*/
|
||||||
} else
|
} else
|
||||||
rtd->dai->cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in;
|
cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in;
|
||||||
|
|
||||||
switch (params_format(params)) {
|
switch (params_format(params)) {
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
case SNDRV_PCM_FORMAT_S8:
|
||||||
@ -162,7 +162,7 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
|
static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
@ -189,7 +189,7 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream)
|
static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||||
} else {
|
} else {
|
||||||
@ -198,7 +198,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_i2s_probe(struct platform_device *pdev)
|
static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
|
||||||
{
|
{
|
||||||
__i2s_internal_codec();
|
__i2s_internal_codec();
|
||||||
__i2s_as_slave();
|
__i2s_as_slave();
|
||||||
@ -232,8 +232,7 @@ static int jz4740_i2s_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int jz4740_i2s_suspend(struct platform_device *dev,
|
static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
|
||||||
struct snd_soc_dai *dai)
|
|
||||||
{
|
{
|
||||||
if (!dai->active)
|
if (!dai->active)
|
||||||
return 0;
|
return 0;
|
||||||
@ -241,8 +240,7 @@ static int jz4740_i2s_suspend(struct platform_device *dev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4740_i2s_resume(struct platform_device *pdev,
|
static int jz4740_i2s_resume(struct snd_soc_dai *dai)
|
||||||
struct snd_soc_dai *dai)
|
|
||||||
{
|
{
|
||||||
if (!dai->active)
|
if (!dai->active)
|
||||||
return 0;
|
return 0;
|
||||||
@ -256,15 +254,22 @@ static int jz4740_i2s_resume(struct platform_device *pdev,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define JZ4740_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
#define JZ4740_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||||
SNDRV_PCM_RATE_12000 | SNDRV_PCM_RATE_16000 |\
|
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
|
||||||
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_24000 |\
|
|
||||||
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
||||||
SNDRV_PCM_RATE_48000)
|
SNDRV_PCM_RATE_48000)
|
||||||
|
|
||||||
|
struct snd_soc_dai_ops snd_jz4740_i2s_dai_ops = {
|
||||||
|
.startup = jz4740_i2s_startup,
|
||||||
|
.shutdown = jz4740_i2s_shutdown,
|
||||||
|
.trigger = jz4740_i2s_trigger,
|
||||||
|
.hw_params = jz4740_i2s_hw_params,
|
||||||
|
.set_fmt = jz4740_i2s_set_dai_fmt,
|
||||||
|
.set_sysclk = jz4740_i2s_set_dai_sysclk,
|
||||||
|
};
|
||||||
|
|
||||||
struct snd_soc_dai jz4740_i2s_dai = {
|
struct snd_soc_dai jz4740_i2s_dai = {
|
||||||
.name = "jz4740-i2s",
|
.name = "jz4740-i2s",
|
||||||
.id = 0,
|
.id = 0,
|
||||||
.type = SND_SOC_DAI_I2S,
|
|
||||||
.probe = jz4740_i2s_probe,
|
.probe = jz4740_i2s_probe,
|
||||||
.suspend = jz4740_i2s_suspend,
|
.suspend = jz4740_i2s_suspend,
|
||||||
.resume = jz4740_i2s_resume,
|
.resume = jz4740_i2s_resume,
|
||||||
@ -272,25 +277,32 @@ struct snd_soc_dai jz4740_i2s_dai = {
|
|||||||
.channels_min = 1,
|
.channels_min = 1,
|
||||||
.channels_max = 2,
|
.channels_max = 2,
|
||||||
.rates = JZ4740_I2S_RATES,
|
.rates = JZ4740_I2S_RATES,
|
||||||
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
|
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
|
},
|
||||||
.capture = {
|
.capture = {
|
||||||
.channels_min = 1,
|
.channels_min = 1,
|
||||||
.channels_max = 2,
|
.channels_max = 2,
|
||||||
.rates = JZ4740_I2S_RATES,
|
.rates = JZ4740_I2S_RATES,
|
||||||
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
|
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.ops = {
|
|
||||||
.startup = jz4740_i2s_startup,
|
|
||||||
.shutdown = jz4740_i2s_shutdown,
|
|
||||||
.trigger = jz4740_i2s_trigger,
|
|
||||||
.hw_params = jz4740_i2s_hw_params,},
|
|
||||||
.dai_ops = {
|
|
||||||
.set_fmt = jz4740_i2s_set_dai_fmt,
|
|
||||||
.set_sysclk = jz4740_i2s_set_dai_sysclk,
|
|
||||||
},
|
},
|
||||||
|
.ops = &snd_jz4740_i2s_dai_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
|
EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
|
||||||
|
|
||||||
|
static int __init jz4740_i2s_init(void)
|
||||||
|
{
|
||||||
|
return snd_soc_register_dai(&jz4740_i2s_dai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit jz4740_i2s_exit(void)
|
||||||
|
{
|
||||||
|
snd_soc_unregister_dai(&jz4740_i2s_dai);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(jz4740_i2s_init);
|
||||||
|
module_exit(jz4740_i2s_exit);
|
||||||
|
|
||||||
/* Module information */
|
/* Module information */
|
||||||
MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn");
|
MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn");
|
||||||
MODULE_DESCRIPTION("jz4740 I2S SoC Interface");
|
MODULE_DESCRIPTION("jz4740 I2S SoC Interface");
|
||||||
|
0
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.h
Executable file → Normal file
0
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-i2s.h
Executable file → Normal file
90
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.c
Executable file → Normal file
90
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.c
Executable file → Normal file
@ -12,7 +12,6 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
@ -29,6 +28,29 @@ static int tran_bit = 0;
|
|||||||
static int hw_params_cnt = 0;
|
static int hw_params_cnt = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static struct jz4740_dma_client jz4740_dma_client_out = {
|
||||||
|
.name = "I2S PCM Stereo out"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_dma_client jz4740_dma_client_in = {
|
||||||
|
.name = "I2S PCM Stereo in"
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = {
|
||||||
|
.client = &jz4740_dma_client_out,
|
||||||
|
.channel = DMA_ID_AIC_TX,
|
||||||
|
.dma_addr = AIC_DR,
|
||||||
|
.dma_size = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = {
|
||||||
|
.client = &jz4740_dma_client_in,
|
||||||
|
.channel = DMA_ID_AIC_RX,
|
||||||
|
.dma_addr = AIC_DR,
|
||||||
|
.dma_size = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct jz4740_dma_buf_aic {
|
struct jz4740_dma_buf_aic {
|
||||||
struct jz4740_dma_buf_aic *next;
|
struct jz4740_dma_buf_aic *next;
|
||||||
int size; /* buffer size in bytes */
|
int size; /* buffer size in bytes */
|
||||||
@ -66,13 +88,11 @@ static const struct snd_pcm_hardware jz4740_pcm_hardware = {
|
|||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||||
SNDRV_PCM_FMTBIT_U16_LE |
|
|
||||||
SNDRV_PCM_FMTBIT_U8 |
|
|
||||||
SNDRV_PCM_FMTBIT_S8,
|
SNDRV_PCM_FMTBIT_S8,
|
||||||
.rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/,
|
.rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/,
|
||||||
.rate_min = 8000,
|
.rate_min = 8000,
|
||||||
.rate_min = 48000,
|
.rate_min = 48000,
|
||||||
.channels_min = 1,//2
|
.channels_min = 2,
|
||||||
.channels_max = 2,
|
.channels_max = 2,
|
||||||
.buffer_bytes_max = 128 * 1024,//16 * 1024
|
.buffer_bytes_max = 128 * 1024,//16 * 1024
|
||||||
.period_bytes_min = PAGE_SIZE,
|
.period_bytes_min = PAGE_SIZE,
|
||||||
@ -126,7 +146,7 @@ void audio_start_dma(struct jz4740_runtime_data *prtd, int mode)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct jz4740_dma_buf_aic *aic_buf;
|
struct jz4740_dma_buf_aic *aic_buf;
|
||||||
int channel;
|
int channel;
|
||||||
printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__);
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DMA_MODE_WRITE:
|
case DMA_MODE_WRITE:
|
||||||
/* free cur aic_buf */
|
/* free cur aic_buf */
|
||||||
@ -146,13 +166,11 @@ void audio_start_dma(struct jz4740_runtime_data *prtd, int mode)
|
|||||||
aic_buf = prtd->next;
|
aic_buf = prtd->next;
|
||||||
channel = prtd->params->channel;
|
channel = prtd->params->channel;
|
||||||
if (aic_buf) {
|
if (aic_buf) {
|
||||||
flags = claim_dma_lock();
|
|
||||||
disable_dma(channel);
|
disable_dma(channel);
|
||||||
jz_set_alsa_dma(channel, mode, tran_bit);
|
jz_set_alsa_dma(channel, mode, tran_bit);
|
||||||
set_dma_addr(channel, aic_buf->data);
|
set_dma_addr(channel, aic_buf->data);
|
||||||
set_dma_count(channel, aic_buf->size);
|
set_dma_count(channel, aic_buf->size);
|
||||||
enable_dma(channel);
|
enable_dma(channel);
|
||||||
release_dma_lock(flags);
|
|
||||||
prtd->aic_dma_flag |= AIC_START_DMA;
|
prtd->aic_dma_flag |= AIC_START_DMA;
|
||||||
} else {
|
} else {
|
||||||
printk("next buffer is NULL for playback\n");
|
printk("next buffer is NULL for playback\n");
|
||||||
@ -179,13 +197,11 @@ void audio_start_dma(struct jz4740_runtime_data *prtd, int mode)
|
|||||||
channel = prtd->params->channel;
|
channel = prtd->params->channel;
|
||||||
|
|
||||||
if (aic_buf) {
|
if (aic_buf) {
|
||||||
flags = claim_dma_lock();
|
|
||||||
disable_dma(channel);
|
disable_dma(channel);
|
||||||
jz_set_alsa_dma(channel, mode, tran_bit);
|
jz_set_alsa_dma(channel, mode, tran_bit);
|
||||||
set_dma_addr(channel, aic_buf->data);
|
set_dma_addr(channel, aic_buf->data);
|
||||||
set_dma_count(channel, aic_buf->size);
|
set_dma_count(channel, aic_buf->size);
|
||||||
enable_dma(channel);
|
enable_dma(channel);
|
||||||
release_dma_lock(flags);
|
|
||||||
prtd->aic_dma_flag |= AIC_START_DMA;
|
prtd->aic_dma_flag |= AIC_START_DMA;
|
||||||
} else {
|
} else {
|
||||||
printk("next buffer is NULL for capture\n");
|
printk("next buffer is NULL for capture\n");
|
||||||
@ -283,17 +299,10 @@ static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct jz4740_runtime_data *prtd = runtime->private_data;
|
struct jz4740_runtime_data *prtd = runtime->private_data;
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
struct jz4740_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
|
struct jz4740_pcm_dma_params *dma = &jz4740_i2s_pcm_stereo_out;
|
||||||
size_t totbytes = params_buffer_bytes(params);
|
size_t totbytes = params_buffer_bytes(params);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
if (hw_params_cnt)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
hw_params_cnt++ ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!dma)
|
if (!dma)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -343,7 +352,6 @@ static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||||||
__dmac_disable_descriptor(prtd->params->channel);
|
__dmac_disable_descriptor(prtd->params->channel);
|
||||||
__dmac_channel_disable_irq(prtd->params->channel);
|
__dmac_channel_disable_irq(prtd->params->channel);
|
||||||
spin_unlock_irq(&prtd->lock);
|
spin_unlock_irq(&prtd->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,32 +573,8 @@ static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
|
|||||||
unsigned long start;
|
unsigned long start;
|
||||||
unsigned long off;
|
unsigned long off;
|
||||||
u32 len;
|
u32 len;
|
||||||
int ret = -ENXIO;
|
printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
|
||||||
|
return 0;
|
||||||
off = vma->vm_pgoff << PAGE_SHIFT;
|
|
||||||
start = runtime->dma_addr;
|
|
||||||
|
|
||||||
len = PAGE_ALIGN((start & ~PAGE_MASK) + runtime->dma_bytes);
|
|
||||||
start &= PAGE_MASK;
|
|
||||||
|
|
||||||
if ((vma->vm_end - vma->vm_start + off) > len) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
off += start;
|
|
||||||
vma->vm_pgoff = off >> PAGE_SHIFT;
|
|
||||||
vma->vm_flags |= VM_IO;
|
|
||||||
|
|
||||||
#if defined(CONFIG_MIPS32)
|
|
||||||
pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
|
|
||||||
pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
|
|
||||||
/* pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; */
|
|
||||||
#endif
|
|
||||||
ret = io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
|
|
||||||
vma->vm_end - vma->vm_start,
|
|
||||||
vma->vm_page_prot);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct snd_pcm_ops jz4740_pcm_ops = {
|
struct snd_pcm_ops jz4740_pcm_ops = {
|
||||||
@ -645,17 +629,19 @@ static void jz4740_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 jz4740_pcm_dmamask = DMA_32BIT_MASK;
|
static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
|
||||||
|
|
||||||
int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
||||||
struct snd_pcm *pcm)
|
struct snd_pcm *pcm)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
printk("pcm new\n");
|
||||||
|
|
||||||
if (!card->dev->dma_mask)
|
if (!card->dev->dma_mask)
|
||||||
card->dev->dma_mask = &jz4740_pcm_dmamask;
|
card->dev->dma_mask = &jz4740_pcm_dmamask;
|
||||||
if (!card->dev->coherent_dma_mask)
|
if (!card->dev->coherent_dma_mask)
|
||||||
card->dev->coherent_dma_mask = DMA_32BIT_MASK;
|
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||||
|
|
||||||
if (dai->playback.channels_min) {
|
if (dai->playback.channels_min) {
|
||||||
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
|
ret = jz4740_pcm_preallocate_dma_buffer(pcm,
|
||||||
@ -684,6 +670,18 @@ struct snd_soc_platform jz4740_soc_platform = {
|
|||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4740_soc_platform);
|
EXPORT_SYMBOL_GPL(jz4740_soc_platform);
|
||||||
|
|
||||||
|
static int __init jz4740_soc_platform_init(void)
|
||||||
|
{
|
||||||
|
return snd_soc_register_platform(&jz4740_soc_platform);
|
||||||
|
}
|
||||||
|
module_init(jz4740_soc_platform_init);
|
||||||
|
|
||||||
|
static void __exit jz4740_soc_platform_exit(void)
|
||||||
|
{
|
||||||
|
snd_soc_unregister_platform(&jz4740_soc_platform);
|
||||||
|
}
|
||||||
|
module_exit(jz4740_soc_platform_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Richard");
|
MODULE_AUTHOR("Richard");
|
||||||
MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module");
|
MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
0
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.h
Executable file → Normal file
0
target/linux/xburst/files-2.6.31/sound/soc/jz4740/jz4740-pcm.h
Executable file → Normal file
@ -1,364 +0,0 @@
|
|||||||
/*
|
|
||||||
* pavo.c -- SoC audio for PAVO
|
|
||||||
*
|
|
||||||
* 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 the
|
|
||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/moduleparam.h>
|
|
||||||
#include <linux/timer.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
#include <sound/soc-dapm.h>
|
|
||||||
|
|
||||||
#include "../codecs/jzcodec.h"
|
|
||||||
#include "jz4740-pcm.h"
|
|
||||||
#include "jz4740-i2s.h"
|
|
||||||
|
|
||||||
#define PAVO_HP 0
|
|
||||||
#define PAVO_MIC 1
|
|
||||||
#define PAVO_LINE 2
|
|
||||||
#define PAVO_HEADSET 3
|
|
||||||
#define PAVO_HP_OFF 4
|
|
||||||
#define PAVO_SPK_ON 0
|
|
||||||
#define PAVO_SPK_OFF 1
|
|
||||||
|
|
||||||
/* audio clock in Hz - rounded from 12.235MHz */
|
|
||||||
#define PAVO_AUDIO_CLOCK 12288000
|
|
||||||
|
|
||||||
static int pavo_jack_func;
|
|
||||||
static int pavo_spk_func;
|
|
||||||
|
|
||||||
unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
|
|
||||||
{
|
|
||||||
unsigned short gpio_bit = 0;
|
|
||||||
|
|
||||||
return gpio_bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
|
|
||||||
{
|
|
||||||
unsigned short gpio_bit = 0;
|
|
||||||
|
|
||||||
return gpio_bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pavo_ext_control(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
|
|
||||||
|
|
||||||
/* set up jack connection */
|
|
||||||
switch (pavo_jack_func) {
|
|
||||||
case PAVO_HP:
|
|
||||||
hp = 1;
|
|
||||||
/* set = unmute headphone */
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
|
||||||
break;
|
|
||||||
case PAVO_MIC:
|
|
||||||
mic = 1;
|
|
||||||
/* reset = mute headphone */
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
|
||||||
break;
|
|
||||||
case PAVO_LINE:
|
|
||||||
line = 1;
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
|
||||||
break;
|
|
||||||
case PAVO_HEADSET:
|
|
||||||
hs = 1;
|
|
||||||
mic = 1;
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L);
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pavo_spk_func == PAVO_SPK_ON)
|
|
||||||
spk = 1;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* set the enpoints to their new connetion states */
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk);
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic);
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "Line Jack", line);
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp);
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs);
|
|
||||||
|
|
||||||
/* signal a DAPM event */
|
|
||||||
snd_soc_dapm_sync_endpoints(codec);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_startup(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_codec *codec = rtd->socdev->codec;
|
|
||||||
|
|
||||||
/* check the jack status at stream startup */
|
|
||||||
pavo_ext_control(codec);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we need to unmute the HP at shutdown as the mute burns power on pavo */
|
|
||||||
static void pavo_shutdown(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_codec *codec = rtd->socdev->codec;*/
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
|
||||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* set codec DAI configuration */
|
|
||||||
ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
|
|
||||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* set cpu DAI configuration */
|
|
||||||
ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
|
|
||||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* set the codec system clock for DAC and ADC */
|
|
||||||
ret = codec_dai->dai_ops.set_sysclk(codec_dai, JZCODEC_SYSCLK, 111,
|
|
||||||
SND_SOC_CLOCK_IN);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* set the I2S system clock as input (unused) */
|
|
||||||
ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, JZ4740_I2S_SYSCLK, 0,
|
|
||||||
SND_SOC_CLOCK_IN);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct snd_soc_ops pavo_ops = {
|
|
||||||
.startup = pavo_startup,
|
|
||||||
.hw_params = pavo_hw_params,
|
|
||||||
.shutdown = pavo_shutdown,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int pavo_get_jack(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
ucontrol->value.integer.value[0] = pavo_jack_func;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_set_jack(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
||||||
|
|
||||||
if (pavo_jack_func == ucontrol->value.integer.value[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pavo_jack_func = ucontrol->value.integer.value[0];
|
|
||||||
pavo_ext_control(codec);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_get_spk(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
ucontrol->value.integer.value[0] = pavo_spk_func;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_set_spk(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
||||||
|
|
||||||
if (pavo_spk_func == ucontrol->value.integer.value[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pavo_spk_func = ucontrol->value.integer.value[0];
|
|
||||||
pavo_ext_control(codec);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_amp_event(struct snd_soc_dapm_widget *w, int event)
|
|
||||||
{
|
|
||||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, PAVO_SCP_APM_ON);
|
|
||||||
;
|
|
||||||
else
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, PAVO_SCP_APM_ON);
|
|
||||||
;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pavo_mic_event(struct snd_soc_dapm_widget *w, int event)
|
|
||||||
{
|
|
||||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
|
|
||||||
;
|
|
||||||
else
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
|
|
||||||
;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pavo machine dapm widgets */
|
|
||||||
static const struct snd_soc_dapm_widget jzcodec_dapm_widgets[] = {
|
|
||||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
|
||||||
SND_SOC_DAPM_MIC("Mic Jack",pavo_mic_event),
|
|
||||||
SND_SOC_DAPM_SPK("Ext Spk", pavo_amp_event),
|
|
||||||
SND_SOC_DAPM_LINE("Line Jack", NULL),
|
|
||||||
SND_SOC_DAPM_HP("Headset Jack", NULL),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* pavo machine audio map (connections to the codec pins) */
|
|
||||||
static const char *audio_map[][3] = {
|
|
||||||
|
|
||||||
/* headset Jack - in = micin, out = LHPOUT*/
|
|
||||||
{"Headset Jack", NULL, "LHPOUT"},
|
|
||||||
|
|
||||||
/* headphone connected to LHPOUT1, RHPOUT1 */
|
|
||||||
{"Headphone Jack", NULL, "LHPOUT"},
|
|
||||||
{"Headphone Jack", NULL, "RHPOUT"},
|
|
||||||
|
|
||||||
/* speaker connected to LOUT, ROUT */
|
|
||||||
{"Ext Spk", NULL, "ROUT"},
|
|
||||||
{"Ext Spk", NULL, "LOUT"},
|
|
||||||
|
|
||||||
/* mic is connected to MICIN (via right channel of headphone jack) */
|
|
||||||
{"MICIN", NULL, "Mic Jack"},
|
|
||||||
|
|
||||||
/* Same as the above but no mic bias for line signals */
|
|
||||||
{"MICIN", NULL, "Line Jack"},
|
|
||||||
|
|
||||||
{NULL, NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
|
|
||||||
"Off"};
|
|
||||||
static const char *spk_function[] = {"On", "Off"};
|
|
||||||
static const struct soc_enum pavo_enum[] = {
|
|
||||||
SOC_ENUM_SINGLE_EXT(5, jack_function),
|
|
||||||
SOC_ENUM_SINGLE_EXT(2, spk_function),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct snd_kcontrol_new jzcodec_pavo_controls[] = {
|
|
||||||
SOC_ENUM_EXT("Jack Function", pavo_enum[0], pavo_get_jack,
|
|
||||||
pavo_set_jack),
|
|
||||||
SOC_ENUM_EXT("Speaker Function", pavo_enum[1], pavo_get_spk,
|
|
||||||
pavo_set_spk),
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pavo for a jzcodec as connected on jz4740 Device
|
|
||||||
*/
|
|
||||||
static int pavo_jzcodec_init(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
int i, err;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
|
|
||||||
snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
|
|
||||||
#endif
|
|
||||||
/* Add pavo specific controls */
|
|
||||||
for (i = 0; i < ARRAY_SIZE(jzcodec_pavo_controls); i++) {
|
|
||||||
err = snd_ctl_add(codec->card,
|
|
||||||
snd_soc_cnew(&jzcodec_pavo_controls[i],codec, NULL));
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add pavo specific widgets */
|
|
||||||
for(i = 0; i < ARRAY_SIZE(jzcodec_dapm_widgets); i++) {
|
|
||||||
snd_soc_dapm_new_control(codec, &jzcodec_dapm_widgets[i]);
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
/* Set up pavo specific audio path audio_map */
|
|
||||||
for(i = 0; audio_map[i][0] != NULL; i++) {
|
|
||||||
snd_soc_dapm_connect_input(codec, audio_map[i][0],
|
|
||||||
audio_map[i][1], audio_map[i][2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_soc_dapm_sync_endpoints(codec);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pavo digital audio interface glue - connects codec <--> CPU */
|
|
||||||
static struct snd_soc_dai_link pavo_dai = {
|
|
||||||
.name = "JZCODEC",
|
|
||||||
.stream_name = "JZCODEC",
|
|
||||||
.cpu_dai = &jz4740_i2s_dai,
|
|
||||||
.codec_dai = &jzcodec_dai,
|
|
||||||
.init = pavo_jzcodec_init,
|
|
||||||
.ops = &pavo_ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* pavo audio machine driver */
|
|
||||||
static struct snd_soc_machine snd_soc_machine_pavo = {
|
|
||||||
.name = "Pavo",
|
|
||||||
.dai_link = &pavo_dai,
|
|
||||||
.num_links = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* pavo audio subsystem */
|
|
||||||
static struct snd_soc_device pavo_snd_devdata = {
|
|
||||||
.machine = &snd_soc_machine_pavo,
|
|
||||||
.platform = &jz4740_soc_platform,
|
|
||||||
.codec_dev = &soc_codec_dev_jzcodec,
|
|
||||||
//.codec_data
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct platform_device *pavo_snd_device;
|
|
||||||
|
|
||||||
static int __init pavo_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
pavo_snd_device = platform_device_alloc("soc-audio", -1);
|
|
||||||
|
|
||||||
if (!pavo_snd_device)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
platform_set_drvdata(pavo_snd_device, &pavo_snd_devdata);
|
|
||||||
pavo_snd_devdata.dev = &pavo_snd_device->dev;
|
|
||||||
ret = platform_device_add(pavo_snd_device);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
platform_device_put(pavo_snd_device);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit pavo_exit(void)
|
|
||||||
{
|
|
||||||
platform_device_unregister(pavo_snd_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(pavo_init);
|
|
||||||
module_exit(pavo_exit);
|
|
||||||
|
|
||||||
/* Module information */
|
|
||||||
MODULE_AUTHOR("Richard");
|
|
||||||
MODULE_DESCRIPTION("ALSA SoC Pavo");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,34 +0,0 @@
|
|||||||
config SND_JZ4750_SOC
|
|
||||||
tristate "SoC Audio for Ingenic jz4750 chip"
|
|
||||||
depends on (JZ4750_APUS || JZ4750_FUWA || JZ4750D_CETUS) && SND_SOC
|
|
||||||
help
|
|
||||||
Say Y or M if you want to add support for codecs attached to
|
|
||||||
the Jz4750 AC97, I2S or SSP interface. You will also need
|
|
||||||
to select the audio interfaces to support below.
|
|
||||||
|
|
||||||
config SND_JZ4750_SOC_APUS
|
|
||||||
tristate "SoC Audio support for Ingenic Jz4750 APUS board"
|
|
||||||
depends on SND_JZ4750_SOC
|
|
||||||
help
|
|
||||||
Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4750 APUS board.
|
|
||||||
|
|
||||||
config SND_JZ4750_AC97
|
|
||||||
tristate "select AC97 protocol and AC97 codec pcm core support"
|
|
||||||
depends on SND_JZ4750_SOC && SND_JZ4750_SOC_APUS
|
|
||||||
select SND_AC97_CODEC
|
|
||||||
help
|
|
||||||
Say Y if you want to add AC97 protocol support for pcm core.
|
|
||||||
|
|
||||||
config SND_JZ4750_SOC_AC97
|
|
||||||
tristate "SoC Audio (AC97 protocol) for Ingenic jz4750 chip"
|
|
||||||
depends on SND_JZ4750_SOC && SND_JZ4750_AC97 && SND_JZ4750_SOC_APUS
|
|
||||||
select AC97_BUS
|
|
||||||
select SND_SOC_AC97_BUS
|
|
||||||
help
|
|
||||||
Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4750 APUS board.
|
|
||||||
|
|
||||||
config SND_JZ4750_SOC_I2S
|
|
||||||
depends on SND_JZ4750_SOC && SND_JZ4750_SOC_APUS
|
|
||||||
tristate "SoC Audio (I2S protocol) for Ingenic jz4750 chip"
|
|
||||||
help
|
|
||||||
Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4750 APUS board.
|
|
@ -1,15 +0,0 @@
|
|||||||
#
|
|
||||||
# Jz4750 Platform Support
|
|
||||||
#
|
|
||||||
snd-soc-jz4750-objs := jz4750-pcm.o
|
|
||||||
snd-soc-jz4750-ac97-objs := jz4750-ac97.o
|
|
||||||
snd-soc-jz4750-i2s-objs := jz4750-i2s.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_SND_JZ4750_SOC) += snd-soc-jz4750.o
|
|
||||||
obj-$(CONFIG_SND_JZ4750_SOC_AC97) += snd-soc-jz4750-ac97.o
|
|
||||||
obj-$(CONFIG_SND_JZ4750_SOC_I2S) += snd-soc-jz4750-i2s.o
|
|
||||||
|
|
||||||
# Jz4750 Machine Support
|
|
||||||
snd-soc-apus-objs := apus.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_SND_JZ4750_SOC_APUS) += snd-soc-apus.o
|
|
@ -1,405 +0,0 @@
|
|||||||
/*
|
|
||||||
* apus.c -- SoC audio for APUS
|
|
||||||
*
|
|
||||||
* 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 the
|
|
||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/moduleparam.h>
|
|
||||||
#include <linux/timer.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
#include <sound/soc-dapm.h>
|
|
||||||
#include <sound/tlv.h>
|
|
||||||
|
|
||||||
#include "../codecs/jzdlv.h"
|
|
||||||
#include "jz4750-pcm.h"
|
|
||||||
#include "jz4750-i2s.h"
|
|
||||||
|
|
||||||
//static struct snd_soc_machine apus;
|
|
||||||
|
|
||||||
#define APUS_HP 0
|
|
||||||
#define APUS_MIC 1
|
|
||||||
#define APUS_LINE 2
|
|
||||||
#define APUS_HEADSET 3
|
|
||||||
#define APUS_HP_OFF 4
|
|
||||||
#define APUS_SPK_ON 0
|
|
||||||
#define APUS_SPK_OFF 1
|
|
||||||
|
|
||||||
static int apus_jack_func;
|
|
||||||
static int apus_spk_func;
|
|
||||||
|
|
||||||
unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
|
|
||||||
{
|
|
||||||
unsigned short gpio_bit = 0;
|
|
||||||
|
|
||||||
return gpio_bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
|
|
||||||
{
|
|
||||||
unsigned short gpio_bit = 0;
|
|
||||||
|
|
||||||
return gpio_bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void apus_ext_control(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
int spk = 0, mic = 0, line = 0, hp = 0, hs = 0;
|
|
||||||
|
|
||||||
/* set up jack connection */
|
|
||||||
switch (apus_jack_func) {
|
|
||||||
case APUS_HP:
|
|
||||||
hp = 1;
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Mic Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Line Jack");
|
|
||||||
snd_soc_dapm_enable_pin(codec, "Headphone Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Headset Jack");
|
|
||||||
break;
|
|
||||||
case APUS_MIC:
|
|
||||||
mic = 1;
|
|
||||||
snd_soc_dapm_enable_pin(codec, "Mic Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Line Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Headphone Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Headset Jack");
|
|
||||||
break;
|
|
||||||
case APUS_LINE:
|
|
||||||
line = 1;
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Mic Jack");
|
|
||||||
snd_soc_dapm_enable_pin(codec, "Line Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Headphone Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Headset Jack");
|
|
||||||
break;
|
|
||||||
case APUS_HEADSET:
|
|
||||||
hs = 1;
|
|
||||||
mic = 1;
|
|
||||||
snd_soc_dapm_enable_pin(codec, "Mic Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Line Jack");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Headphone Jack");
|
|
||||||
snd_soc_dapm_enable_pin(codec, "Headset Jack");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apus_spk_func == APUS_SPK_ON)
|
|
||||||
spk = 1;
|
|
||||||
|
|
||||||
if (apus_spk_func == APUS_SPK_ON)
|
|
||||||
snd_soc_dapm_enable_pin(codec, "Ext Spk");
|
|
||||||
else
|
|
||||||
snd_soc_dapm_disable_pin(codec, "Ext Spk");
|
|
||||||
|
|
||||||
/* signal a DAPM event */
|
|
||||||
snd_soc_dapm_sync(codec);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_startup(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_codec *codec = rtd->socdev->codec;
|
|
||||||
|
|
||||||
/* check the jack status at stream startup */
|
|
||||||
apus_ext_control(codec);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we need to unmute the HP at shutdown as the mute burns power on apus */
|
|
||||||
static int apus_shutdown(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_codec *codec = rtd->socdev->codec;*/
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
|
||||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* set codec DAI configuration */
|
|
||||||
/*ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
|
|
||||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);*/
|
|
||||||
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
|
|
||||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* set cpu DAI configuration */
|
|
||||||
/*ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
|
|
||||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);*/
|
|
||||||
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
|
|
||||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* set the codec system clock for DAC and ADC */
|
|
||||||
/*ret = codec_dai->dai_ops.set_sysclk(codec_dai, JZDLV_SYSCLK, 111,
|
|
||||||
SND_SOC_CLOCK_IN);*/
|
|
||||||
ret = snd_soc_dai_set_sysclk(codec_dai, JZDLV_SYSCLK, 111,
|
|
||||||
SND_SOC_CLOCK_IN);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* set the I2S system clock as input (unused) */
|
|
||||||
/*ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, JZ4750_I2S_SYSCLK, 0,
|
|
||||||
SND_SOC_CLOCK_IN);*/
|
|
||||||
ret = snd_soc_dai_set_sysclk(cpu_dai, JZ4750_I2S_SYSCLK, 0,
|
|
||||||
SND_SOC_CLOCK_IN);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct snd_soc_ops apus_ops = {
|
|
||||||
.startup = apus_startup,
|
|
||||||
.hw_params = apus_hw_params,
|
|
||||||
.shutdown = apus_shutdown,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int apus_get_jack(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
ucontrol->value.integer.value[0] = apus_jack_func;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_set_jack(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
||||||
|
|
||||||
if (apus_jack_func == ucontrol->value.integer.value[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
apus_jack_func = ucontrol->value.integer.value[0];
|
|
||||||
apus_ext_control(codec);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_get_spk(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
ucontrol->value.integer.value[0] = apus_spk_func;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_set_spk(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
|
||||||
|
|
||||||
if (apus_spk_func == ucontrol->value.integer.value[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
apus_spk_func = ucontrol->value.integer.value[0];
|
|
||||||
apus_ext_control(codec);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
|
|
||||||
{
|
|
||||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, APUS_SCP_APM_ON);
|
|
||||||
;
|
|
||||||
else
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, APUS_SCP_APM_ON);
|
|
||||||
;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apus_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
|
|
||||||
{
|
|
||||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
|
||||||
//set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
|
|
||||||
;
|
|
||||||
else
|
|
||||||
//reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS);
|
|
||||||
;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_get_reg(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
//int reg = kcontrol->private_value & 0xFF;
|
|
||||||
//int shift = (kcontrol->private_value >> 8) & 0x0F;
|
|
||||||
//int mask = (kcontrol->private_value >> 16) & 0xFF;
|
|
||||||
|
|
||||||
//ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jzdlv_set_reg(struct snd_kcontrol *kcontrol,
|
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
|
||||||
{
|
|
||||||
//int reg = kcontrol->private_value & 0xFF;
|
|
||||||
//int shift = (kcontrol->private_value >> 8) & 0x0F;
|
|
||||||
//int mask = (kcontrol->private_value >> 16) & 0xFF;
|
|
||||||
|
|
||||||
/*if (((lm4857_regs[reg] >> shift) & mask) ==
|
|
||||||
ucontrol->value.integer.value[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
lm4857_regs[reg] &= ~(mask << shift);
|
|
||||||
lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
|
|
||||||
lm4857_write_regs();*/
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* apus machine dapm widgets */
|
|
||||||
static const struct snd_soc_dapm_widget jzdlv_dapm_widgets[] = {
|
|
||||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
|
||||||
SND_SOC_DAPM_MIC("Mic Jack",apus_mic_event),
|
|
||||||
SND_SOC_DAPM_SPK("Ext Spk", apus_amp_event),
|
|
||||||
SND_SOC_DAPM_LINE("Line Jack", NULL),
|
|
||||||
SND_SOC_DAPM_HP("Headset Jack", NULL),
|
|
||||||
};
|
|
||||||
|
|
||||||
/* apus machine audio map (connections to the codec pins) */
|
|
||||||
static const struct snd_soc_dapm_route audio_map[] = {
|
|
||||||
|
|
||||||
/* headset Jack - in = micin, out = LHPOUT*/
|
|
||||||
{"Headset Jack", NULL, "LHPOUT"},
|
|
||||||
|
|
||||||
/* headphone connected to LHPOUT1, RHPOUT1 */
|
|
||||||
{"Headphone Jack", NULL, "LHPOUT"},
|
|
||||||
{"Headphone Jack", NULL, "RHPOUT"},
|
|
||||||
|
|
||||||
/* speaker connected to LOUT, ROUT */
|
|
||||||
{"Ext Spk", NULL, "ROUT"},
|
|
||||||
{"Ext Spk", NULL, "LOUT"},
|
|
||||||
|
|
||||||
/* mic is connected to MICIN (via right channel of headphone jack) */
|
|
||||||
{"MICIN", NULL, "Mic Jack"},
|
|
||||||
|
|
||||||
/* Same as the above but no mic bias for line signals */
|
|
||||||
{"MICIN", NULL, "Line Jack"},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
|
|
||||||
"Off"};
|
|
||||||
static const char *spk_function[] = {"On", "Off"};
|
|
||||||
static const struct soc_enum apus_enum[] = {
|
|
||||||
SOC_ENUM_SINGLE_EXT(5, jack_function),
|
|
||||||
SOC_ENUM_SINGLE_EXT(2, spk_function),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
|
|
||||||
//static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
|
|
||||||
|
|
||||||
static const struct snd_kcontrol_new jzdlv_apus_controls[] = {
|
|
||||||
/* SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", 1, 0, 31, 0,
|
|
||||||
jzdlv_get_reg, jzdlv_set_reg, stereo_tlv),*/
|
|
||||||
SOC_SINGLE_EXT_TLV("PCM", 1, 0, 31, 0,
|
|
||||||
jzdlv_get_reg, jzdlv_set_reg, stereo_tlv),
|
|
||||||
SOC_SINGLE_EXT_TLV("Capture", 2, 0, 31, 0,
|
|
||||||
jzdlv_get_reg, jzdlv_set_reg, stereo_tlv),
|
|
||||||
/* SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
|
|
||||||
lm4857_get_reg, lm4857_set_reg, mono_tlv),*/
|
|
||||||
|
|
||||||
SOC_ENUM_EXT("Jack Function", apus_enum[0], apus_get_jack,apus_set_jack),
|
|
||||||
SOC_ENUM_EXT("Speaker Function", apus_enum[1], apus_get_spk,apus_set_spk),
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Apus for a jzdlv as connected on jz4750 Device
|
|
||||||
*/
|
|
||||||
static int apus_jzdlv_init(struct snd_soc_codec *codec)
|
|
||||||
{
|
|
||||||
int i, err;
|
|
||||||
|
|
||||||
snd_soc_dapm_disable_pin(codec, "LLINEIN");
|
|
||||||
snd_soc_dapm_disable_pin(codec, "RLINEIN");
|
|
||||||
|
|
||||||
/* Add apus specific controls */
|
|
||||||
for (i = 0; i < ARRAY_SIZE(jzdlv_apus_controls); i++) {
|
|
||||||
err = snd_ctl_add(codec->card,
|
|
||||||
snd_soc_cnew(&jzdlv_apus_controls[i],codec, NULL));
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add apus specific widgets */
|
|
||||||
snd_soc_dapm_new_controls(codec, jzdlv_dapm_widgets,
|
|
||||||
ARRAY_SIZE(jzdlv_dapm_widgets));
|
|
||||||
|
|
||||||
/* Set up apus specific audio path audio_map */
|
|
||||||
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
|
|
||||||
snd_soc_dapm_sync(codec);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* apus digital audio interface glue - connects codec <--> CPU */
|
|
||||||
static struct snd_soc_dai_link apus_dai = {
|
|
||||||
.name = "JZDLV",
|
|
||||||
.stream_name = "JZDLV",
|
|
||||||
.cpu_dai = &jz4750_i2s_dai,
|
|
||||||
.codec_dai = &jzdlv_dai,
|
|
||||||
.init = apus_jzdlv_init,
|
|
||||||
.ops = &apus_ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* apus audio machine driver */
|
|
||||||
static struct snd_soc_machine snd_soc_machine_apus = {
|
|
||||||
.name = "Apus",
|
|
||||||
.dai_link = &apus_dai,
|
|
||||||
.num_links = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* apus audio subsystem */
|
|
||||||
static struct snd_soc_device apus_snd_devdata = {
|
|
||||||
.machine = &snd_soc_machine_apus,
|
|
||||||
.platform = &jz4750_soc_platform,
|
|
||||||
.codec_dev = &soc_codec_dev_jzdlv,
|
|
||||||
//.codec_data
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct platform_device *apus_snd_device;
|
|
||||||
|
|
||||||
static int __init apus_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
apus_snd_device = platform_device_alloc("soc-audio", -1);
|
|
||||||
|
|
||||||
if (!apus_snd_device)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
platform_set_drvdata(apus_snd_device, &apus_snd_devdata);
|
|
||||||
apus_snd_devdata.dev = &apus_snd_device->dev;
|
|
||||||
ret = platform_device_add(apus_snd_device);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
platform_device_put(apus_snd_device);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit apus_exit(void)
|
|
||||||
{
|
|
||||||
platform_device_unregister(apus_snd_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(apus_init);
|
|
||||||
module_exit(apus_exit);
|
|
||||||
|
|
||||||
/* Module information */
|
|
||||||
MODULE_AUTHOR("Richard");
|
|
||||||
MODULE_DESCRIPTION("ALSA SoC Apus");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,261 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip.
|
|
||||||
*
|
|
||||||
* Author: Richard
|
|
||||||
* Created: Dec 02, 2007
|
|
||||||
* Copyright: Ingenic Semiconductor Inc.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/wait.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/ac97_codec.h>
|
|
||||||
#include <sound/initval.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
|
|
||||||
#include <asm/irq.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <asm/hardware.h>
|
|
||||||
#include <asm/arch/audio.h>
|
|
||||||
|
|
||||||
#include "jz4740-pcm.h"
|
|
||||||
#include "jz4740-ac97.h"
|
|
||||||
|
|
||||||
static DEFINE_MUTEX(car_mutex);
|
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
|
|
||||||
static volatile long gsr_bits;
|
|
||||||
|
|
||||||
static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97,
|
|
||||||
unsigned short reg)
|
|
||||||
{
|
|
||||||
unsigned short val = -1;
|
|
||||||
volatile u32 *reg_addr;
|
|
||||||
|
|
||||||
mutex_lock(&car_mutex);
|
|
||||||
|
|
||||||
out: mutex_unlock(&car_mutex);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
|
||||||
unsigned short val)
|
|
||||||
{
|
|
||||||
volatile u32 *reg_addr;
|
|
||||||
|
|
||||||
mutex_lock(&car_mutex);
|
|
||||||
|
|
||||||
mutex_unlock(&car_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97)
|
|
||||||
{
|
|
||||||
gsr_bits = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id)
|
|
||||||
{
|
|
||||||
long status;
|
|
||||||
return IRQ_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct snd_ac97_bus_ops soc_ac97_ops = {
|
|
||||||
.read = jz4740_ac97_read,
|
|
||||||
.write = jz4740_ac97_write,
|
|
||||||
.warm_reset = jz4740_ac97_warm_reset,
|
|
||||||
.reset = jz4740_ac97_cold_reset,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = {
|
|
||||||
.name = "AC97 PCM Stereo out",
|
|
||||||
.dev_addr = __PREG(PCDR),
|
|
||||||
.drcmr = &DRCMRTXPCDR,
|
|
||||||
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
|
||||||
DCMD_BURST32 | DCMD_WIDTH4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = {
|
|
||||||
.name = "AC97 PCM Stereo in",
|
|
||||||
.dev_addr = __PREG(PCDR),
|
|
||||||
.drcmr = &DRCMRRXPCDR,
|
|
||||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
|
||||||
DCMD_BURST32 | DCMD_WIDTH4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = {
|
|
||||||
.name = "AC97 Aux PCM (Slot 5) Mono out",
|
|
||||||
.dev_addr = __PREG(MODR),
|
|
||||||
.drcmr = &DRCMRTXMODR,
|
|
||||||
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
|
||||||
DCMD_BURST16 | DCMD_WIDTH2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = {
|
|
||||||
.name = "AC97 Aux PCM (Slot 5) Mono in",
|
|
||||||
.dev_addr = __PREG(MODR),
|
|
||||||
.drcmr = &DRCMRRXMODR,
|
|
||||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
|
||||||
DCMD_BURST16 | DCMD_WIDTH2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = {
|
|
||||||
.name = "AC97 Mic PCM (Slot 6) Mono in",
|
|
||||||
.dev_addr = __PREG(MCDR),
|
|
||||||
.drcmr = &DRCMRRXMCDR,
|
|
||||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
|
||||||
DCMD_BURST16 | DCMD_WIDTH2,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static int jz4740_ac97_suspend(struct platform_device *pdev,
|
|
||||||
struct snd_soc_cpu_dai *dai)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_resume(struct platform_device *pdev,
|
|
||||||
struct snd_soc_cpu_dai *dai)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define jz4740_ac97_suspend NULL
|
|
||||||
#define jz4740_ac97_resume NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int jz4740_ac97_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4740_ac97_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out;
|
|
||||||
else
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out;
|
|
||||||
else
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
return -ENODEV;
|
|
||||||
else
|
|
||||||
cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
|
||||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
|
|
||||||
SNDRV_PCM_RATE_48000)
|
|
||||||
|
|
||||||
struct snd_soc_cpu_dai jz4740_ac97_dai[] = {
|
|
||||||
{
|
|
||||||
.name = "jz4740-ac97",
|
|
||||||
.id = 0,
|
|
||||||
.type = SND_SOC_DAI_AC97,
|
|
||||||
.probe = jz4740_ac97_probe,
|
|
||||||
.remove = jz4740_ac97_remove,
|
|
||||||
.suspend = jz4740_ac97_suspend,
|
|
||||||
.resume = jz4740_ac97_resume,
|
|
||||||
.playback = {
|
|
||||||
.stream_name = "AC97 Playback",
|
|
||||||
.channels_min = 2,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "AC97 Capture",
|
|
||||||
.channels_min = 2,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.hw_params = jz4740_ac97_hw_params,},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "jz4740-ac97-aux",
|
|
||||||
.id = 1,
|
|
||||||
.type = SND_SOC_DAI_AC97,
|
|
||||||
.playback = {
|
|
||||||
.stream_name = "AC97 Aux Playback",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 1,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "AC97 Aux Capture",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 1,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.hw_params = jz4740_ac97_hw_aux_params,},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "jz4740-ac97-mic",
|
|
||||||
.id = 2,
|
|
||||||
.type = SND_SOC_DAI_AC97,
|
|
||||||
.capture = {
|
|
||||||
.stream_name = "AC97 Mic Capture",
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 1,
|
|
||||||
.rates = JZ4740_AC97_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.hw_params = jz4740_ac97_hw_mic_params,},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4740_ac97_dai);
|
|
||||||
EXPORT_SYMBOL_GPL(soc_ac97_ops);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Richard");
|
|
||||||
MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/sound/soc/jz4750/jz4750-ac97.h
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JZ4750_AC97_H
|
|
||||||
#define _JZ4750_AC97_H
|
|
||||||
|
|
||||||
#define JZ4750_DAI_AC97_HIFI 0
|
|
||||||
#define JZ4750_DAI_AC97_AUX 1
|
|
||||||
#define JZ4750_DAI_AC97_MIC 2
|
|
||||||
|
|
||||||
extern struct snd_soc_cpu_dai jz4750_ac97_dai[3];
|
|
||||||
|
|
||||||
/* platform data */
|
|
||||||
extern struct snd_ac97_bus_ops jz4750_ac97_ops;
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,311 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 the
|
|
||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/pcm_params.h>
|
|
||||||
#include <sound/initval.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
|
|
||||||
#include "jz4750-pcm.h"
|
|
||||||
#include "jz4750-i2s.h"
|
|
||||||
#include "../codecs/jzdlv.h"
|
|
||||||
|
|
||||||
static struct jz4750_dma_client jz4750_dma_client_out = {
|
|
||||||
.name = "I2S PCM Stereo out"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4750_dma_client jz4750_dma_client_in = {
|
|
||||||
.name = "I2S PCM Stereo in"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_out = {
|
|
||||||
.client = &jz4750_dma_client_out,
|
|
||||||
.channel = DMA_ID_AIC_TX,
|
|
||||||
.dma_addr = AIC_DR,
|
|
||||||
.dma_size = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct jz4750_pcm_dma_params jz4750_i2s_pcm_stereo_in = {
|
|
||||||
.client = &jz4750_dma_client_in,
|
|
||||||
.channel = DMA_ID_AIC_RX,
|
|
||||||
.dma_addr = AIC_DR,
|
|
||||||
.dma_size = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int jz4750_i2s_startup(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
/*struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|
||||||
unsigned int fmt)
|
|
||||||
{
|
|
||||||
/* interface format */
|
|
||||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
|
||||||
case SND_SOC_DAIFMT_I2S:
|
|
||||||
/* 1 : ac97 , 0 : i2s */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_LEFT_J:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
|
||||||
case SND_SOC_DAIFMT_CBS_CFS:
|
|
||||||
/* 0 : slave */
|
|
||||||
break;
|
|
||||||
case SND_SOC_DAIFMT_CBM_CFS:
|
|
||||||
/* 1 : master */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set Jz4750 Clock source
|
|
||||||
*/
|
|
||||||
static int jz4750_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
|
|
||||||
int clk_id, unsigned int freq, int dir)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4750_snd_tx_ctrl(int on)
|
|
||||||
{
|
|
||||||
if (on) {
|
|
||||||
/* enable replay */
|
|
||||||
__i2s_enable_transmit_dma();
|
|
||||||
__i2s_enable_replay();
|
|
||||||
__i2s_enable();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* disable replay & capture */
|
|
||||||
__i2s_disable_replay();
|
|
||||||
__i2s_disable_record();
|
|
||||||
__i2s_disable_receive_dma();
|
|
||||||
__i2s_disable_transmit_dma();
|
|
||||||
__i2s_disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4750_snd_rx_ctrl(int on)
|
|
||||||
{
|
|
||||||
if (on) {
|
|
||||||
/* enable capture */
|
|
||||||
__i2s_enable_receive_dma();
|
|
||||||
__i2s_enable_record();
|
|
||||||
__i2s_enable();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* disable replay & capture */
|
|
||||||
__i2s_disable_replay();
|
|
||||||
__i2s_disable_record();
|
|
||||||
__i2s_disable_receive_dma();
|
|
||||||
__i2s_disable_transmit_dma();
|
|
||||||
__i2s_disable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_i2s_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
//struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
|
|
||||||
int channels = params_channels(params);
|
|
||||||
|
|
||||||
jz4750_snd_rx_ctrl(0);
|
|
||||||
jz4750_snd_rx_ctrl(0);
|
|
||||||
write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
//cpu_dai->dma_data = &jz4750_i2s_pcm_stereo_out;
|
|
||||||
rtd->dai->cpu_dai->dma_data = &jz4750_i2s_pcm_stereo_out;
|
|
||||||
if (channels == 1)
|
|
||||||
__aic_enable_mono2stereo();
|
|
||||||
else
|
|
||||||
__aic_disable_mono2stereo();
|
|
||||||
} else
|
|
||||||
rtd->dai->cpu_dai->dma_data = &jz4750_i2s_pcm_stereo_in;
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
switch (channels) {
|
|
||||||
case 1:
|
|
||||||
write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
switch (params_format(params)) {
|
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
|
||||||
__i2s_set_transmit_trigger(4);
|
|
||||||
__i2s_set_receive_trigger(3);
|
|
||||||
__i2s_set_oss_sample_size(8);
|
|
||||||
__i2s_set_iss_sample_size(8);
|
|
||||||
break;
|
|
||||||
case SNDRV_PCM_FORMAT_S16_LE:
|
|
||||||
/* playback sample:16 bits, burst:16 bytes */
|
|
||||||
__i2s_set_transmit_trigger(4);
|
|
||||||
/* capture sample:16 bits, burst:16 bytes */
|
|
||||||
__i2s_set_receive_trigger(3);
|
|
||||||
__i2s_set_oss_sample_size(16);
|
|
||||||
__i2s_set_iss_sample_size(16);
|
|
||||||
/* DAC path and ADC path */
|
|
||||||
write_codec_file(2, 0x00);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
|
||||||
jz4750_snd_rx_ctrl(1);
|
|
||||||
else
|
|
||||||
jz4750_snd_tx_ctrl(1);
|
|
||||||
break;
|
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
|
||||||
jz4750_snd_rx_ctrl(0);
|
|
||||||
else
|
|
||||||
jz4750_snd_tx_ctrl(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4750_i2s_shutdown(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_i2s_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
__i2s_internal_codec();
|
|
||||||
__i2s_as_slave();
|
|
||||||
__i2s_select_i2s();
|
|
||||||
__aic_select_i2s();
|
|
||||||
mdelay(2);
|
|
||||||
|
|
||||||
__i2s_disable();
|
|
||||||
mdelay(2);
|
|
||||||
REG_AIC_I2SCR = 0x10;
|
|
||||||
__i2s_disable();
|
|
||||||
__i2s_internal_codec();
|
|
||||||
__i2s_as_slave();
|
|
||||||
__i2s_select_i2s();
|
|
||||||
__aic_select_i2s();
|
|
||||||
__i2s_set_oss_sample_size(16);
|
|
||||||
__i2s_set_iss_sample_size(16);
|
|
||||||
__aic_play_lastsample();
|
|
||||||
|
|
||||||
__i2s_disable_record();
|
|
||||||
__i2s_disable_replay();
|
|
||||||
__i2s_disable_loopback();
|
|
||||||
__i2s_set_transmit_trigger(7);
|
|
||||||
__i2s_set_receive_trigger(7);
|
|
||||||
|
|
||||||
jz4750_snd_tx_ctrl(0);
|
|
||||||
jz4750_snd_rx_ctrl(0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
static int jz4750_i2s_suspend(struct platform_device *dev,
|
|
||||||
struct snd_soc_dai *dai)
|
|
||||||
{
|
|
||||||
if (!dai->active)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_i2s_resume(struct platform_device *pdev,
|
|
||||||
struct snd_soc_dai *dai)
|
|
||||||
{
|
|
||||||
if (!dai->active)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define jz4750_i2s_suspend NULL
|
|
||||||
#define jz4750_i2s_resume NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define JZ4750_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
|
||||||
SNDRV_PCM_RATE_12000 | SNDRV_PCM_RATE_16000 |\
|
|
||||||
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_24000 |\
|
|
||||||
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
|
||||||
SNDRV_PCM_RATE_48000)
|
|
||||||
|
|
||||||
struct snd_soc_dai jz4750_i2s_dai = {
|
|
||||||
.name = "jz4750-i2s",
|
|
||||||
.id = 0,
|
|
||||||
.type = SND_SOC_DAI_I2S,
|
|
||||||
.probe = jz4750_i2s_probe,
|
|
||||||
.suspend = jz4750_i2s_suspend,
|
|
||||||
.resume = jz4750_i2s_resume,
|
|
||||||
.playback = {
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZ4750_I2S_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.capture = {
|
|
||||||
.channels_min = 1,
|
|
||||||
.channels_max = 2,
|
|
||||||
.rates = JZ4750_I2S_RATES,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
|
|
||||||
.ops = {
|
|
||||||
.startup = jz4750_i2s_startup,
|
|
||||||
.shutdown = jz4750_i2s_shutdown,
|
|
||||||
.trigger = jz4750_i2s_trigger,
|
|
||||||
.hw_params = jz4750_i2s_hw_params,},
|
|
||||||
.dai_ops = {
|
|
||||||
.set_fmt = jz4750_i2s_set_dai_fmt,
|
|
||||||
.set_sysclk = jz4750_i2s_set_dai_sysclk,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4750_i2s_dai);
|
|
||||||
|
|
||||||
/* Module information */
|
|
||||||
MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn");
|
|
||||||
MODULE_DESCRIPTION("jz4750 I2S SoC Interface");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JZ4750_I2S_H
|
|
||||||
#define _JZ4750_I2S_H
|
|
||||||
|
|
||||||
/* jz4750 DAI ID's */
|
|
||||||
#define JZ4750_DAI_I2S 0
|
|
||||||
|
|
||||||
/* I2S clock */
|
|
||||||
#define JZ4750_I2S_SYSCLK 0
|
|
||||||
|
|
||||||
extern struct snd_soc_dai jz4750_i2s_dai;
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,687 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
|
||||||
|
|
||||||
#include <sound/driver.h>
|
|
||||||
#include <sound/core.h>
|
|
||||||
#include <sound/pcm.h>
|
|
||||||
#include <sound/pcm_params.h>
|
|
||||||
#include <sound/soc.h>
|
|
||||||
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include "jz4750-pcm.h"
|
|
||||||
|
|
||||||
static long sum_bytes = 0;
|
|
||||||
static int first_transfer = 0;
|
|
||||||
static int printk_flag = 0;
|
|
||||||
static int tran_bit = 0;
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
static int hw_params_cnt = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct jz4750_dma_buf_aic {
|
|
||||||
struct jz4750_dma_buf_aic *next;
|
|
||||||
int size; /* buffer size in bytes */
|
|
||||||
dma_addr_t data; /* start of DMA data */
|
|
||||||
dma_addr_t ptr; /* where the DMA got to [1] */
|
|
||||||
void *id; /* client's id */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jz4750_runtime_data {
|
|
||||||
spinlock_t lock;
|
|
||||||
int state;
|
|
||||||
int aic_dma_flag; /* start dma transfer or not */
|
|
||||||
unsigned int dma_loaded;
|
|
||||||
unsigned int dma_limit;
|
|
||||||
unsigned int dma_period;
|
|
||||||
dma_addr_t dma_start;
|
|
||||||
dma_addr_t dma_pos;
|
|
||||||
dma_addr_t dma_end;
|
|
||||||
struct jz4750_pcm_dma_params *params;
|
|
||||||
|
|
||||||
dma_addr_t user_cur_addr; /* user current write buffer start address */
|
|
||||||
unsigned int user_cur_len; /* user current write buffer length */
|
|
||||||
|
|
||||||
/* buffer list and information */
|
|
||||||
struct jz4750_dma_buf_aic *curr; /* current dma buffer */
|
|
||||||
struct jz4750_dma_buf_aic *next; /* next buffer to load */
|
|
||||||
struct jz4750_dma_buf_aic *end; /* end of queue */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* identify hardware playback capabilities */
|
|
||||||
static const struct snd_pcm_hardware jz4750_pcm_hardware = {
|
|
||||||
.info = SNDRV_PCM_INFO_MMAP |
|
|
||||||
SNDRV_PCM_INFO_MMAP_VALID |
|
|
||||||
SNDRV_PCM_INFO_INTERLEAVED |
|
|
||||||
SNDRV_PCM_INFO_BLOCK_TRANSFER,
|
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
|
||||||
SNDRV_PCM_FMTBIT_U16_LE |
|
|
||||||
SNDRV_PCM_FMTBIT_U8 |
|
|
||||||
SNDRV_PCM_FMTBIT_S8,
|
|
||||||
.rates = SNDRV_PCM_RATE_8000_96000/*0x3fe*/,
|
|
||||||
.rate_min = 8000,
|
|
||||||
.rate_max = 96000,
|
|
||||||
.channels_min = 1,//2
|
|
||||||
.channels_max = 2,
|
|
||||||
.buffer_bytes_max = 128 * 1024,//16 * 1024
|
|
||||||
.period_bytes_min = PAGE_SIZE,
|
|
||||||
.period_bytes_max = PAGE_SIZE * 2,
|
|
||||||
.periods_min = 2,
|
|
||||||
.periods_max = 128,//16,
|
|
||||||
.fifo_size = 32,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* jz4750__dma_buf_enqueue
|
|
||||||
*
|
|
||||||
* queue an given buffer for dma transfer.
|
|
||||||
*
|
|
||||||
* data the physical address of the buffer data
|
|
||||||
* size the size of the buffer in bytes
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int jz4750_dma_buf_enqueue(struct jz4750_runtime_data *prtd, dma_addr_t data, int size)
|
|
||||||
{
|
|
||||||
struct jz4750_dma_buf_aic *aic_buf;
|
|
||||||
|
|
||||||
aic_buf = kzalloc(sizeof(struct jz4750_dma_buf_aic), GFP_KERNEL);
|
|
||||||
if (aic_buf == NULL) {
|
|
||||||
printk("aic buffer allocate failed,no memory!\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
aic_buf->data = aic_buf->ptr = data;
|
|
||||||
aic_buf->size = size;
|
|
||||||
if( prtd->curr == NULL) {
|
|
||||||
prtd->curr = aic_buf;
|
|
||||||
prtd->end = aic_buf;
|
|
||||||
prtd->next = NULL;
|
|
||||||
} else {
|
|
||||||
if (prtd->end == NULL)
|
|
||||||
printk("prtd->end is NULL\n");
|
|
||||||
prtd->end->next = aic_buf;
|
|
||||||
prtd->end = aic_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if necessary, update the next buffer field */
|
|
||||||
if (prtd->next == NULL)
|
|
||||||
prtd->next = aic_buf;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void audio_start_dma(struct jz4750_runtime_data *prtd, int mode)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
struct jz4750_dma_buf_aic *aic_buf;
|
|
||||||
int channel;
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case DMA_MODE_WRITE:
|
|
||||||
/* free cur aic_buf */
|
|
||||||
if (first_transfer == 1) {
|
|
||||||
first_transfer = 0;
|
|
||||||
} else {
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
if (aic_buf != NULL) {
|
|
||||||
prtd->curr = aic_buf->next;
|
|
||||||
prtd->next = aic_buf->next;
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
kfree(aic_buf);
|
|
||||||
aic_buf = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aic_buf = prtd->next;
|
|
||||||
channel = prtd->params->channel;
|
|
||||||
if (aic_buf) {
|
|
||||||
flags = claim_dma_lock();
|
|
||||||
disable_dma(channel);
|
|
||||||
jz_set_alsa_dma(channel, mode, tran_bit);
|
|
||||||
set_dma_addr(channel, aic_buf->data);
|
|
||||||
set_dma_count(channel, aic_buf->size);
|
|
||||||
enable_dma(channel);
|
|
||||||
release_dma_lock(flags);
|
|
||||||
prtd->aic_dma_flag |= AIC_START_DMA;
|
|
||||||
} else {
|
|
||||||
printk("next buffer is NULL for playback\n");
|
|
||||||
prtd->aic_dma_flag &= ~AIC_START_DMA;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DMA_MODE_READ:
|
|
||||||
/* free cur aic_buf */
|
|
||||||
if (first_transfer == 1) {
|
|
||||||
first_transfer = 0;
|
|
||||||
} else {
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
if (aic_buf != NULL) {
|
|
||||||
prtd->curr = aic_buf->next;
|
|
||||||
prtd->next = aic_buf->next;
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
kfree(aic_buf);
|
|
||||||
aic_buf = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aic_buf = prtd->next;
|
|
||||||
channel = prtd->params->channel;
|
|
||||||
|
|
||||||
if (aic_buf) {
|
|
||||||
flags = claim_dma_lock();
|
|
||||||
disable_dma(channel);
|
|
||||||
jz_set_alsa_dma(channel, mode, tran_bit);
|
|
||||||
set_dma_addr(channel, aic_buf->data);
|
|
||||||
set_dma_count(channel, aic_buf->size);
|
|
||||||
enable_dma(channel);
|
|
||||||
release_dma_lock(flags);
|
|
||||||
prtd->aic_dma_flag |= AIC_START_DMA;
|
|
||||||
} else {
|
|
||||||
printk("next buffer is NULL for capture\n");
|
|
||||||
prtd->aic_dma_flag &= ~AIC_START_DMA;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* place a dma buffer onto the queue for the dma system to handle.
|
|
||||||
*/
|
|
||||||
static void jz4750_pcm_enqueue(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd = runtime->private_data;
|
|
||||||
/*struct snd_dma_buffer *buf = &substream->dma_buffer;*/
|
|
||||||
dma_addr_t pos = prtd->dma_pos;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while (prtd->dma_loaded < prtd->dma_limit) {
|
|
||||||
unsigned long len = prtd->dma_period;
|
|
||||||
|
|
||||||
if ((pos + len) > prtd->dma_end) {
|
|
||||||
len = prtd->dma_end - pos;
|
|
||||||
}
|
|
||||||
ret = jz4750_dma_buf_enqueue(prtd, pos, len);
|
|
||||||
if (ret == 0) {
|
|
||||||
prtd->dma_loaded++;
|
|
||||||
pos += prtd->dma_period;
|
|
||||||
if (pos >= prtd->dma_end)
|
|
||||||
pos = prtd->dma_start;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prtd->dma_pos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call the function:jz4750_pcm_dma_irq() after DMA has transfered the current buffer
|
|
||||||
*/
|
|
||||||
static irqreturn_t jz4750_pcm_dma_irq(int dma_ch, void *dev_id)
|
|
||||||
{
|
|
||||||
struct snd_pcm_substream *substream = dev_id;
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd = runtime->private_data;
|
|
||||||
/*struct jz4750_dma_buf_aic *aic_buf = prtd->curr;*/
|
|
||||||
int channel = prtd->params->channel;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
disable_dma(channel);
|
|
||||||
prtd->aic_dma_flag &= ~AIC_START_DMA;
|
|
||||||
/* must clear TT bit in DCCSR to avoid interrupt again */
|
|
||||||
if (__dmac_channel_transmit_end_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_end(channel);
|
|
||||||
}
|
|
||||||
if (__dmac_channel_transmit_halt_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_halt(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__dmac_channel_address_error_detected(channel)) {
|
|
||||||
__dmac_channel_clear_address_error(channel);
|
|
||||||
}
|
|
||||||
if (substream)
|
|
||||||
snd_pcm_period_elapsed(substream);
|
|
||||||
|
|
||||||
spin_lock(&prtd->lock);
|
|
||||||
prtd->dma_loaded--;
|
|
||||||
if (prtd->state & ST_RUNNING) {
|
|
||||||
jz4750_pcm_enqueue(substream);
|
|
||||||
}
|
|
||||||
spin_unlock(&prtd->lock);
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
if (prtd->state & ST_RUNNING) {
|
|
||||||
if (prtd->dma_loaded) {
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
||||||
audio_start_dma(prtd, DMA_MODE_WRITE);
|
|
||||||
else
|
|
||||||
audio_start_dma(prtd, DMA_MODE_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
local_irq_restore(flags);
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* some parameter about DMA operation */
|
|
||||||
static int jz4750_pcm_hw_params(struct snd_pcm_substream *substream,
|
|
||||||
struct snd_pcm_hw_params *params)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd = runtime->private_data;
|
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
||||||
struct jz4750_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
|
|
||||||
size_t totbytes = params_buffer_bytes(params);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
if (hw_params_cnt)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
hw_params_cnt++ ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!dma)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (params_format(params)) {
|
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
|
||||||
tran_bit = 8;
|
|
||||||
break;
|
|
||||||
case SNDRV_PCM_FORMAT_S16_LE:
|
|
||||||
tran_bit = 16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare DMA */
|
|
||||||
prtd->params = dma;
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name,
|
|
||||||
jz4750_pcm_dma_irq, IRQF_DISABLED, substream);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
prtd->params->channel = ret;
|
|
||||||
} else {
|
|
||||||
ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name,
|
|
||||||
jz4750_pcm_dma_irq, IRQF_DISABLED, substream);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
prtd->params->channel = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
|
||||||
runtime->dma_bytes = totbytes;
|
|
||||||
|
|
||||||
spin_lock_irq(&prtd->lock);
|
|
||||||
prtd->dma_loaded = 0;
|
|
||||||
prtd->aic_dma_flag = 0;
|
|
||||||
prtd->dma_limit = runtime->hw.periods_min;
|
|
||||||
prtd->dma_period = params_period_bytes(params);
|
|
||||||
prtd->dma_start = runtime->dma_addr;
|
|
||||||
prtd->dma_pos = prtd->dma_start;
|
|
||||||
prtd->dma_end = prtd->dma_start + totbytes;
|
|
||||||
prtd->curr = NULL;
|
|
||||||
prtd->next = NULL;
|
|
||||||
prtd->end = NULL;
|
|
||||||
sum_bytes = 0;
|
|
||||||
first_transfer = 1;
|
|
||||||
printk_flag = 0;
|
|
||||||
|
|
||||||
__dmac_disable_descriptor(prtd->params->channel);
|
|
||||||
__dmac_channel_disable_irq(prtd->params->channel);
|
|
||||||
spin_unlock_irq(&prtd->lock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_pcm_hw_free(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct jz4750_runtime_data *prtd = substream->runtime->private_data;
|
|
||||||
|
|
||||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
|
||||||
if (prtd->params) {
|
|
||||||
jz_free_dma(prtd->params->channel);
|
|
||||||
prtd->params = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set some dma para for playback/capture */
|
|
||||||
static int jz4750_dma_ctrl(int channel)
|
|
||||||
{
|
|
||||||
disable_dma(channel);
|
|
||||||
|
|
||||||
/* must clear TT bit in DCCSR to avoid interrupt again */
|
|
||||||
if (__dmac_channel_transmit_end_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_end(channel);
|
|
||||||
}
|
|
||||||
if (__dmac_channel_transmit_halt_detected(channel)) {
|
|
||||||
__dmac_channel_clear_transmit_halt(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__dmac_channel_address_error_detected(channel)) {
|
|
||||||
__dmac_channel_clear_address_error(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_pcm_prepare(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct jz4750_runtime_data *prtd = substream->runtime->private_data;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* return if this is a bufferless transfer e.g */
|
|
||||||
if (!prtd->params)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* flush the DMA channel and DMA channel bit check */
|
|
||||||
jz4750_dma_ctrl(prtd->params->channel);
|
|
||||||
prtd->dma_loaded = 0;
|
|
||||||
prtd->dma_pos = prtd->dma_start;
|
|
||||||
|
|
||||||
/* enqueue dma buffers */
|
|
||||||
jz4750_pcm_enqueue(substream);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd = runtime->private_data;
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
|
||||||
prtd->state |= ST_RUNNING;
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
audio_start_dma(prtd, DMA_MODE_WRITE);
|
|
||||||
} else {
|
|
||||||
audio_start_dma(prtd, DMA_MODE_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
||||||
prtd->state &= ~ST_RUNNING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
|
||||||
printk(" RESUME \n");
|
|
||||||
break;
|
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
||||||
printk(" RESTART \n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static snd_pcm_uframes_t
|
|
||||||
jz4750_pcm_pointer(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd = runtime->private_data;
|
|
||||||
struct jz4750_dma_buf_aic *aic_buf = prtd->curr;
|
|
||||||
long count,res;
|
|
||||||
|
|
||||||
dma_addr_t ptr;
|
|
||||||
snd_pcm_uframes_t x;
|
|
||||||
int channel = prtd->params->channel;
|
|
||||||
|
|
||||||
spin_lock(&prtd->lock);
|
|
||||||
#if 1
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
} else {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
# else
|
|
||||||
|
|
||||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
REG_DMAC_DSAR(channel) = ptr;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
} else {
|
|
||||||
ptr = REG_DMAC_DSAR(channel);
|
|
||||||
if (ptr == 0x0)
|
|
||||||
printk("\ndma address is 00000000 in running!\n");
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) {
|
|
||||||
count = get_dma_residue(channel);
|
|
||||||
count = aic_buf->size - count;
|
|
||||||
ptr = aic_buf->data + count;
|
|
||||||
REG_DMAC_DTAR(channel) = ptr;
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
} else {
|
|
||||||
ptr = REG_DMAC_DTAR(channel);
|
|
||||||
if (ptr == 0x0)
|
|
||||||
printk("\ndma address is 00000000 in running!\n");
|
|
||||||
res = ptr - prtd->dma_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
spin_unlock(&prtd->lock);
|
|
||||||
x = bytes_to_frames(runtime, res);
|
|
||||||
if (x == runtime->buffer_size)
|
|
||||||
x = 0;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_pcm_open(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
hw_params_cnt = 0;
|
|
||||||
#endif
|
|
||||||
REG_DMAC_DMACKE(0) = 0x3f;
|
|
||||||
REG_DMAC_DMACKE(1) = 0x3f;
|
|
||||||
snd_soc_set_runtime_hwparams(substream, &jz4750_pcm_hardware);
|
|
||||||
prtd = kzalloc(sizeof(struct jz4750_runtime_data), GFP_KERNEL);
|
|
||||||
if (prtd == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
spin_lock_init(&prtd->lock);
|
|
||||||
|
|
||||||
runtime->private_data = prtd;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_pcm_close(struct snd_pcm_substream *substream)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
struct jz4750_runtime_data *prtd = runtime->private_data;
|
|
||||||
struct jz4750_dma_buf_aic *aic_buf = NULL;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
|
||||||
hw_params_cnt = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (prtd)
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
|
|
||||||
while (aic_buf != NULL) {
|
|
||||||
prtd->curr = aic_buf->next;
|
|
||||||
prtd->next = aic_buf->next;
|
|
||||||
aic_buf->next = NULL;
|
|
||||||
kfree(aic_buf);
|
|
||||||
aic_buf = NULL;
|
|
||||||
aic_buf = prtd->curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prtd) {
|
|
||||||
prtd->curr = NULL;
|
|
||||||
prtd->next = NULL;
|
|
||||||
prtd->end = NULL;
|
|
||||||
kfree(prtd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jz4750_pcm_mmap(struct snd_pcm_substream *substream,
|
|
||||||
struct vm_area_struct *vma)//include/linux/mm.h
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
||||||
unsigned long start;
|
|
||||||
unsigned long off;
|
|
||||||
u32 len;
|
|
||||||
int ret = -ENXIO;
|
|
||||||
|
|
||||||
off = vma->vm_pgoff << PAGE_SHIFT;
|
|
||||||
start = runtime->dma_addr;
|
|
||||||
|
|
||||||
len = PAGE_ALIGN((start & ~PAGE_MASK) + runtime->dma_bytes);
|
|
||||||
start &= PAGE_MASK;
|
|
||||||
|
|
||||||
if ((vma->vm_end - vma->vm_start + off) > len) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
off += start;
|
|
||||||
vma->vm_pgoff = off >> PAGE_SHIFT;
|
|
||||||
vma->vm_flags |= VM_IO;
|
|
||||||
|
|
||||||
#if defined(CONFIG_MIPS32)
|
|
||||||
pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
|
|
||||||
pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
|
|
||||||
/* pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; */
|
|
||||||
#endif
|
|
||||||
ret = io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
|
|
||||||
vma->vm_end - vma->vm_start,
|
|
||||||
vma->vm_page_prot);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct snd_pcm_ops jz4750_pcm_ops = {
|
|
||||||
.open = jz4750_pcm_open,
|
|
||||||
.close = jz4750_pcm_close,
|
|
||||||
.ioctl = snd_pcm_lib_ioctl,
|
|
||||||
.hw_params = jz4750_pcm_hw_params,
|
|
||||||
.hw_free = jz4750_pcm_hw_free,
|
|
||||||
.prepare = jz4750_pcm_prepare,
|
|
||||||
.trigger = jz4750_pcm_trigger,
|
|
||||||
.pointer = jz4750_pcm_pointer,
|
|
||||||
.mmap = jz4750_pcm_mmap,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int jz4750_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
|
|
||||||
{
|
|
||||||
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
|
|
||||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
|
||||||
size_t size = jz4750_pcm_hardware.buffer_bytes_max;
|
|
||||||
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
|
||||||
buf->dev.dev = pcm->card->dev;
|
|
||||||
buf->private_data = NULL;
|
|
||||||
|
|
||||||
/*buf->area = dma_alloc_coherent(pcm->card->dev, size,
|
|
||||||
&buf->addr, GFP_KERNEL);*/
|
|
||||||
buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
|
|
||||||
&buf->addr, GFP_KERNEL);
|
|
||||||
if (!buf->area)
|
|
||||||
return -ENOMEM;
|
|
||||||
buf->bytes = size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jz4750_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
|
||||||
{
|
|
||||||
struct snd_pcm_substream *substream;
|
|
||||||
struct snd_dma_buffer *buf;
|
|
||||||
int stream;
|
|
||||||
|
|
||||||
for (stream = 0; stream < 2; stream++) {
|
|
||||||
substream = pcm->streams[stream].substream;
|
|
||||||
if (!substream)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
buf = &substream->dma_buffer;
|
|
||||||
if (!buf->area)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dma_free_noncoherent(pcm->card->dev, buf->bytes,
|
|
||||||
buf->area, buf->addr);
|
|
||||||
buf->area = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 jz4750_pcm_dmamask = DMA_32BIT_MASK;
|
|
||||||
|
|
||||||
int jz4750_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
|
|
||||||
struct snd_pcm *pcm)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!card->dev->dma_mask)
|
|
||||||
card->dev->dma_mask = &jz4750_pcm_dmamask;
|
|
||||||
if (!card->dev->coherent_dma_mask)
|
|
||||||
card->dev->coherent_dma_mask = DMA_32BIT_MASK;
|
|
||||||
|
|
||||||
if (dai->playback.channels_min) {
|
|
||||||
ret = jz4750_pcm_preallocate_dma_buffer(pcm,
|
|
||||||
SNDRV_PCM_STREAM_PLAYBACK);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dai->capture.channels_min) {
|
|
||||||
ret = jz4750_pcm_preallocate_dma_buffer(pcm,
|
|
||||||
SNDRV_PCM_STREAM_CAPTURE);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct snd_soc_platform jz4750_soc_platform = {
|
|
||||||
.name = "jz4750-audio",
|
|
||||||
.pcm_ops = &jz4750_pcm_ops,
|
|
||||||
.pcm_new = jz4750_pcm_new,
|
|
||||||
.pcm_free = jz4750_pcm_free_dma_buffers,
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(jz4750_soc_platform);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Richard");
|
|
||||||
MODULE_DESCRIPTION("Ingenic Jz4750 PCM DMA module");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JZ4750_PCM_H
|
|
||||||
#define _JZ4750_PCM_H
|
|
||||||
|
|
||||||
#include <asm/jzsoc.h>
|
|
||||||
|
|
||||||
#define ST_RUNNING (1<<0)
|
|
||||||
#define ST_OPENED (1<<1)
|
|
||||||
|
|
||||||
#define AIC_START_DMA (1<<0)
|
|
||||||
#define AIC_END_DMA (1<<1)
|
|
||||||
|
|
||||||
struct jz4750_dma_client {
|
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct jz4750_pcm_dma_params {
|
|
||||||
struct jz4750_dma_client *client; /* stream identifier */
|
|
||||||
int channel; /* Channel ID */
|
|
||||||
dma_addr_t dma_addr;
|
|
||||||
int dma_size; /* Size of the DMA transfer */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* platform data */
|
|
||||||
extern struct snd_soc_platform jz4750_soc_platform;
|
|
||||||
|
|
||||||
#endif
|
|
@ -54,118 +54,6 @@ index 2389352..24dcb18 100644
|
|||||||
#define SNDRV_PCM_RATE_8000_48000 (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000)
|
#define SNDRV_PCM_RATE_8000_48000 (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000)
|
||||||
#define SNDRV_PCM_RATE_8000_96000 (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\
|
#define SNDRV_PCM_RATE_8000_96000 (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\
|
||||||
SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
|
SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
|
||||||
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
|
|
||||||
index 72cfd47..5ae0a2d 100644
|
|
||||||
--- a/sound/core/pcm_lib.c
|
|
||||||
+++ b/sound/core/pcm_lib.c
|
|
||||||
@@ -2076,6 +2076,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
|
|
||||||
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
|
|
||||||
}
|
|
||||||
|
|
||||||
+#if 0
|
|
||||||
snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
|
|
||||||
{
|
|
||||||
struct snd_pcm_runtime *runtime;
|
|
||||||
@@ -2091,6 +2092,99 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
|
|
||||||
return -EINVAL;
|
|
||||||
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
|
|
||||||
}
|
|
||||||
+#else
|
|
||||||
+snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
|
|
||||||
+{
|
|
||||||
+ struct snd_pcm_runtime *runtime;
|
|
||||||
+ int nonblock;
|
|
||||||
+
|
|
||||||
+ snd_pcm_sframes_t tmp_frames;
|
|
||||||
+ snd_pcm_sframes_t final_frames;
|
|
||||||
+ int channels;
|
|
||||||
+
|
|
||||||
+ snd_assert(substream != NULL, return -ENXIO);
|
|
||||||
+ runtime = substream->runtime;
|
|
||||||
+ snd_assert(runtime != NULL, return -ENXIO);
|
|
||||||
+ snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
|
|
||||||
+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
|
|
||||||
+ return -EBADFD;
|
|
||||||
+
|
|
||||||
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
|
|
||||||
+ if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * mono capture process for no mono codec
|
|
||||||
+ * function codec such as ipcood and dlv
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ tmp_frames = snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
|
|
||||||
+
|
|
||||||
+ channels = runtime->channels;
|
|
||||||
+
|
|
||||||
+ if (channels == 1) {
|
|
||||||
+ short *tmpbuf = kcalloc(tmp_frames, sizeof(short), GFP_KERNEL);
|
|
||||||
+ short *src, *dst, *end;
|
|
||||||
+
|
|
||||||
+ memcpy(tmpbuf, buf, frames_to_bytes(runtime, tmp_frames));
|
|
||||||
+
|
|
||||||
+ src = (short *)buf;
|
|
||||||
+ dst = (short *)tmpbuf;
|
|
||||||
+ end = dst + tmp_frames - 1;
|
|
||||||
+
|
|
||||||
+ src++;
|
|
||||||
+ dst++;
|
|
||||||
+ dst++;
|
|
||||||
+ final_frames = 1;
|
|
||||||
+ while (dst <= end) {
|
|
||||||
+ *src = *dst;
|
|
||||||
+ final_frames++;
|
|
||||||
+ src++;
|
|
||||||
+ dst++;
|
|
||||||
+ dst++;
|
|
||||||
+ }
|
|
||||||
+ tmp_frames = final_frames;
|
|
||||||
+ kfree(tmpbuf);
|
|
||||||
+
|
|
||||||
+#if 0
|
|
||||||
+ /* when i have time, i will try the code, no kcalloc */
|
|
||||||
+ snd_assert(runtime->dma_area, return -EFAULT);
|
|
||||||
+ if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
|
|
||||||
+ return -EFAULT;
|
|
||||||
+
|
|
||||||
+ unsigned int up_bytes = frames_to_bytes(runtime, frames);
|
|
||||||
+
|
|
||||||
+ int while_cnt = 4;
|
|
||||||
+ int while_all = up_bytes - 2;
|
|
||||||
+
|
|
||||||
+ while (while_cnt <= while_all) {
|
|
||||||
+ //printk("[%d = %d]\n",(while_cnt/2),while_cnt);
|
|
||||||
+ buf[(while_cnt/2)] = buf[while_cnt];
|
|
||||||
+ //printk("[%d = %d]\n",((while_cnt/2)+1),(while_cnt+1));
|
|
||||||
+ buf[((while_cnt/2)+1)] = buf[(while_cnt+1)];
|
|
||||||
+ while_cnt += 4;
|
|
||||||
+#if 0
|
|
||||||
+ buf[2] = buf[4];
|
|
||||||
+ buf[3] = buf[5];
|
|
||||||
+
|
|
||||||
+ buf[4] = buf[8];
|
|
||||||
+ buf[5] = buf[9];
|
|
||||||
+
|
|
||||||
+ buf[6] = buf[12];
|
|
||||||
+ buf[7] = buf[13];
|
|
||||||
+
|
|
||||||
+ buf[8] = buf[16];
|
|
||||||
+ buf[9] = buf[17];
|
|
||||||
+#endif
|
|
||||||
+ }
|
|
||||||
+ /* when i have time, i will try the code, no kcalloc */
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return tmp_frames;
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(snd_pcm_lib_read);
|
|
||||||
|
|
||||||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
|
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
|
||||||
index ac2150e..2a57ab7 100644
|
index ac2150e..2a57ab7 100644
|
||||||
--- a/sound/core/pcm_native.c
|
--- a/sound/core/pcm_native.c
|
||||||
@ -187,24 +75,6 @@ index ac2150e..2a57ab7 100644
|
|||||||
|
|
||||||
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
|
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
|
||||||
.count = ARRAY_SIZE(rates),
|
.count = ARRAY_SIZE(rates),
|
||||||
@@ -1764,9 +1765,17 @@ static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
|
|
||||||
struct snd_pcm_hw_rule *rule)
|
|
||||||
{
|
|
||||||
struct snd_pcm_hardware *hw = rule->private;
|
|
||||||
+#if 0
|
|
||||||
return snd_interval_list(hw_param_interval(params, rule->var),
|
|
||||||
snd_pcm_known_rates.count,
|
|
||||||
snd_pcm_known_rates.list, hw->rates);
|
|
||||||
+#else
|
|
||||||
+ //printk("hw->rates=0x%08x\n",hw->rates);//0x3b6
|
|
||||||
+ hw->rates = 0x3fe;//12KHz and 24KHz bits are all zero,you need set 1
|
|
||||||
+ return snd_interval_list(hw_param_interval(params, rule->var),
|
|
||||||
+ snd_pcm_known_rates.count,
|
|
||||||
+ snd_pcm_known_rates.list, hw->rates);
|
|
||||||
+#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
|
|
||||||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
|
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
|
||||||
index d3e786a..a5335f4 100644
|
index d3e786a..a5335f4 100644
|
||||||
--- a/sound/soc/Kconfig
|
--- a/sound/soc/Kconfig
|
||||||
@ -230,22 +100,17 @@ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
|
|||||||
index bbc97fd..493e216 100644
|
index bbc97fd..493e216 100644
|
||||||
--- a/sound/soc/codecs/Kconfig
|
--- a/sound/soc/codecs/Kconfig
|
||||||
+++ b/sound/soc/codecs/Kconfig
|
+++ b/sound/soc/codecs/Kconfig
|
||||||
@@ -176,3 +176,15 @@ config SND_SOC_WM9712
|
@@ -179,3 +179,15 @@ config SND_SOC_WM9712
|
||||||
|
|
||||||
config SND_SOC_WM9713
|
config SND_SOC_WM9713
|
||||||
tristate
|
tristate
|
||||||
+
|
+
|
||||||
+config SND_SOC_ICODEC
|
+config SND_SOC_JZCODEC
|
||||||
+ tristate "Jz4740 internal codec"
|
+ tristate "JZ4720/JZ4740 SoC internal codec"
|
||||||
+ depends on SND_SOC && SND_JZ4740_SOC_PAVO && SND_JZ4740_SOC_I2S
|
+ depends on SND_SOC && SOC_JZ4740
|
||||||
+ help
|
+ help
|
||||||
+ Say Y if you want to use internal codec on Ingenic Jz4740 PAVO board.
|
+ Say Y if you want to use internal codec on Ingenic JZ4720/JZ4740 based
|
||||||
+
|
+ boards.
|
||||||
+config SND_SOC_DLV
|
|
||||||
+ tristate "Jz4750 internal codec"
|
|
||||||
+ depends on SND_SOC && SND_JZ4750_SOC_APUS && SND_JZ4750_SOC_I2S
|
|
||||||
+ help
|
|
||||||
+ Say Y if you want to use internal codec on Ingenic Jz4750 APUS board.
|
|
||||||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
|
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
|
||||||
index 8b75305..f053c15 100644
|
index 8b75305..f053c15 100644
|
||||||
--- a/sound/soc/codecs/Makefile
|
--- a/sound/soc/codecs/Makefile
|
||||||
@ -262,7 +127,7 @@ index 8b75305..f053c15 100644
|
|||||||
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
|
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
|
||||||
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
|
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
|
||||||
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
|
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
|
||||||
+obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o
|
+obj-$(CONFIG_SND_SOC_JZCODEC) += snd-soc-jzcodec.o
|
||||||
--
|
--
|
||||||
1.5.6.5
|
1.5.6.5
|
||||||
|
|
||||||
|
229
target/linux/xburst/patches-2.6.31/410-soc-32bit-regs.patch
Normal file
229
target/linux/xburst/patches-2.6.31/410-soc-32bit-regs.patch
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
--- /opt/Projects/linux-2.6/sound/soc/soc-core.c 2009-09-02 16:48:38.000000000 +0200
|
||||||
|
+++ ./soc-core.c 2009-09-15 03:23:13.000000000 +0200
|
||||||
|
@@ -500,8 +500,8 @@
|
||||||
|
if (cpu_dai->ops->hw_params) {
|
||||||
|
ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
|
||||||
|
if (ret < 0) {
|
||||||
|
- printk(KERN_ERR "asoc: interface %s hw params failed\n",
|
||||||
|
- cpu_dai->name);
|
||||||
|
+ printk(KERN_ERR "asoc: interface %s hw params failed: %d\n",
|
||||||
|
+ cpu_dai->name, ret);
|
||||||
|
goto interface_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -842,7 +842,7 @@
|
||||||
|
* DAIs currently; we can't do this per link since some AC97
|
||||||
|
* codecs have non-AC97 DAIs.
|
||||||
|
*/
|
||||||
|
- if (!ac97)
|
||||||
|
+ if (!ac97) {
|
||||||
|
for (i = 0; i < card->num_links; i++) {
|
||||||
|
found = 0;
|
||||||
|
list_for_each_entry(dai, &dai_list, list)
|
||||||
|
@@ -856,6 +856,7 @@
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/* Note that we do not current check for codec components */
|
||||||
|
|
||||||
|
@@ -1263,11 +1264,11 @@
|
||||||
|
*
|
||||||
|
* Returns 1 for change else 0.
|
||||||
|
*/
|
||||||
|
-int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
|
||||||
|
- unsigned short mask, unsigned short value)
|
||||||
|
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
|
||||||
|
+ unsigned int mask, unsigned int value)
|
||||||
|
{
|
||||||
|
int change;
|
||||||
|
- unsigned short old, new;
|
||||||
|
+ unsigned int old, new;
|
||||||
|
|
||||||
|
mutex_lock(&io_mutex);
|
||||||
|
old = snd_soc_read(codec, reg);
|
||||||
|
@@ -1293,11 +1294,11 @@
|
||||||
|
*
|
||||||
|
* Returns 1 for change else 0.
|
||||||
|
*/
|
||||||
|
-int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
|
||||||
|
- unsigned short mask, unsigned short value)
|
||||||
|
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
|
||||||
|
+ unsigned int mask, unsigned int value)
|
||||||
|
{
|
||||||
|
int change;
|
||||||
|
- unsigned short old, new;
|
||||||
|
+ unsigned int old, new;
|
||||||
|
|
||||||
|
mutex_lock(&io_mutex);
|
||||||
|
old = snd_soc_read(codec, reg);
|
||||||
|
@@ -1586,7 +1587,7 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short val, bitmask;
|
||||||
|
+ unsigned int val, bitmask;
|
||||||
|
|
||||||
|
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
|
||||||
|
;
|
||||||
|
@@ -1615,8 +1616,8 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short val;
|
||||||
|
- unsigned short mask, bitmask;
|
||||||
|
+ unsigned int val;
|
||||||
|
+ unsigned int mask, bitmask;
|
||||||
|
|
||||||
|
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
|
||||||
|
;
|
||||||
|
@@ -1652,7 +1653,7 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short reg_val, val, mux;
|
||||||
|
+ unsigned int reg_val, val, mux;
|
||||||
|
|
||||||
|
reg_val = snd_soc_read(codec, e->reg);
|
||||||
|
val = (reg_val >> e->shift_l) & e->mask;
|
||||||
|
@@ -1691,8 +1692,8 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short val;
|
||||||
|
- unsigned short mask;
|
||||||
|
+ unsigned int val;
|
||||||
|
+ unsigned int mask;
|
||||||
|
|
||||||
|
if (ucontrol->value.enumerated.item[0] > e->max - 1)
|
||||||
|
return -EINVAL;
|
||||||
|
@@ -1852,7 +1853,7 @@
|
||||||
|
int max = mc->max;
|
||||||
|
unsigned int mask = (1 << fls(max)) - 1;
|
||||||
|
unsigned int invert = mc->invert;
|
||||||
|
- unsigned short val, val2, val_mask;
|
||||||
|
+ unsigned int val, val2, val_mask;
|
||||||
|
|
||||||
|
val = (ucontrol->value.integer.value[0] & mask);
|
||||||
|
if (invert)
|
||||||
|
@@ -1958,7 +1959,7 @@
|
||||||
|
unsigned int mask = (1 << fls(max)) - 1;
|
||||||
|
unsigned int invert = mc->invert;
|
||||||
|
int err;
|
||||||
|
- unsigned short val, val2, val_mask;
|
||||||
|
+ unsigned int val, val2, val_mask;
|
||||||
|
|
||||||
|
val_mask = mask << shift;
|
||||||
|
val = (ucontrol->value.integer.value[0] & mask);
|
||||||
|
@@ -2050,7 +2051,7 @@
|
||||||
|
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
|
unsigned int reg = mc->reg;
|
||||||
|
int min = mc->min;
|
||||||
|
- unsigned short val;
|
||||||
|
+ unsigned int val;
|
||||||
|
|
||||||
|
val = (ucontrol->value.integer.value[0]+min) & 0xff;
|
||||||
|
val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
|
||||||
|
@@ -2251,6 +2252,7 @@
|
||||||
|
if (!dai->ops)
|
||||||
|
dai->ops = &null_dai_ops;
|
||||||
|
|
||||||
|
+
|
||||||
|
INIT_LIST_HEAD(&dai->list);
|
||||||
|
|
||||||
|
mutex_lock(&client_mutex);
|
||||||
|
--- /opt/Projects/linux-2.6/sound/soc/soc-dapm.c 2009-09-02 16:48:38.000000000 +0200
|
||||||
|
+++ ./soc-dapm.c 2009-09-08 17:49:09.000000000 +0200
|
||||||
|
@@ -268,7 +268,7 @@
|
||||||
|
static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
|
||||||
|
{
|
||||||
|
int change, power;
|
||||||
|
- unsigned short old, new;
|
||||||
|
+ unsigned int old, new;
|
||||||
|
struct snd_soc_codec *codec = widget->codec;
|
||||||
|
|
||||||
|
/* check for valid widgets */
|
||||||
|
@@ -1246,7 +1246,6 @@
|
||||||
|
/**
|
||||||
|
* snd_soc_dapm_new_widgets - add new dapm widgets
|
||||||
|
* @codec: audio codec
|
||||||
|
- *
|
||||||
|
* Checks the codec for any new dapm widgets and creates them if found.
|
||||||
|
*
|
||||||
|
* Returns 0 for success.
|
||||||
|
@@ -1336,7 +1335,8 @@
|
||||||
|
|
||||||
|
ucontrol->value.integer.value[0] =
|
||||||
|
(snd_soc_read(widget->codec, reg) >> shift) & mask;
|
||||||
|
- if (shift != rshift)
|
||||||
|
+
|
||||||
|
+ if (shift != rshift)
|
||||||
|
ucontrol->value.integer.value[1] =
|
||||||
|
(snd_soc_read(widget->codec, reg) >> rshift) & mask;
|
||||||
|
if (invert) {
|
||||||
|
@@ -1372,7 +1372,7 @@
|
||||||
|
int max = mc->max;
|
||||||
|
unsigned int mask = (1 << fls(max)) - 1;
|
||||||
|
unsigned int invert = mc->invert;
|
||||||
|
- unsigned short val, val2, val_mask;
|
||||||
|
+ unsigned int val, val2, val_mask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
val = (ucontrol->value.integer.value[0] & mask);
|
||||||
|
@@ -1436,7 +1436,7 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short val, bitmask;
|
||||||
|
+ unsigned int val, bitmask;
|
||||||
|
|
||||||
|
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
|
||||||
|
;
|
||||||
|
@@ -1464,8 +1464,8 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short val, mux;
|
||||||
|
- unsigned short mask, bitmask;
|
||||||
|
+ unsigned int val, mux;
|
||||||
|
+ unsigned int mask, bitmask;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
|
||||||
|
@@ -1523,7 +1523,7 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short reg_val, val, mux;
|
||||||
|
+ unsigned int reg_val, val, mux;
|
||||||
|
|
||||||
|
reg_val = snd_soc_read(widget->codec, e->reg);
|
||||||
|
val = (reg_val >> e->shift_l) & e->mask;
|
||||||
|
@@ -1563,8 +1563,8 @@
|
||||||
|
{
|
||||||
|
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||||
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
|
- unsigned short val, mux;
|
||||||
|
- unsigned short mask;
|
||||||
|
+ unsigned int val, mux;
|
||||||
|
+ unsigned int mask;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (ucontrol->value.enumerated.item[0] > e->max - 1)
|
||||||
|
218,221c218,221
|
||||||
|
< int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
|
||||||
|
< unsigned short mask, unsigned short value);
|
||||||
|
< int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
|
||||||
|
< unsigned short mask, unsigned short value);
|
||||||
|
---
|
||||||
|
> int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
|
||||||
|
> unsigned int mask, unsigned int value);
|
||||||
|
> int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
|
||||||
|
> unsigned int mask, unsigned int value);
|
||||||
|
495,496c495,496
|
||||||
|
< unsigned short reg;
|
||||||
|
< unsigned short reg2;
|
||||||
|
---
|
||||||
|
> unsigned int reg;
|
||||||
|
> unsigned int reg2;
|
Loading…
Reference in New Issue
Block a user