blob: 8c017b3c11296ef751ff4506e4ee36b3fc98b8e0 [file] [log] [blame]
/*
* tlv320dac31.c ---- DAC3100 ALSA Soc Audio Driver
*
* History:
* 2012/05/17 - [ Johnson Diao ] created file
*
* Copyright (C) 2004-2012, Ambarella, Inc.
*
* All rights reserved. No Part of this file may be reproduced, stored
* in a retrieval system, or transmitted, in any form, or by any means,
* electronic, mechanical, photocopying, recording, or otherwise,
* without the prior consent of Ambarella, Inc.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <linux/gpio.h>
#include <sound/tlv320dac31.h>
#include <linux/device.h>
#include "tlv320dac31.h"
#define DAC31_VERSION "0.1"
#define debug_dac (0)
#if debug_dac
#define PRINTK(arg...) printk(arg)
#else
#define PRINTK(arg...)
#endif
/* havn't test the headphone and mic ,so DO NOT DEFINE IT !!!! */
#define HAEDPHONE_JACK 0
/* whenever aplay/arecord is run, dac3100_hw_params() function gets called.
* This function reprograms the clock dividers etc. this flag can be used to
* disable this when the clock dividers are programmed by pps config file
*/
static int PLL_ENABLE=0;
/*
*****************************************************************************
* Function Definitions
*****************************************************************************
*/
static int dac31_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level);
/*
*----------------------------------------------------------------------------
* Function : snd_soc_get_volsw_2r_dac3100
* Purpose : Callback to get the value of a double mixer control that spans
* two registers.
*
*----------------------------------------------------------------------------
*/
int snd_soc_get_volsw_dac3100(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int reg = mc->reg;
int mask;
int shift;
unsigned short val;
PRINTK("snd_soc_get_volsw_dac3100 %s\n", kcontrol->id.name);
/* Check the id name of the kcontrol and configure the mask and shift */
if (!strcmp(kcontrol->id.name,"Mic Register Volume")) {
mask = 0x7f;
shift =0;
} else {
printk(KERN_ALERT "Invalid kcontrol name\n");
return -1;
}
val = (snd_soc_read(codec, reg) >> shift) & mask;
if (!strcmp(kcontrol->id.name,"Mic Register Volume")) {
ucontrol->value.integer.value[0] = (126-val);
}
return 0;
}
/*
*----------------------------------------------------------------------------
* Function : snd_soc_put_volsw_2r_dac3100
* Purpose : Callback to set the value of a double mixer control that spans
* two registers.
*
*----------------------------------------------------------------------------
*/
int snd_soc_put_volsw_dac3100(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
int err;
unsigned short val, val_mask;
PRINTK("snd_soc_put_volsw_dac3100 (%s)\n", kcontrol->id.name);
val = (ucontrol->value.integer.value[0] << shift);
PRINTK("\nval= 0x%x \n",val);
if (!strcmp(kcontrol->id.name,"Mic Register Volume")) {
val = 126-val;
val_mask = 0x7f;
}else {
printk(KERN_ALERT "Invalid control name\n");
return -1;
}
if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) {
printk(KERN_ALERT "Error while updating bits\n");
return err;
}
return err;
}
/*
*----------------------------------------------------------------------------
* Function : snd_soc_get_volsw_2r_dac3100
* Purpose : Callback to get the value of a double mixer control that spans
* two registers.
*
*----------------------------------------------------------------------------
*/
int snd_soc_get_volsw_2r_dac3100(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int reg = mc->reg;
int reg2 = mc->rreg;
int mask;
int shift;
unsigned short val, val2;
PRINTK("snd_soc_get_volsw_2r_dac3100 %s\n", kcontrol->id.name);
/* Check the id name of the kcontrol and configure the mask and shift */
if (!strcmp(kcontrol->id.name, "DAC Playback Volume")) {
mask = dac3100_8BITS_MASK;
shift = 0;
} else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) {
mask = 0xF;
shift = 3;
} else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
mask = 0x7F;
shift = 0;
} else {
printk(KERN_ALERT "Invalid kcontrol name\n");
return -1;
}
val = (snd_soc_read(codec, reg) >> shift) & mask;
val2 = (snd_soc_read(codec, reg2) >> shift) & mask;
if (!strcmp(kcontrol->id.name, "DAC Playback Volume")) {
ucontrol->value.integer.value[0] =
(val <= 48) ? (val + 127) : (val - 129);
ucontrol->value.integer.value[1] =
(val2 <= 48) ? (val2 + 127) : (val2 - 129);
}else if (!strcmp(kcontrol->id.name, "HP Driver Gain")){
ucontrol->value.integer.value[0] = val;
ucontrol->value.integer.value[1] = val2;
} else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
ucontrol->value.integer.value[0] =
((val*2) <= 40) ? ((val*2 + 24)/2) : ((val*2 - 254)/2);
ucontrol->value.integer.value[1] =
((val2*2) <= 40) ? ((val2*2 + 24)/2) : ((val2*2 - 254)/2);
}
return 0;
}
/*
*----------------------------------------------------------------------------
* Function : snd_soc_put_volsw_2r_dac3100
* Purpose : Callback to set the value of a double mixer control that spans
* two registers.
*
*----------------------------------------------------------------------------
*/
int snd_soc_put_volsw_2r_dac3100(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
int err;
unsigned short val, val2, val_mask;
PRINTK("snd_soc_put_volsw_2r_dac3100 (%s)\n", kcontrol->id.name);
val = (ucontrol->value.integer.value[0] << shift);
val2 = (ucontrol->value.integer.value[1] << shift);
PRINTK("\nval= 0x%x val2 =0x%x\n",val,val2);
if (!strcmp(kcontrol->id.name, "DAC Playback Volume")) {
val = (val >= 127) ? (val - 127):(val+129);
val2 = (val2 >= 127) ? (val2 - 127) : (val2 + 129);
val_mask = dac3100_8BITS_MASK; /* 8 bits */
} else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) {
val_mask = (0xF << shift); /* 4 bits */
} else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
val = (val*2 >= 24) ? ((val*2 - 24)/2) : ((val*2 + 254)/2);
val2 = (val2*2 >= 24) ? ((val2*2 - 24)/2) : ((val2*2 + 254)/2);
val_mask = 0x7F; /* 7 bits */
} else {
printk(KERN_ALERT "Invalid control name\n");
return -1;
}
PRINTK("VAL=%x MASK=%x\n",val,val_mask);
if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) {
printk(KERN_ALERT "Error while updating bits\n");
return err;
}
err = snd_soc_update_bits(codec, reg2, val_mask, val2);
return err;
}
struct dac31_priv {
unsigned int sysclk;
void *control_data;
};
static const int dac31_reg_enable[] = {
RESET,
AIS_REG_3,
CLK_REG_1,
CLK_REG_2,
NDAC_CLK_REG_6,
MDAC_CLK_REG_7,
DAC_OSR_MSB,
DAC_OSR_LSB,
INTERFACE_SET_REG_1,
DAC_INSTRUCTION_SET,
DAC31_COERAM,
DAC_MIXER_ROUTING,
SPL_DRIVER,
LEFT_ANALOG_SPL,
CLASS_D_SPK,
LDAC_VOL,
RDAC_VOL,
DAC_MUTE_CTRL_REG,
DAC_CHN_REG,
DAC31_REG_END,
};
static const u8 dac31_reg[DAC31_CACHEREGNUM] = {
0x00,0x01,0x01,0x66, /* 0 */
0x00,0x00,0x04,0x00, /* 4 */
0x00,0x00,0x00,0x81, /* 8 */
0x82,0x00,0x80,0x80, /* 12 */
0x08,0x00,0x01,0x01, /* 16 */
0x80,0x80,0x04,0x00, /* 20 */
0x00,0x00,0x01,0x00, /* 24 */
0x00,0x09,0x01,0x00, /* 28 */
0x00,0x00,0x00,0x00, /* 32 */
0x80,0x00,0x00,0x00, /* 36 */
0x00,0x00,0x00,0x00, /* 40 */
0x00,0x00,0x00,0x00, /* 44 */
0x00,0x00,0x00,0x02, /* 48 */
0x32,0x12,0x03,0x02, /* 52 */
0x02,0x11,0x10,0x00, /* 56 */
0x17,0x04,0x00,0x14, /* 60 */
0x00,0xd8,0xd8,0x00, /* 64 */
0x6f,0x38,0x00,0x00, /* 68 */
0x00,0x00,0x00,0xee, /* 72 */
0x10,0xd8,0x7e,0xe3, /* 76 */
0x00,0x00,0x80,0x00, /* 80 */
0x00,0x00,0x00,0x00, /* 84 */
0x7f,0x00,0x00,0x00, /* 88 */
0x00,0x00,0x00,0x00, /* 92 */
0x00,0x00,0x00,0x00, /* 96 */
0x00,0x00,0x00,0x00, /* 100 */
0x00,0x00,0x00,0x00, /* 104 */
0x00,0x00,0x00,0x00, /* 108 */
0x00,0x00,0x00,0x00, /* 112 */
0x00,0x00,0x00,0x00, /* 116 */
0x00,0x00,0x00,0x00, /* 120 */
0x00,0x00,0x00,0x00, /* 124 - PAGE0 Registers(127) ends here */
0x01,0x00,0x00,0x00, /* 128, PAGE1-0 */
0x00,0x00,0x00,0x00, /* 132, PAGE1-4 */
0x00,0x00,0x00,0x00, /* 136, PAGE1-8 */
0x00,0x00,0x00,0x00, /* 140, PAGE1-12 */
0x00,0x00,0x00,0x00, /* 144, PAGE1-16 */
0x00,0x00,0x00,0x00, /* 148, PAGE1-20 */
0x00,0x00,0x00,0x00, /* 152, PAGE1-24 */
0x00,0x00,0x00,0x04, /* 156, PAGE1-28 */
0x06,0x3e,0x00,0x44, /* 160, PAGE1-32 */
0x7f,0x7f,0x92,0x7f, /* 164, PAGE1-36 */
0x02,0x02,0x1c,0x00, /* 168, PAGE1-40 */
0x20,0x86,0x00,0x80, /* 172, PAGE1-44 */
0x00, 0x00, 0x00, /* 176, PAGE1-48 */
/* page 3-16 , 179 need Individual treatment*/
0x00,
/* page 8-1 ,180 need Individual treatment */
0x04,
};
#define PAGE3_REG16 179
#define PAGE8_REG1 180
static inline unsigned int dac31_read_reg_cache(struct snd_soc_codec *codec,unsigned int reg)
{
u8 *cache = codec->reg_cache;
unsigned int ret;
if (TIMER_MCLK_DIV == reg){
ret = cache[PAGE3_REG16];
}else if (DAC31_COERAM == reg){
ret = cache[PAGE8_REG1];
}else if (reg >= DAC31_CACHEREGNUM){
ret = 0;
}else{
ret = cache[reg];
}
return ret;
}
static int dac31_change_reg_page(struct snd_soc_codec *codec, u8 page_no)
{
struct i2c_client *client = codec->control_data;
int count = 3;
if (i2c_smbus_read_byte_data(client, PAGE_SELECT) == page_no){
PRINTK("already in page %d\n",page_no);
return 0;
}
while (count > 0) {
i2c_smbus_write_byte_data(client, PAGE_SELECT, page_no); /* switch register page, Page0 */
if (i2c_smbus_read_byte_data(client, PAGE_SELECT) == page_no) {
break;
} else {
printk(KERN_ALERT " DAC: try to select page %d but failed ,try again \n",page_no);
}
count --;
}
if (count == 0) {
printk(KERN_ALERT "DAC : failed to change dac31 reg page to %d \n",page_no);
return -1;
} else {
return 0;
}
}
static int dac31_write(struct snd_soc_codec *codec, unsigned int reg,unsigned int value)
{
u8 *cache = codec->reg_cache;
struct i2c_client *client = codec->control_data;
u8 page;
u8 rreg;
page = reg / 128;
rreg = reg % 128;
PRINTK("PAGE =%x\n",page);
if (dac31_change_reg_page(codec,page) ){
printk(KERN_ALERT "ERROR IN dac31_write\n");
return -EIO;
}
PRINTK("WRITE %d =0x%x\n",rreg,value);
if (i2c_smbus_write_byte_data(client, rreg, value)) {
pr_err("DAC31: I2C write failed\n");
return -EIO;
}
if (reg < DAC31_CACHEREGNUM){
cache[reg] = value;
}else if (TIMER_MCLK_DIV == reg){
cache[PAGE3_REG16] = value;
}else if (DAC31_COERAM == reg){
cache[PAGE8_REG1] = value;
}
return value;
}
#if 0
static inline unsigned int dac31_read(struct snd_soc_codec *codec, unsigned int reg)
{
u8 *cache = codec->reg_cache;
u8 page;
u8 rreg;
u8 value;
//PRINTK("************in dac31_read\n");
page = reg / 128;
rreg = reg % 128;
if (dac31_change_reg_page(codec,page)){
PRINTK("=======================ERROR IN dac31_read\n");
return -EIO;
}
value = rreg & 0xff;
value = i2c_smbus_read_byte_data(codec->control_data, value);
if (reg < DAC31_CACHEREGNUM){
cache[reg] = value;
}else if (TIMER_MCLK_DIV == reg){
cache[PAGE3_REG16] = value;
}else if (DAC31_COERAM == reg){
cache[PAGE8_REG1] = value;
}
//PRINTK("reg_%d : %x\n",reg,value);
return value;
}
#endif
static int dac31_sync(struct snd_soc_codec *codec)
{
u8 *cache = codec->reg_cache;
int i,r = 0;
for (i=0; dac31_reg_enable[i] != -1;i++ ) {
PRINTK("IN SYNC i=%d\n",i);
if (TIMER_MCLK_DIV == dac31_reg_enable[i]) {
r |= snd_soc_write(codec,TIMER_MCLK_DIV,cache[PAGE3_REG16]);
}else if (DAC31_COERAM == dac31_reg_enable[i]){
r |= snd_soc_write(codec,DAC31_COERAM,cache[PAGE8_REG1]);
}else{
r |= snd_soc_write(codec,dac31_reg_enable[i],cache[dac31_reg_enable[i]]);
}
}
return r;
}
static int dac31_get_pllenable(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = PLL_ENABLE;
return 0;
}
static int dac31_SET_pllenable(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
PLL_ENABLE = ucontrol->value.integer.value[0];
if (PLL_ENABLE){
snd_soc_write(codec,CLK_REG_1,0x03);//PLL generic on chip
snd_soc_write(codec,CLK_REG_3,0x01); // PLL j VALUE
snd_soc_write(codec,CLK_REG_4,0x00); // PLL D VALUE
snd_soc_write(codec,CLK_REG_5,0x00); //PLL D VALUE
snd_soc_write(codec,CLK_REG_2,0x91); // PLL PR VALUE,AND POWER UP
snd_soc_write(codec,NDAC_CLK_REG_6,0x81); // ndac value
snd_soc_write(codec,MDAC_CLK_REG_7,0x82); // mdac value
snd_soc_write(codec,DAC_OSR_MSB,0x00); // dosr value
snd_soc_write(codec,DAC_OSR_LSB,0x80); //dosr value
}else{
snd_soc_write(codec,CLK_REG_1,0X00);//DISABLE PLL, USED MCLK
snd_soc_write(codec,CLK_REG_2,0x00); // PLL POWER DOWN
snd_soc_write(codec,NDAC_CLK_REG_6,0x81); // NDAC POWER up
snd_soc_write(codec,MDAC_CLK_REG_7,0x82); // mdac value
snd_soc_write(codec,DAC_OSR_MSB,0x00); // dosr value
snd_soc_write(codec,DAC_OSR_LSB,0x80); //dosr value
}
return 0;
}
/******************** ALSA Controls and Widgets *********************************************/
static DECLARE_TLV_DB_SCALE(output_tlv,-6350,50,0);
static DECLARE_TLV_DB_SCALE(hp_tlv,0,100,0);
static DECLARE_TLV_DB_SCALE(volume_tlv,-7830,50,0);
static DECLARE_TLV_DB_SCALE(micvo_tlv,-6300,50,0);
static const char *dac31_lo_gain[] = {"+6db", "+12db","+18db","+24db"};
static const char *dac_mute_control[] = {"UNMUTE" , "MUTE"};
static const char *hpdriver_voltage_control[] = {"1.35V", "1.5V", "1.65V", "1.8V"};
static const char *drc_status_control[] = {"DISABLED", "ENABLED"};
static const char *pll_enable[]={"DISABLE","ENABLE"};
static const char *process_block[]={"RESERVED","PRB_P1","PRB_P2","PRB_P3","PRB_P4","PRB_P5","PRB_P6","PRB_P7",
"PRB_P8","PRB_P9","PRB_P10","PRB_P11","PRB_P12","PRB_P13","PRB_P14",
"PRB_P15","PRB_P16","PRB_P17","PRB_P18","PRB_P19","PRB_P20","PRB_P21",
"PRB_P22","PRB_P23","PRB_P24","PRB_P25"};
static const char *micvol_control[]={"CONTROL REGISTER","PIN"};
static const char *micbiasvoltage_control[]={"POWER DOWN","2V","2.5V","AVDD"};
static const char *datapath_control[]={"Both Channel Off","Left-channel=left data Right-channel=right data",
"Left-channel=right data Right-channel=left data",
"Left-channel=Right-channel=(L+R)/2 data"};
static const struct soc_enum dac31_enum[] = {
SOC_ENUM_SINGLE(SPL_DRIVER, 3, 4, dac31_lo_gain),
SOC_ENUM_SINGLE (DAC_MUTE_CTRL_REG, 3, 2, dac_mute_control),
SOC_ENUM_SINGLE (DAC_MUTE_CTRL_REG, 2, 2, dac_mute_control),
SOC_ENUM_SINGLE (HPHONE_DRIVERS, 3, 4, hpdriver_voltage_control),
SOC_ENUM_DOUBLE (DRC_CTRL_1, 6, 5, 2, drc_status_control),
SOC_ENUM_SINGLE_EXT(2,pll_enable),
SOC_ENUM_SINGLE(DAC_INSTRUCTION_SET,0,25,process_block),
SOC_ENUM_SINGLE(VOL_MICDECT_ADC,7,2,micvol_control),
SOC_ENUM_SINGLE(MICBIAS_CTRL,0,4,micbiasvoltage_control),
SOC_ENUM_DOUBLE(DAC_CHN_REG,4,2,4,datapath_control),
};
static const struct snd_kcontrol_new dac31_snd_controls[]={
SOC_DOUBLE_R_EXT_TLV("DAC Playback Volume",LDAC_VOL,RDAC_VOL,0,0xaf,0,\
snd_soc_get_volsw_2r_dac3100,snd_soc_put_volsw_2r_dac3100,output_tlv),
/* sound new kcontrol for HP driver gain */
SOC_DOUBLE_R_EXT_TLV("HP Driver Gain", HPL_DRIVER, HPR_DRIVER, 3, 9, 0,\
snd_soc_get_volsw_2r_dac3100,snd_soc_put_volsw_2r_dac3100,hp_tlv),
/* sound new kcontrol for LO driver gain */
SOC_ENUM("LO Driver Gain", dac31_enum[0]),
/* sound new kcontrol for HP mute */
SOC_DOUBLE_R("HP DAC Playback Switch", HPL_DRIVER, HPR_DRIVER, 2, 0x01, 0),
/* sound new kcontrol for LO mute */
SOC_SINGLE("LO DAC Playback Switch", SPL_DRIVER, 2, 0x01, 0),
/* sound new kcontrol for Analog Volume Control for headphone and Speaker Outputs
* Please refer to Table 5-24 of the Codec DataSheet
*/
SOC_DOUBLE_R_TLV("HP Analog Volume",LEFT_ANALOG_HPL,RIGHT_ANALOG_HPR, 0, 117, 1, volume_tlv),
SOC_SINGLE_TLV("SPKR Analog Volume", LEFT_ANALOG_SPL, 0, 117, 1,volume_tlv),
SOC_ENUM ("LEFT DAC MUTE", dac31_enum[1]),
SOC_ENUM ("RIGHT DAC MUTE", dac31_enum[2]),
SOC_ENUM ("HP Driver Voltage level", dac31_enum[3]),
SOC_ENUM ("DRC Status", dac31_enum[4]),
/* Dynamic Range Compression Control */
SOC_SINGLE ("DRC Hysteresis Value (0=0db 3=db)", DRC_CTRL_1, 0, 0x03, 0),
SOC_SINGLE ("DRC Threshold Value (0=-3db,7=-24db)", DRC_CTRL_1, 2, 0x07, 0),
SOC_SINGLE ("DRC Hold Time", DRC_CTRL_2, 3, 0x0F, 0),
SOC_SINGLE ("DRC Attack Time", DRC_CTRL_3, 4, 0x0F, 0),
SOC_SINGLE ("DRC Delay Rate", DRC_CTRL_3, 0, 0x0F, 0),
/* PLL control */
SOC_ENUM_EXT("PLL Enable Switch", dac31_enum[5], dac31_get_pllenable,dac31_SET_pllenable),
/*Processing Blocks*/
SOC_ENUM("Processing Blocks Switch",dac31_enum[6]),
/* input volume control */
SOC_SINGLE_EXT_TLV("Pin Volume Control Value(Read Only)",VOL_MICDECT_GAIN,0,0x7e,0,\
snd_soc_get_volsw_dac3100,snd_soc_put_volsw_dac3100,micvo_tlv),
SOC_ENUM("Volume Control Pin Switch",dac31_enum[7]),
/* headphone */
SOC_ENUM("Micbias Voltage Switch",dac31_enum[8]),
/*Channel Path */
SOC_ENUM("Data Path Switch",dac31_enum[9]),
};
/*
* DAPM Mixer Controls
*/
/* Left DAC_L Mixer */
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
SOC_DAPM_SINGLE("L_DAC switch", DAC_MIXER_ROUTING, 6, 2, 0),
SOC_DAPM_SINGLE("MIC1_L switch", DAC_MIXER_ROUTING, 5, 1, 0),
};
/* Right DAC_R Mixer */
static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
SOC_DAPM_SINGLE("R_DAC switch", DAC_MIXER_ROUTING, 2, 2, 0),
SOC_DAPM_SINGLE("MIC1_R switch", DAC_MIXER_ROUTING, 1, 1, 0),
};
static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
SOC_DAPM_SINGLE("L_DAC switch", DAC_MIXER_ROUTING, 6, 2, 0),
SOC_DAPM_SINGLE("MIC1_L switch", DAC_MIXER_ROUTING, 5, 1, 0),
};
static const struct snd_soc_dapm_widget dac31_dapm_widgets[] = {
/* Left DAC to Left Outputs */
/* dapm widget (stream domain) for left DAC */
SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_CHN_REG, 7, 0),
/* dapm widget (path domain) for left DAC_L Mixer */
SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
&hpl_output_mixer_controls[0],
ARRAY_SIZE(hpl_output_mixer_controls)),
SND_SOC_DAPM_PGA("HPL Power", HPHONE_DRIVERS, 7, 0, NULL, 0),
SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
&lol_output_mixer_controls[0],
ARRAY_SIZE(lol_output_mixer_controls)),
SND_SOC_DAPM_PGA("LOL Power", CLASS_D_SPK, 7, 0, NULL, 0),
/* Right DAC to Right Outputs */
/* dapm widget (stream domain) for right DAC */
SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_CHN_REG, 6, 0),
/* dapm widget (path domain) for right DAC_R mixer */
SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
&hpr_output_mixer_controls[0],
ARRAY_SIZE(hpr_output_mixer_controls)),
SND_SOC_DAPM_PGA("HPR Power", HPHONE_DRIVERS, 6, 0, NULL, 0),
/* dapm widget (platform domain) name for HPLOUT */
SND_SOC_DAPM_OUTPUT("HPL"),
/* dapm widget (platform domain) name for HPROUT */
SND_SOC_DAPM_OUTPUT("HPR"),
/* dapm widget (platform domain) name for LOLOUT */
SND_SOC_DAPM_OUTPUT("LOL"),
/* dapm widget (platform domain) name for MIC1LP */
SND_SOC_DAPM_INPUT("MIC1LP"),
/* dapm widget (platform domain) name for MIC1RP*/
SND_SOC_DAPM_INPUT("MIC1RP"),
/* dapm widget (platform domain) name for MIC1LM */
SND_SOC_DAPM_INPUT("MIC1LM"),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* ******** Right Output ******** */
{"HPR Output Mixer", "R_DAC switch", "Right DAC"},
{"HPR Output Mixer", "MIC1_R switch", "MIC1RP"},
{"HPR Power", NULL, "HPR Output Mixer"},
{"HPR", NULL, "HPR Power"},
/* ******** Left Output ******** */
{"HPL Output Mixer", "L_DAC switch", "Left DAC"},
{"HPL Output Mixer", "MIC1_L switch", "MIC1LP"},
{"HPL Power", NULL, "HPL Output Mixer"},
{"HPL", NULL, "HPL Power"},
{"LOL Output Mixer", "L_DAC switch", "Left DAC"},
{"LOL Output Mixer", "MIC1_L switch", "MIC1LP"},
{"LOL Power", NULL, "LOL Output Mixer"},
{"LOL", NULL, "LOL Power"},
};
static int dac31_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm,dac31_dapm_widgets,
ARRAY_SIZE(dac31_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map,ARRAY_SIZE(audio_map));
return 0;
}
static int dac31_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
{
u8 value;
if (level ==codec->dapm.bias_level)
return 0;
switch (level) {
/* full On */
case SND_SOC_BIAS_ON:
PRINTK("===========SND_SOC_BIAS_ON=============\n");
/* Switch on NDAC Divider */
value = snd_soc_read(codec, NDAC_CLK_REG_6);
snd_soc_write(codec, NDAC_CLK_REG_6, value | ENABLE_NDAC);
/* Switch on MDAC Divider */
value = snd_soc_read(codec, MDAC_CLK_REG_7);
snd_soc_write(codec, MDAC_CLK_REG_7,
value | ENABLE_MDAC);
/* Switch on BCLK_N Divider */
value = snd_soc_read(codec, CLK_REG_11);
snd_soc_write(codec, CLK_REG_11, value | ENABLE_BCLK);
/* Switch ON Left and Right DACs */
value = snd_soc_read (codec, DAC_CHN_REG);
snd_soc_write (codec, DAC_CHN_REG, (value | ENABLE_DAC));
snd_soc_write(codec,DAC_MUTE_CTRL_REG,0x00);//unmute DAC left and right channels
/* Switch ON the Class_D Speaker Amplifier */
value = snd_soc_read (codec, CLASS_D_SPK);
snd_soc_write (codec, CLASS_D_SPK, (value | 0x80));
/* UNMUTE THE Class-D Speaker Driver */
value = snd_soc_read (codec, SPL_DRIVER);
snd_soc_write (codec, SPL_DRIVER, (value | 0x04));
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
PRINTK("===========SND_SOC_BIAS_STANDBY=============\n");
/* MUTE THE Class-D Speaker Driver */
value = snd_soc_read (codec, SPL_DRIVER);
value &= ~0x04;
snd_soc_write (codec, SPL_DRIVER, value);
/* Switch OFF the Class_D Speaker Amplifier */
value = snd_soc_read (codec, CLASS_D_SPK);
snd_soc_write (codec, CLASS_D_SPK, (value & ~0x80));
/* Switch OFF Left and Right DACs */
value = snd_soc_read (codec, DAC_CHN_REG);
snd_soc_write (codec, DAC_CHN_REG, (value & ~ENABLE_DAC));
/* Switch off NDAC Divider */
value = snd_soc_read(codec, NDAC_CLK_REG_6);
snd_soc_write(codec, NDAC_CLK_REG_6,
value & ~ENABLE_NDAC);
/* Switch off MDAC Divider */
value = snd_soc_read(codec, MDAC_CLK_REG_7);
snd_soc_write(codec, MDAC_CLK_REG_7,
value & ~ENABLE_MDAC);
/* Switch off BCLK_N Divider */
snd_soc_write(codec, CLK_REG_11, value & ~ENABLE_BCLK);
break;
case SND_SOC_BIAS_OFF:
PRINTK("===========SND_SOC_BIAS_OFF=============\n");
/* MUTE THE Class-D Speaker Driver */
value = snd_soc_read (codec, SPL_DRIVER);
value &= ~0x04;
snd_soc_write (codec, SPL_DRIVER, value);
/* Switch OFF the Class_D Speaker Amplifier */
value = snd_soc_read (codec, CLASS_D_SPK);
snd_soc_write (codec, CLASS_D_SPK, (value & ~0x80));
/* Switch OFF Left and Right DACs */
value = snd_soc_read (codec, DAC_CHN_REG);
snd_soc_write (codec, DAC_CHN_REG, (value & ~ENABLE_DAC));
/* Switch off NDAC Divider */
value = snd_soc_read(codec, NDAC_CLK_REG_6);
snd_soc_write(codec, NDAC_CLK_REG_6,
value & ~ENABLE_NDAC);
/* Switch off MDAC Divider */
value = snd_soc_read(codec, MDAC_CLK_REG_7);
snd_soc_write(codec, MDAC_CLK_REG_7,
value & ~ENABLE_MDAC);
/* Switch off BCLK_N Divider */
snd_soc_write(codec, CLK_REG_11, value & ~ENABLE_BCLK);
break;
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
/* the sturcture contains the different values for mclk */
static const struct dac3100_rate_divs dac3100_divs[] = {
/*
* mclk, rate, p_val, pll_j, pll_d, dosr, ndac, mdac, aosr, nadc, madc, blck_N,
* codec_speficic_initializations
*/
/* 8k rate */
// DDenchev (MMS)
{ 4096000, 8000,1, 1, 0, 512, 1, 1,16,
{{DAC_INSTRUCTION_SET, 7}, {61, 1}}},
{12000000, 8000, 1, 7, 1680, 128, 2, 42, 4,
{{DAC_INSTRUCTION_SET, 7}, {61, 1}}},
{13000000, 8000, 1, 6, 3803, 128, 3, 27, 4,
{{DAC_INSTRUCTION_SET, 7}, {61, 4}}},
{24000000, 8000, 2, 7, 6800, 768, 15, 1, 24,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/* 11.025k rate */
// DDenchev (MMS)
{5644800, 11025, 1, 1, 0, 256, 1, 2, 8,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{12000000, 11025, 1, 7, 560, 128, 5, 12, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 11025, 1, 6, 1876, 128, 3, 19, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
{24000000, 11025, 2, 7, 5264, 512, 16, 1, 16,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/* 12k rate */
// DDenchev (MMS)
{12000000, 12000, 1, 7, 1680, 128, 2, 28, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 12000, 1, 6, 3803, 128, 3, 18, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
/* 16k rate */
// DDenchev (MMS)
{ 4096000, 16000, 1, 1, 0, 256, 1, 1, 8,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{12000000, 16000, 1, 7, 1680, 128, 2, 21, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 16000, 1, 6, 6166, 128, 3, 14, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
{24000000, 16000, 2, 7, 6800, 384, 15, 1, 12,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/* 22.05k rate */
// DDenchev (MMS)
{ 5644800, 22050, 1, 1, 0, 128, 1, 2, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{12000000, 22050, 1, 7, 560, 128, 5, 6, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 22050, 1, 6, 5132, 128, 3, 10, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
{24000000, 22050, 2, 7, 5264, 256, 16, 1, 8,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/* 24k rate */
// DDenchev (MMS)
{ 6144000, 24000, 1, 1, 0, 128, 1, 2, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{12000000, 24000, 1, 7, 1680, 128, 2, 14, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 24000, 1, 6, 3803, 128, 3, 9, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
/* 32k rate */
// DDenchev (MMS)
{ 8192000, 32000, 1, 1, 0, 128, 1, 2, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{12000000, 32000, 1, 6, 1440, 128, 2, 9, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 32000, 1, 6, 6166, 128, 3, 7, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
{24000000, 32000, 2, 7, 1680, 192, 7, 2, 6,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/* 44.1k rate */
// DDenchev (MMS)
{11289600, 44100, 1, 1, 0, 128, 1, 2, 4,
{{DAC_INSTRUCTION_SET, 7}, {61, 1}}},
{12000000, 44100, 1, 7, 560, 128, 5, 3, 4,
{{DAC_INSTRUCTION_SET, 7}, {61, 1}}},
{13000000, 44100, 1, 6, 5132, 128, 3, 5, 4,
{{DAC_INSTRUCTION_SET, 7}, {61, 4}}},
{24000000, 44100, 2, 7, 5264, 128, 8, 2, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/* 48k rate */
// DDenchev (MMS)
{12288000, 48000, 1, 1, 0, 64, 1, 4, 2,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{12000000, 48000, 1, 7, 1680, 128, 2, 7, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
{13000000, 48000, 1, 6, 6166, 128, 7, 2, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 4}}},
{24000000, 48000, 2, 8, 1920, 128, 8, 2, 4,
{{DAC_INSTRUCTION_SET, 1}, {61, 1}}},
/*96k rate : GT 21/12/2009: NOT MODIFIED */
{12000000, 96000, 1, 8, 1920, 64, 2, 8, 2,
{{DAC_INSTRUCTION_SET, 7}, {61, 7}}},
{13000000, 96000, 1, 6, 6166, 64, 7, 2, 2,
{{DAC_INSTRUCTION_SET, 7}, {61, 10}}},
{24000000, 96000, 2, 8, 1920, 64, 4, 4, 2,
{{DAC_INSTRUCTION_SET, 7}, {61, 7}}},
/*192k : GT 21/12/2009: NOT MODIFIED */
{12000000, 192000, 1, 8, 1920, 32, 2, 8, 1,
{{DAC_INSTRUCTION_SET, 17}, {61, 13}}},
{13000000, 192000, 1, 6, 6166, 32, 7, 2, 1,
{{DAC_INSTRUCTION_SET, 17}, {61, 13}}},
{24000000, 192000, 2, 8, 1920, 32, 4, 4, 1,
{{DAC_INSTRUCTION_SET, 17}, {61, 13}}},
};
/*
*----------------------------------------------------------------------------
* Function : dac3100_get_divs
* Purpose : This function is to get required divisor from the "dac3100_divs"
* table.
*
*----------------------------------------------------------------------------
*/
static inline int dac31_get_divs(int mclk, int rate)
{
int i;
PRINTK("+ dac3100_get_divs mclk(%d) rate(%d)\n", mclk, rate);
for (i = 0; i < ARRAY_SIZE(dac3100_divs); i++) {
if ((dac3100_divs[i].rate == rate) && (dac3100_divs[i].mclk == mclk)) {
PRINTK("%d %d %d %d %d %d %d\n",
dac3100_divs[i].p_val,
dac3100_divs[i].pll_j,
dac3100_divs[i].pll_d,
dac3100_divs[i].dosr,
dac3100_divs[i].ndac,
dac3100_divs[i].mdac,
dac3100_divs[i].blck_N);
return i;
}
}
printk(KERN_ALERT "Master clock and sample rate is not supported\n");
return -EINVAL;
}
static int dac31_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 dac31_priv *dac31 = snd_soc_codec_get_drvdata(codec);
dac31->sysclk = freq;
return 0;
}
#if debug_dac
void debug_hw_params(struct snd_soc_codec *codec)
{
PRINTK("CLK_REG_2=%x\n",snd_soc_read(codec, CLK_REG_2));
PRINTK("CLK_REG_3=%x\n",snd_soc_read(codec, CLK_REG_3));
PRINTK("CLK_REG_4=%x\n",snd_soc_read(codec, CLK_REG_4));
PRINTK("CLK_REG_5=%x\n",snd_soc_read(codec, CLK_REG_5));
PRINTK("NDAC_CLK_REG_6=%x\n",snd_soc_read(codec, NDAC_CLK_REG_6 ));
PRINTK("MDAC_CLK_REG_7=%x\n",snd_soc_read(codec, MDAC_CLK_REG_7));
PRINTK("DAC_OSR_MSB=%x\n",snd_soc_read(codec, DAC_OSR_MSB));
PRINTK("DAC_OSR_LSB=%x\n",snd_soc_read(codec, DAC_OSR_LSB));
PRINTK("CLK_REG_11=%x\n",snd_soc_read(codec, CLK_REG_11));
PRINTK("INTERFACE_SET_REG_1=%x\n",snd_soc_read(codec, INTERFACE_SET_REG_1));
return;
}
#endif
static int dac31_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec =rtd->codec;
struct dac31_priv *dac31 = snd_soc_codec_get_drvdata(codec);
int i;
u8 data;
dac31_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
i = dac31_get_divs(dac31->sysclk, params_rate(params));
PRINTK("- Sampling rate: %d, %d\n", params_rate(params), i);
if (i < 0) {
printk(KERN_ALERT "sampling rate not supported\n");
return i;
}
if (PLL_ENABLE){
/* We will fix R value to 1 and will make P & J=K.D as varialble */
/* Setting P & R values */
snd_soc_write(codec, CLK_REG_2, ((dac3100_divs[i].p_val << 4) | 0x81));//cddiao fix PLL to power up
/* J value */
snd_soc_write(codec, CLK_REG_3, dac3100_divs[i].pll_j);
/* MSB & LSB for D value */
snd_soc_write(codec, CLK_REG_4, (dac3100_divs[i].pll_d >> 8));
snd_soc_write(codec, CLK_REG_5, (dac3100_divs[i].pll_d & dac3100_8BITS_MASK));
}
/* NDAC divider value */
snd_soc_write(codec, NDAC_CLK_REG_6,( dac3100_divs[i].ndac) | 0x80);// cddiao fix NDAC to power up
/* MDAC divider value */
snd_soc_write(codec, MDAC_CLK_REG_7, (dac3100_divs[i].mdac) |0x80);// cddiao fix MDAC to power up
/* DOSR MSB & LSB values */
snd_soc_write(codec, DAC_OSR_MSB, dac3100_divs[i].dosr >> 8);
snd_soc_write(codec, DAC_OSR_LSB, dac3100_divs[i].dosr & dac3100_8BITS_MASK);
/* BCLK N divider */
snd_soc_write(codec, CLK_REG_11, (dac3100_divs[i].blck_N) | 0x80); // slave mode, no need to
data = snd_soc_read(codec, INTERFACE_SET_REG_1);
data = data & ~(3 << 4);
PRINTK( "- Data length: %d\n", params_format(params));
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
case SNDRV_PCM_FORMAT_S20_3LE:
data |= (dac3100_WORD_LEN_20BITS << DAC_OSR_MSB_SHIFT);
break;
case SNDRV_PCM_FORMAT_S24_LE:
data |= (dac3100_WORD_LEN_24BITS << DAC_OSR_MSB_SHIFT);
break;
case SNDRV_PCM_FORMAT_S32_LE:
data |= (dac3100_WORD_LEN_32BITS << DAC_OSR_MSB_SHIFT);
break;
}
/* Write to Page 0 Reg 27 for the Codec Interface control 1 Register */
snd_soc_write(codec, INTERFACE_SET_REG_1, data);
/* Switch on the Codec into ON State after all the above configuration */
dac31_set_bias_level(codec, SND_SOC_BIAS_ON);
/* The below block is not required since these are RESERVED REGISTERS
* in the DAc3100 Codec Chipset
* for (j = 0; j < NO_FEATURE_REGS; j++) {
* snd_soc_write(codec,
* dac3100_divs[i].codec_specific_regs[j].reg_offset,
* dac3100_divs[i].codec_specific_regs[j].reg_val);
*}
*/
PRINTK("- SET dac3100_hw_params\n");
#if debug_dac
debug_hw_params(codec);
#endif
return 0;
}
static int dac31_set_dai_fmt(struct snd_soc_dai *codec_dai,unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
u8 iface_reg;
iface_reg = snd_soc_read(codec, INTERFACE_SET_REG_1);
iface_reg = iface_reg & ~(3 << 6 | 3 << 2);
PRINTK("+ dac3100_set_dai_fmt (%x) \n", fmt);
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
break;
case SND_SOC_DAIFMT_DSP_A:
iface_reg |= (dac3100_DSP_MODE << CLK_REG_3_SHIFT);
break;
case SND_SOC_DAIFMT_RIGHT_J:
iface_reg |= (dac3100_RIGHT_JUSTIFIED_MODE << CLK_REG_3_SHIFT);
break;
case SND_SOC_DAIFMT_LEFT_J:
iface_reg |= (dac3100_LEFT_JUSTIFIED_MODE << CLK_REG_3_SHIFT);
break;
default:
printk(KERN_ALERT "Invalid DAI interface format\n");
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
iface_reg |= 0x0c;
PRINTK("=======SLAVE MODE ========\n");
break;
default:
return -EINVAL;
}
PRINTK("- dac3100_set_dai_fmt (%x) \n", iface_reg);
snd_soc_write(codec, INTERFACE_SET_REG_1, iface_reg);
return 0;
}
static int dac31_mute(struct snd_soc_dai *dai, int mute)
{
return 0;
}
#define DAC31_RATES SNDRV_PCM_RATE_8000_48000
#define DAC31_FORMATS SNDRV_PCM_FMTBIT_S16_LE
static struct snd_soc_dai_ops dac31_dai_ops = {
.set_fmt = dac31_set_dai_fmt,
.hw_params = dac31_hw_params,
.digital_mute = dac31_mute,
.set_sysclk = dac31_set_dai_sysclk,
};
struct snd_soc_dai_driver dac31_dai = {
.name = "tlv320dac31",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = DAC31_RATES,
.formats = DAC31_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = DAC31_RATES,
.formats = DAC31_FORMATS,},
.ops = &dac31_dai_ops,
};
static int dac31_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
PRINTK("IN SUSPEND\n");
dac31_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int dac31_resume(struct snd_soc_codec *codec)
{
PRINTK("in resume\n");
dac31_sync(codec);
dac31_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static int dac31_probe(struct snd_soc_codec *codec)
{
struct dac31_priv *dac31 = snd_soc_codec_get_drvdata(codec);
struct dac31_platform_data *dac31_pdata;
int ret;
PRINTK("IN THE DAC31_PROBE\n");
dev_info(codec->dev, "DAC31 Audio Codec %s", DAC31_VERSION);
codec->control_data = dac31->control_data;
dac31_pdata = codec->dev->platform_data;
if (!dac31_pdata)
return -EINVAL;
if (gpio_is_valid(dac31_pdata->rst_pin)) {
ret = gpio_request(dac31_pdata->rst_pin,"TLVDAC31RESETGPIO");
if (ret < 0)
return ret;
} else {
return -ENODEV;
}
gpio_direction_output(dac31_pdata->rst_pin,GPIO_LOW);
msleep(dac31_pdata->rst_delay);
gpio_direction_output(dac31_pdata->rst_pin,GPIO_HIGH);
/* power on device */
dac31_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_write(codec,RESET,0x01); // reset the chip
snd_soc_write(codec,AIS_REG_3,0x01); // BDIV_CLKIN confied to DAC_MOD_CLK and BCLK not inverted
if (PLL_ENABLE){
snd_soc_write(codec,CLK_REG_1,0x03);//PLL generic on chip
snd_soc_write(codec,CLK_REG_3,0x01); // PLL j VALUE
snd_soc_write(codec,CLK_REG_4,0x00); // PLL D VALUE
snd_soc_write(codec,CLK_REG_5,0x00); //PLL D VALUE
snd_soc_write(codec,CLK_REG_2,0x91); // PLL PR VALUE,AND POWER UP
snd_soc_write(codec,NDAC_CLK_REG_6,0x81); // ndac value
snd_soc_write(codec,MDAC_CLK_REG_7,0x82); // mdac value
snd_soc_write(codec,DAC_OSR_MSB,0x00); // dosr value
snd_soc_write(codec,DAC_OSR_LSB,0x80); //dosr value
}else{
snd_soc_write(codec,CLK_REG_1,0x00);//DISABLE PLL, USED MCLK
snd_soc_write(codec,CLK_REG_2,0x00); // PLL POWER DOWN
snd_soc_write(codec,NDAC_CLK_REG_6,0x81); // NDAC POWER up
snd_soc_write(codec,MDAC_CLK_REG_7,0x82); // mdac value
snd_soc_write(codec,DAC_OSR_MSB,0x00); // dosr value
snd_soc_write(codec,DAC_OSR_LSB,0x80); //dosr value
}
#if HAEDPHONE_JACK
snd_soc_write(codec,GPIO1_CTRL,0x14);// set gpio1 to interrupt 1 output
snd_soc_write(codec,INT1_CTRL,0x80);// set INT1 to headphone detector
#endif
snd_soc_write(codec,INTERFACE_SET_REG_1,0x00);//i2s 16bit
snd_soc_write(codec,DAC_INSTRUCTION_SET,0x17);// PRB_P23
snd_soc_write(codec,DAC31_COERAM,0x04);// enable adaptive filtering
//PLAYBACK PATH SETTING
snd_soc_write(codec,DAC_MIXER_ROUTING,0x44);// dac route to the mixer
//CLASS-D SPEAKER DRIVER
snd_soc_write(codec,SPL_DRIVER,0x01c);//class-d 24db
snd_soc_write(codec,LEFT_ANALOG_SPL,0x92);//class-d volume -6db
snd_soc_write(codec,CLASS_D_SPK,0x86);//power up class-d,
//power up dac
snd_soc_write(codec,LDAC_VOL,0xd8);//dac left -22db
snd_soc_write(codec,RDAC_VOL,0xd8);//dac right -22db
snd_soc_write(codec,DAC_MUTE_CTRL_REG,0x00);//unmute DAC left and right channels
snd_soc_write(codec,DAC_CHN_REG,0xd4);//power up dac and data path
snd_soc_add_controls(codec, dac31_snd_controls,ARRAY_SIZE(dac31_snd_controls));
dac31_add_widgets(codec);
return 0;
}
static int dac31_remove(struct snd_soc_codec *codec)
{
struct dac31_platform_data *dac31_pdata;
dac31_set_bias_level(codec, SND_SOC_BIAS_OFF);
dac31_pdata = codec->dev->platform_data;
gpio_free(dac31_pdata->rst_pin);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_dac31 = {
.probe = dac31_probe,
.remove = dac31_remove,
.suspend = dac31_suspend,
.resume = dac31_resume,
.read = dac31_read_reg_cache,
.write = dac31_write,
.set_bias_level = dac31_set_bias_level,
.reg_cache_size = ARRAY_SIZE(dac31_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = dac31_reg,
.reg_cache_step = 1,
};
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
static int dac31_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
struct dac31_priv *dac31;
int ret;
PRINTK("IN I2C PROBE\n");
dac31 = kzalloc(sizeof(struct dac31_priv), GFP_KERNEL);
if (dac31 == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c,dac31);
dac31->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_dac31,
&dac31_dai, 1);
if (ret < 0)
kfree(dac31);
PRINTK("ret = %d\n",ret);
return ret;
}
static int dac31_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
kfree(i2c_get_clientdata(i2c));
return 0;
}
static int dac31_i2c_resume(struct i2c_client *i2c)
{
struct dac31_platform_data *dac31_pdata;
dac31_pdata = i2c->dev.platform_data;
if (!dac31_pdata)
return -EINVAL;
PRINTK("IN DAC31_I2C_RESUME\n");
gpio_direction_output(dac31_pdata->rst_pin,GPIO_LOW);
msleep(dac31_pdata->rst_delay);
gpio_direction_output(dac31_pdata->rst_pin,GPIO_HIGH);
msleep(dac31_pdata->rst_delay);
return 0;
}
static const struct i2c_device_id dac31_i2c_id[] = {
{ "tlv320dac31", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, dac31_i2c_id);
static struct i2c_driver dac31_i2c_driver = {
.driver = {
.name = "tlv320dac31-codec",
.owner = THIS_MODULE,
},
.probe = dac31_i2c_probe,
.remove = dac31_i2c_remove,
.id_table = dac31_i2c_id,
.resume = dac31_i2c_resume,
};
#endif
static int __init dac31_modinit(void)
{
int ret;
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
PRINTK("init dac31 modinit\n");
ret = i2c_add_driver(&dac31_i2c_driver);
if (ret != 0)
pr_err("Failed to register DAC31 I2C driver: %d\n", ret);
#endif
return ret;
}
module_init(dac31_modinit);
static void __exit dac31_exit(void)
{
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
i2c_del_driver(&dac31_i2c_driver);
#endif
}
module_exit(dac31_exit);
MODULE_DESCRIPTION("Soc DAC31 Driver");
MODULE_AUTHOR("Johnson Diao (cddiao@ambarella.com)");
MODULE_LICENSE("GPL");