1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-25 16:34:04 +02:00
openwrt-xburst/target/linux/xburst/files-2.6.27/sound/oss/jzcodec.c
Mirko Vogt dc3d3f1c49 yet another patchset - 2.6.27
it's basically also provided by ingenic and nativly based on 2.6.27,
adjusted to fit into the OpenWrt-environment
2009-10-28 03:13:11 +08:00

444 lines
9.3 KiB
C
Executable File

/*
* linux/drivers/sound/jzcodec.c
*
* JzSOC internal audio driver.
*
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <sound/driver.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/proc_fs.h>
#include <linux/soundcard.h>
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <asm/hardirq.h>
#include <asm/jzsoc.h>
#include "sound_config.h"
#define USE_NONE 1
#define USE_MIC 2
#define USE_LINEIN 3
typedef struct hpvol_shift_s
{
int hpvol;
int shift;
} hpvol_shift_t;
extern mixer_info info;
extern _old_mixer_info old_info;
extern int codec_volue_shift;
extern hpvol_shift_t hpvol_shift_table[72];
extern int abnormal_data_count;
extern void (*set_codec_mode)(void);
extern void (*each_time_init_codec)(void);
extern int (*set_codec_startup_param)(void);
extern void (*set_codec_volume_table)(void);
extern void (*set_codec_record)(int mode);
extern void (*set_codec_replay)(void);
extern void (*set_codec_replay_record)(int mode);
extern void (*turn_on_codec)(void);
extern void (*turn_off_codec)(void);
extern void (*set_codec_speed)(int rate);
extern void (*reset_codec)(void);
extern void (*codec_mixer_old_info_id_name)(void);
extern void (*codec_mixer_info_id_name)(void);
extern void (*set_codec_bass)(int val);
extern void (*set_codec_volume)(int val);
extern void (*set_codec_mic)(int val);
extern void (*set_codec_line)(int val);
extern void (*i2s_resume_codec)(void);
extern void (*i2s_suspend_codec)(void);
extern void (*set_codec_direct_mode)(void);
extern void (*clear_codec_direct_mode)(void);
static int jzcodec_reg[2];
void set_jzcodec_mode(void);
void each_time_init_jzcodec(void);
int set_jzcodec_startup_param(void);
void set_jzcodec_volume_table(void);
void set_jzcodec_replay(void);
void set_jzcodec_record(int mode);
void turn_on_jzcodec(void);
void turn_off_jzcodec(void);
void set_jzcodec_speed(int rate);
void reset_jzcodec(void);
void jzcodec_mixer_old_info_id_name(void);
void jzcodec_mixer_info_id_name(void);
void set_jzcodec_bass(int val);
void set_jzcodec_volume(int val);
void set_jzcodec_mic(int val);
void set_jzcodec_line(int val);
void in_codec_app1(void);
void in_codec_app12(void);
void HP_turn_on(void);
void HP_turn_off(void);
void resume_jzcodec(void);
void suspend_jzcodec(void);
void set_jzcodec_replay_record(int mode);
void set_jzcodec_mode(void)
{
__i2s_internal_codec();
__i2s_as_slave();
__i2s_select_i2s();
__aic_select_i2s();
REG_ICDC_CDCCR1 = 0x001b2303;
schedule_timeout(1);
REG_ICDC_CDCCR1 = 0x001b2302;
}
void each_time_init_jzcodec(void)
{
__i2s_disable();
__i2s_as_slave();
__i2s_set_oss_sample_size(16);
__i2s_set_iss_sample_size(16);
}
int set_jzcodec_startup_param(void)
{
REG_ICDC_CDCCR1 = 0x001b2300;
schedule_timeout(50);
REG_ICDC_CDCCR1 = 0x00033300;
schedule_timeout(5);
REG_ICDC_CDCCR1 = 0x17026300;
return 1;
}
void set_jzcodec_volume_table(void)
{
int errno,hpvol_step,sample_shift;
codec_volue_shift = 0;
hpvol_step = 3;
sample_shift = 0;
for(errno = 0;errno < 72;errno++) {
hpvol_shift_table[errno].hpvol = hpvol_step;
hpvol_shift_table[errno].shift = sample_shift;
hpvol_step --;
if(hpvol_step <= 0) {
hpvol_step = 3;
sample_shift ++;
}
}
}
void set_jzcodec_replay(void)
{
in_codec_app1();
}
void set_jzcodec_record(int mode)
{
switch (mode) {
case USE_NONE:
case USE_MIC:
in_codec_app12();
abnormal_data_count = 0;
break;
case USE_LINEIN:
REG_ICDC_CDCCR1 = 0x27022000;//for linein
mdelay(300);
break;
}
}
void set_jzcodec_replay_record(int mode)
{
long val = 0;
REG_ICDC_CDCCR1 = 0x00037302;
mdelay(2);
REG_ICDC_CDCCR1 = 0x03006000;
mdelay(2);
switch (mode) {
case USE_NONE:
case USE_MIC:
REG_ICDC_CDCCR1 = 0x17022000;//for mic
break;
case USE_LINEIN:
REG_ICDC_CDCCR1 = 0x27022000;//for linein
break;
}
val = REG_ICDC_CDCCR2;
val &= 0x0000ff00;
val |= 0x00170030;
REG_ICDC_CDCCR2 = val;
}
void turn_on_jzcodec(void)
{
HP_turn_on();
}
void set_jzcodec_direct_mode(void)
{
long val = 0;
REG_ICDC_CDCCR1 = 0x14000000;
val &= 0x0000ff00;
val |= 0x001f0033;
REG_ICDC_CDCCR2 = val;
mdelay(300);
}
void clear_jzcodec_direct_mode(void)
{
HP_turn_off();
}
void turn_off_jzcodec(void)
{
HP_turn_off();
}
void set_jzcodec_speed(int rate)
{
long codec_speed,speed = 0;
switch (rate) {
case 8000:
speed = 0;
break;
case 11025:
speed = 1;
break;
case 12000:
speed = 2;
break;
case 16000:
speed = 3;
break;
case 22050:
speed = 4;
break;
case 24000:
speed = 5;
break;
case 32000:
speed = 6;
break;
case 44100:
speed = 7;
break;
case 48000:
speed = 8;
break;
default:
break;
}
codec_speed = REG_ICDC_CDCCR2;
codec_speed |= 0x00000f00;
speed = speed << 8;
speed |= 0xfffff0ff;
codec_speed &= speed;
REG_ICDC_CDCCR2 = codec_speed;
}
void reset_jzcodec(void)
{
REG_ICDC_CDCCR1 |= 1;
mdelay(1);
REG_ICDC_CDCCR1 &= 0xfffffffe;
}
void jzcodec_mixer_old_info_id_name(void)
{
strncpy(info.id, "JZCODEC", sizeof(info.id));
strncpy(info.name,"Jz internal codec", sizeof(info.name));
}
void jzcodec_mixer_info_id_name(void)
{
strncpy(old_info.id, "JZCODEC", sizeof(old_info.id));
strncpy(old_info.name,"Jz internal codec", sizeof(old_info.name));
}
void set_jzcodec_bass(int val)
{
int bass_gain = 0;
if(val < 25)
bass_gain = 0;
if(val >= 25 && val < 50)
bass_gain = 1;
if(val >= 50 && val < 75)
bass_gain = 2;
if(val >= 75 && val <= 100 )
bass_gain = 3;
REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (bass_gain << 4));
}
void set_jzcodec_volume(int val)
{
unsigned int sample_oss;
int index,shift_max,vol_scale,vol_step,codec_volume;
shift_max = 0;
sample_oss = (REG_AIC_CR & 0x00380000) >> 19;
switch(sample_oss)
{
case 0x0:
shift_max = 4; /* 8 bits */
break;
case 0x1:
shift_max = 10; /* 16 bits */
break;
case 0x2:
shift_max = 12; /* 18 bits */
break;
case 0x3:
shift_max = 15; /* 20 bits */
break;
case 0x4:
shift_max = 19; /* 24 bits */
break;
}
vol_scale = 3 * (shift_max + 1);
vol_step = 100 / vol_scale;
for(index = 0;index <= 100;index += vol_step)
if( val <= index )
break;
if(index == 0)
index = vol_step;
index = index / vol_step;
if(index > vol_scale)
index = vol_scale;
index = vol_scale - index;
codec_volume = hpvol_shift_table[index].hpvol;
codec_volue_shift = hpvol_shift_table[index].shift;
codec_volume = 3;
REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume);
}
void set_jzcodec_mic(int val)
{
long mic_gain;
mic_gain = 31 * val /100;
REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 | (0x3 << 4));
REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (mic_gain << 16));
}
void set_jzcodec_line(int val)
{
long line_gain;
line_gain = 31 * val /100;
REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (line_gain << 16));
}
void HP_turn_on(void)
{
long val = 0;
/* simple and slow anti-pop */
REG_ICDC_CDCCR1 = 0x00037302;
mdelay(2);
REG_ICDC_CDCCR1 = 0x03006000;
mdelay(2);
REG_ICDC_CDCCR1 = 0x03002000;
val = REG_ICDC_CDCCR2;
val &= 0x0000ff00;
val |= 0x001f0033;
REG_ICDC_CDCCR2 = val;
}
void HP_turn_off(void)
{
mdelay(20);
REG_ICDC_CDCCR1 = 0x00033300;
}
void in_codec_app1(void)
{
/* test is OK */
HP_turn_on();
}
void in_codec_app12(void)
{
REG_ICDC_CDCCR1 = 0x14024300;
mdelay(300);
}
void resume_jzcodec(void)
{
REG_ICDC_CDCCR2 = 0x00170800;
mdelay(2);
REG_ICDC_CDCCR1 = 0x001f2102;
mdelay(5);
REG_ICDC_CDCCR1 = 0x00033302;
mdelay(550);
REG_ICDC_CDCCR1 = 0x00033300;
REG_ICDC_CDCCR1 = jzcodec_reg[0];
REG_ICDC_CDCCR2 = jzcodec_reg[1];
}
void suspend_jzcodec(void)
{
jzcodec_reg[0] = REG_ICDC_CDCCR1;
jzcodec_reg[1] = REG_ICDC_CDCCR2;
REG_ICDC_CDCCR1 = 0x001b2302;
mdelay(1);
REG_ICDC_CDCCR1 = 0x001b2102;
}
static int __init init_jzcodec(void)
{
set_codec_mode = set_jzcodec_mode;
each_time_init_codec = each_time_init_jzcodec;
set_codec_startup_param = set_jzcodec_startup_param;
set_codec_volume_table = set_jzcodec_volume_table;
set_codec_record = set_jzcodec_record;
set_codec_replay = set_jzcodec_replay;
set_codec_replay_record = set_jzcodec_replay_record;
turn_on_codec = turn_on_jzcodec;
turn_off_codec = turn_off_jzcodec;
set_codec_speed = set_jzcodec_speed;
reset_codec = reset_jzcodec;
codec_mixer_old_info_id_name = jzcodec_mixer_old_info_id_name;
codec_mixer_info_id_name = jzcodec_mixer_info_id_name;
set_codec_bass = set_jzcodec_bass;
set_codec_volume = set_jzcodec_volume;
set_codec_mic = set_jzcodec_mic;
set_codec_line = set_jzcodec_line;
i2s_resume_codec = resume_jzcodec;
i2s_suspend_codec = suspend_jzcodec;
set_codec_direct_mode = set_jzcodec_direct_mode;
clear_codec_direct_mode = clear_jzcodec_direct_mode;
return 0;
}
static void __exit cleanup_jzcodec(void)
{
REG_ICDC_CDCCR1 = 0x001b2302;
}
module_init(init_jzcodec);
module_exit(cleanup_jzcodec);