blob: 8c1dc1902157c7c61b55152f369a638e46e6fb03 [file] [log] [blame]
/*
* ak7755.c -- audio driver for AK7755
*
* Copyright (C) 2014 Asahi Kasei Microdevices Corporation
* Author Date Revision
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 14/04/22 1.0
* 15/06/15 1.1
* 16/01/13 2.01 kernel 3.10.94
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/spi/spi.h>
#include <linux/of_gpio.h> // '16/01/13
#include <linux/mutex.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include <sound/ak7755_pdata.h> // '15/06/15
#include "ak7755.h"
#include "ak7755_dsp_code.h"
#include <linux/types.h>
//#define AK7755_PD_SUSPEND // '15/06/15
//#define AK7755_DEBUG //used at debug mode
#define AK7755_CONTIF_DEBUG //used at debug mode
#ifdef AK7755_DEBUG
#define akdbgprt printk
#else
#define akdbgprt(format, arg...) do {} while (0)
#endif
static int fast_boot = 0;
module_param(fast_boot, uint, 0664);
static int aec = 1;
module_param(aec, uint, 0664);
static int RAM_FLAG = 1;
/* AK7755 Codec Private Data */
struct ak7755_priv {
enum snd_soc_control_type control_type;
struct snd_soc_codec *codec;
struct spi_device *spi;
struct i2c_client *i2c;
int fs;
int rclk; //Master Clock
int lign; //LIGN3-0(LineIn Volume)
int selmix; //SELMIX2-0
int status;
int MIRNo;
int bickfs; // '15/06/15 0:64fs, 1:48fs, 2:32fs, 3:256fs
int pdn_gpio; // '15/06/15
unsigned int pdn_active;
int power_gpio;
unsigned int power_active;
int amp_gpio;
unsigned int amp_active;
unsigned int fmt;
u16 DSPPramMode;
u16 DSPCramMode;
u16 DSPOfregMode;
u16 DSPAcramMode;
int EQLevel[5];
int HPFfc[2];
int LimRel;
int LimVol;
};
struct _ak7755_pd_handler {
int ref_count;
struct mutex lock;
struct ak7755_priv *data;
} ak7755_pd_handler = {
.ref_count = -1,
.data = NULL,
};
static struct ak7755_priv *ak7755_data;
/* ak7755 register cache & default register settings */
static u8 ak7755_reg[AK7755_MAX_REGISTERS];
static const u8 ak7755_reg2[] = {
0x00, /* 0xC0 AK7755_C0_CLOCK_SETTING1 */
0x00, /* 0xC1 AK7755_C1_CLOCK_SETTING2 */
0x00, /* 0xC2 AK7755_C2_SERIAL_DATA_FORMAT */
0x00, /* 0xC3 AK7755_C3_DELAY_RAM_DSP_IO */
0x00, /* 0xC4 AK7755_C4_DATARAM_CRAM_SETTING */
0x00, /* 0xC5 AK7755_C5_ACCELARETOR_SETTING */
0x00, /* 0xC6 AK7755_C6_DAC_DEM_SETTING */
0x00, /* 0xC7 AK7755_C7_DSP_OUT_SETTING */
0x00, /* 0xC8 AK7755_C8_DAC_IN_SETTING */
0x00, /* 0xC9 AK7755_C9_ANALOG_IO_SETTING */
0x00, /* 0xCA AK7755_CA_CLK_SDOUT_SETTING */
0x00, /* 0xCB AK7755_CB_TEST_SETTING */
0x00, /* 0xCC AK7755_CC_VOLUME_TRANSITION */
0x80, /* 0xCD AK7755_CD_STO_DLS_SETTING */
0x00, /* 0xCE AK7755_CE_POWER_MANAGEMENT */
0x00, /* 0xCF AK7755_CF_RESET_POWER_SETTING */
0x00, /* 0xD0 AK7755_D0_FUNCTION_SETTING */
0x00, /* 0xD1 AK7755_D1_DSPMCLK_SETTING */
0x00, /* 0xD2 AK7755_D2_MIC_GAIN_SETTING */
0x00, /* 0xD3 AK7755_D3_LIN_LO3_VOLUME_SETTING */
0x00, /* 0xD4 AK7755_D4_LO1_LO2_VOLUME_SETTING */
0x30, /* 0xD5 AK7755_D5_ADC_DVOLUME_SETTING1 */
0x30, /* 0xD6 AK7755_D6_ADC_DVOLUME_SETTING2 */
0x30, /* 0xD7 AK7755_D7_ADC2_DVOLUME_SETTING1 */
0x18, /* 0xD8 AK7755_D8_DAC_DVOLUME_SETTING1 */
0x18, /* 0xD9 AK7755_D9_DAC_DVOLUME_SETTING2 */
0x00, /* 0xDA AK7755_DA_MUTE_ADRC_ZEROCROSS_SET */
0x00, /* 0xDB AK7755_DB_ADRC_MIC_GAIN_READ */
0x00, /* 0xDC AK7755_DC_TEST_SETTING */
0x30, /* 0xDD AK7755_DD_ADC2_DVOLUME_SETTING2 */
0x00, /* 0xDE AK7755_DE_DMIC_IF_SETTING */
};
static struct {
int readable; /* Mask of readable bits */
int writable; /* Mask of writable bits */
} ak7755_access_masks[AK7755_MAX_REGISTERS];
static const struct {
int readable; /* Mask of readable bits */
int writable; /* Mask of writable bits */
} ak7755_access_masks2[] = {
{ 0xFF, 0x7F }, //0xC0
{ 0xFF, 0xFF }, //0xC1
{ 0xFF, 0xFF }, //0xC2
{ 0xFF, 0xFF }, //0xC3
{ 0xFF, 0xFB }, //0xC4
{ 0xFF, 0xFF }, //0xC5
{ 0xFF, 0xF7 }, //0xC6
{ 0xFF, 0xF7 }, //0xC7
{ 0xFF, 0xFF }, //0xC8
{ 0xFF, 0xFF }, //0xC9
{ 0xFF, 0xE7 }, //0xCA
{ 0xFF, 0x00 }, //0xCB
{ 0xFF, 0xB7 }, //0xCC
{ 0xFF, 0x81 }, //0xCD
{ 0xFF, 0xFF }, //0xCE
{ 0xFF, 0x37 }, //0xCF
{ 0xFF, 0xF9 }, //0xD0
{ 0xFF, 0xFF }, //0xD1
{ 0xFF, 0xFF }, //0xD2
{ 0xFF, 0xFF }, //0xD3
{ 0xFF, 0xFF }, //0xD4
{ 0xFF, 0xFF }, //0xD5
{ 0xFF, 0xFF }, //0xD6
{ 0xFF, 0xFF }, //0xD7
{ 0xFF, 0xFF }, //0xD8
{ 0xFF, 0xFF }, //0xD9
{ 0xFF, 0xFF }, //0xDA
{ 0xFF, 0x00 }, //0xDB
{ 0xFF, 0x00 }, //0xDC
{ 0xFF, 0xFF }, //0xDD
{ 0xFF, 0xFC }, //0xDE
};
/* MIC Input Volume control:
* from 0 to 36 dB (quantity of each step is various) */
static DECLARE_TLV_DB_MINMAX(mgnl_tlv, 0, 3600);
static DECLARE_TLV_DB_MINMAX(mgnr_tlv, 0, 3600);
/* Line-out Volume control:
* from -30 to 0 dB in 2 dB steps (mute instead of -30 dB) */
static DECLARE_TLV_DB_SCALE(lovol1_tlv, -3000, 200, 0);
static DECLARE_TLV_DB_SCALE(lovol2_tlv, -3000, 200, 0);
static DECLARE_TLV_DB_SCALE(lovol3_tlv, -3000, 200, 0);
static const char *line_in_texts[] =
{
"-21dB","-18dB","-15dB","-12dB","-9dB","-6dB","-3dB",
"0dB","+3dB","+6dB","+9dB","+12dB","+15dB","+18dB","+21dB",
};
static const struct soc_enum ak7755_linein_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(line_in_texts), line_in_texts),
};
/* ADC, ADC2 Digital Volume control:
* from -103.5 to 24 dB in 0.5 dB steps (mute instead of -103.5 dB) */
static DECLARE_TLV_DB_SCALE(voladl_tlv, -10350, 50, 0);
static DECLARE_TLV_DB_SCALE(voladr_tlv, -10350, 50, 0);
static DECLARE_TLV_DB_SCALE(volad2l_tlv, -10350, 50, 0);
static DECLARE_TLV_DB_SCALE(volad2r_tlv, -10350, 50, 0);
/* DAC Digital Volume control:
* from -115.5 to 12 dB in 0.5 dB steps (mute instead of -115.5 dB) */
static DECLARE_TLV_DB_SCALE(voldal_tlv, -11550, 50, 0);
static DECLARE_TLV_DB_SCALE(voldar_tlv, -11550, 50, 0);
static const char *ak7755_bank_select_texts[] =
{"0:8192", "1024:7168","2048:6144","3072:5120","4096:4096",
"5120:3072","6144:2048","7168:1024","8192:0"};
static const char *ak7755_drms_select_texts[] =
{"512:1536", "1024:1024", "1536:512"};
static const char *ak7755_dram_select_texts[] =
{"Ring:Ring", "Ring:Linear", "Linear:Ring", "Linear:Linear"};
static const char *ak7755_pomode_select_texts[] = {"DBUS Immediate", "OFREG"};
static const char *ak7755_wavp_select_texts[] =
{"33 word", "65 word", "129 word", "257 word"};
static const char *ak7755_filmode1_select_texts[] = {"Adaptive Filter", "FIR Filter"};
static const char *ak7755_filmode2_select_texts[] = {"Adaptive Filter", "FIR Filter"};
static const char *ak7755_submode1_select_texts[] = {"Fullband", "Subband"};
static const char *ak7755_submode2_select_texts[] = {"Fullband", "Subband"};
static const char *ak7755_memdiv_select_texts[] =
{"2048:-", "1792:256", "1536:512", "1024:1024"};
static const char *ak7755_dem_select_texts[] = {"Off", "48kHz", "44.1kHz", "32kHz"};
static const char *ak7755_clkoe_select_texts[] = {"CLKO=L", "CLKO Out Enable"};
static const char *ak7755_clks_select_texts[] =
{"12.288MHz", "6.144MHz", "3.072MHz", "8.192MHz",
"4.096MHz", "2.048MHz", "256fs", "XTI or BICK"};
static const struct soc_enum ak7755_set_enum[] = {
SOC_ENUM_SINGLE(AK7755_C3_DELAY_RAM_DSP_IO, 0,
ARRAY_SIZE(ak7755_bank_select_texts), ak7755_bank_select_texts),
SOC_ENUM_SINGLE(AK7755_C4_DATARAM_CRAM_SETTING, 6,
ARRAY_SIZE(ak7755_drms_select_texts), ak7755_drms_select_texts),
SOC_ENUM_SINGLE(AK7755_C4_DATARAM_CRAM_SETTING, 4,
ARRAY_SIZE(ak7755_dram_select_texts), ak7755_dram_select_texts),
SOC_ENUM_SINGLE(AK7755_C4_DATARAM_CRAM_SETTING, 3,
ARRAY_SIZE(ak7755_pomode_select_texts), ak7755_pomode_select_texts),
SOC_ENUM_SINGLE(AK7755_C4_DATARAM_CRAM_SETTING, 0,
ARRAY_SIZE(ak7755_wavp_select_texts), ak7755_wavp_select_texts),
SOC_ENUM_SINGLE(AK7755_C5_ACCELARETOR_SETTING, 5,
ARRAY_SIZE(ak7755_filmode1_select_texts), ak7755_filmode1_select_texts),
SOC_ENUM_SINGLE(AK7755_C5_ACCELARETOR_SETTING, 4,
ARRAY_SIZE(ak7755_filmode2_select_texts), ak7755_filmode2_select_texts),
SOC_ENUM_SINGLE(AK7755_C5_ACCELARETOR_SETTING, 3,
ARRAY_SIZE(ak7755_submode1_select_texts), ak7755_submode1_select_texts),
SOC_ENUM_SINGLE(AK7755_C5_ACCELARETOR_SETTING, 2,
ARRAY_SIZE(ak7755_submode2_select_texts), ak7755_submode2_select_texts),
SOC_ENUM_SINGLE(AK7755_C5_ACCELARETOR_SETTING, 0,
ARRAY_SIZE(ak7755_memdiv_select_texts), ak7755_memdiv_select_texts),
SOC_ENUM_SINGLE(AK7755_C6_DAC_DEM_SETTING, 6,
ARRAY_SIZE(ak7755_dem_select_texts), ak7755_dem_select_texts),
SOC_ENUM_SINGLE(AK7755_CA_CLK_SDOUT_SETTING, 7,
ARRAY_SIZE(ak7755_clkoe_select_texts), ak7755_clkoe_select_texts),
SOC_ENUM_SINGLE(AK7755_C1_CLOCK_SETTING2, 1,
ARRAY_SIZE(ak7755_clks_select_texts), ak7755_clks_select_texts),
};
// '15/06/15
static const char *ak7755_bick_select_texts[] =
{"64fs", "48fs", "32fs", "TDM" };
static const struct soc_enum ak7755_bick_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_bick_select_texts), ak7755_bick_select_texts)
};
static int get_bickfs(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = ak7755->bickfs;
return 0;
}
static int set_bickfs(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ak7755->bickfs = ucontrol->value.enumerated.item[0];
return 0;
}
// '15/06/15
static const char *selmix_set_texts[] =
{
"SDOUTAD", "ADL_AD2L/ADR", "ADL/ADR_AD2R", "SDOUTAD2",
"DSPL/AD2R", "AD2L/DSPR", "DSPL/ADR", "ADL/DSPR",
};
static const struct soc_enum ak7755_selmix_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(selmix_set_texts), selmix_set_texts),
};
// Added for AK7755
static const struct soc_enum ak7755_firmware_enum[] =
{
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_firmware_pram), ak7755_firmware_pram),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_firmware_cram), ak7755_firmware_cram),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_firmware_ofreg), ak7755_firmware_ofreg),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_firmware_acram), ak7755_firmware_acram),
};
static inline u32 ak7755_read_reg_cache(struct snd_soc_codec *, u16);
static int ak7755_firmware_write_ram(u16 mode, u16 cmd);
static int ak7755_set_status(enum ak7755_status status);
static int ak7755_write_cram(int addr, int len, unsigned char *cram_data);
static int get_linein(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = ak7755->lign;
return 0;
}
static int set_linein(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ak7755->lign = ucontrol->value.enumerated.item[0];
if ( ak7755->lign <= 7) {
snd_soc_update_bits(codec, AK7755_D3_LIN_LO3_VOLUME_SETTING, 0xF0, ((7 - ak7755->lign) << 4) );
}
else {
snd_soc_update_bits(codec, AK7755_D3_LIN_LO3_VOLUME_SETTING, 0xF0, ((ak7755->lign + 1) << 4) );
}
return 0;
}
static int get_selmix(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = ak7755->selmix;
return 0;
}
static int set_selmix(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ak7755->selmix = ucontrol->value.enumerated.item[0];
if ( ak7755->selmix < 4) { //SELMIX2=0, SELMIX1-0=selmix
snd_soc_update_bits(codec, AK7755_C9_ANALOG_IO_SETTING, 0x01, 0x00);
snd_soc_update_bits(codec, AK7755_C8_DAC_IN_SETTING, 0x03, ak7755->selmix);
}
else { //SELMIX2=1, SELMIX1-0=(selmix & 0x03)
snd_soc_update_bits(codec, AK7755_C9_ANALOG_IO_SETTING, 0x01, 0x01);
snd_soc_update_bits(codec, AK7755_C8_DAC_IN_SETTING, 0x03, (ak7755->selmix & 0x03));
}
return 0;
}
static int get_DSP_write_pram(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->DSPPramMode;
return 0;
}
static int set_DSP_write_pram(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
/*
if ( currMode == ak7755_data->DSPPramMode ) {
akdbgprt("\t%s Same PRAM mode =%d\n",__FUNCTION__, currMode);
return(0);
}
*/
if (RAM_FLAG ==1 ){
akdbgprt("\t%s PRAM mode =%d\n",__FUNCTION__, currMode);
ret = ak7755_firmware_write_ram(RAMTYPE_PRAM, currMode);
if ( ret != 0 ) return(-1);
ak7755_data->DSPPramMode = currMode;
}
return(0);
}
static int get_DSP_write_cram(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->DSPCramMode;
return 0;
}
static int set_DSP_write_cram(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
/*
if ( currMode == ak7755_data->DSPCramMode ) {
akdbgprt("\t%s Same CRAM mode =%d\n",__FUNCTION__, currMode);
return(0);
}
*/
if (RAM_FLAG ==1){
RAM_FLAG = 0 ;
akdbgprt("\t%s CRAM mode =%d\n",__FUNCTION__, currMode);
ret = ak7755_firmware_write_ram(RAMTYPE_CRAM, currMode);
if ( ret != 0 ) return(-1);
ak7755_data->DSPCramMode =currMode;
}
return(0);
}
static int get_DSP_write_ofreg(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->DSPOfregMode;
return 0;
}
static int set_DSP_write_ofreg(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
/*
if ( currMode == ak7755_data->DSPOfregMode ) {
akdbgprt("\t%s Same CRAM mode =%d\n",__FUNCTION__, currMode);
return(0);
}
akdbgprt("\t%s OFREG mode =%d\n",__FUNCTION__, currMode);
*/
ret = ak7755_firmware_write_ram(RAMTYPE_OFREG, currMode);
if ( ret != 0 ) return(-1);
ak7755_data->DSPOfregMode =currMode;
return(0);
}
static int get_DSP_write_acram(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->DSPAcramMode;
return 0;
}
static int set_DSP_write_acram(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
/*
if ( currMode == ak7755_data->DSPAcramMode ) {
akdbgprt("\t%s Same CRAM mode =%d\n",__FUNCTION__, currMode);
return(0);
}
*/
akdbgprt("\t%s ACRAM mode =%d\n",__FUNCTION__, currMode);
ret = ak7755_firmware_write_ram(RAMTYPE_ACRAM, currMode);
if ( ret != 0 ) return(-1);
ak7755_data->DSPAcramMode =currMode;
return(0);
}
#if 0
#ifdef AK7755_CRAM_BASIC_COTROL
static const struct soc_enum ak7755_cram_write_enum[] =
{
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_cram_EQ_Level), ak7755_cram_EQ_Level),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_cram_HPF_fc), ak7755_cram_HPF_fc),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_cram_Lim_Rel), ak7755_cram_Lim_Rel),
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak7755_cram_Lim_Vol), ak7755_cram_Lim_Vol),
};
static int ak7755_cram_write_eq_level(
int addr,
int level)
{
u8 bCram[3];
int n;
int ret;
n = 0;
bCram[n++] = (0xFF & (dwEQLevel[level] >> 16));
bCram[n++] = (0xFF & (dwEQLevel[level] >> 8));
bCram[n++] = (0xFF & (dwEQLevel[level]));
ret = ak7755_write_cram(addr, 3, bCram);
ret = ak7755_write_cram(addr+6, 3, bCram);
return(ret);
}
static int get_cram_write_eq1(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->EQLevel[0];
return 0;
}
static int set_cram_write_eq1(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_cram_write_eq_level(AK7755_CRAMADDR_EQ1_LEVEL, (int)currMode);
if ( ret < 0 ) return(-1);
ak7755_data->EQLevel[0] =currMode;
return(0);
}
static int get_cram_write_eq2(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->EQLevel[1];
return 0;
}
static int set_cram_write_eq2(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_cram_write_eq_level(AK7755_CRAMADDR_EQ2_LEVEL, (int)currMode);
if ( ret < 0 ) return(-1);
ak7755_data->EQLevel[1] =currMode;
return(0);
}
static int get_cram_write_eq3(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->EQLevel[2];
return 0;
}
static int set_cram_write_eq3(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_cram_write_eq_level(AK7755_CRAMADDR_EQ3_LEVEL, (int)currMode);
if ( ret < 0 ) return(-1);
ak7755_data->EQLevel[2] =currMode;
return(0);
}
static int get_cram_write_eq4(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->EQLevel[3];
return 0;
}
static int set_cram_write_eq4(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_cram_write_eq_level(AK7755_CRAMADDR_EQ4_LEVEL, (int)currMode);
if ( ret < 0 ) return(-1);
ak7755_data->EQLevel[3] =currMode;
return(0);
}
static int get_cram_write_eq5(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->EQLevel[4];
return 0;
}
static int set_cram_write_eq5(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_cram_write_eq_level(AK7755_CRAMADDR_EQ5_LEVEL, (int)currMode);
if ( ret < 0 ) return(-1);
ak7755_data->EQLevel[4] =currMode;
return(0);
}
static int get_cram_write_hpf1fc(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->HPFfc[0];
return 0;
}
static int set_cram_write_hpf1fc(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_write_cram(AK7755_CRAMADDR_HPF1, 15, HPFCoefTab[currMode]);
if ( ret < 0 ) return(-1);
ak7755_data->HPFfc[0] =currMode;
return(0);
}
static int get_cram_write_hpf2fc(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->HPFfc[1];
return 0;
}
static int set_cram_write_hpf2fc(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_write_cram(AK7755_CRAMADDR_HPF2, 15, HPFCoefTab[currMode]);
if ( ret < 0 ) return(-1);
ak7755_data->HPFfc[1] =currMode;
return(0);
}
static int get_cram_write_limrel(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->LimRel;
return 0;
}
static int set_cram_write_limrel(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
ret = ak7755_write_cram(AK7755_CRAMADDR_LIM_REL, 6, LIMRelTab[currMode]);
if ( ret < 0 ) return(-1);
ak7755_data->LimRel =currMode;
return(0);
}
static int get_cram_write_limvol(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = ak7755_data->LimVol;
return 0;
}
static int set_cram_write_limvol(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u32 currMode = ucontrol->value.enumerated.item[0];
int ret;
int limlevel, nVolLim;
u8 bMixVolLIM[3];
u8 bMixVolHPF[3];
bMixVolHPF[1] = 0;
bMixVolHPF[2] = 0;
bMixVolLIM[1] = 0;
bMixVolLIM[2] = 0;
if ( currMode == 0 ) {
limlevel = 0;
bMixVolLIM[0] = 0;
bMixVolHPF[0] = 0x08;
}
else {
limlevel = currMode - 1;
bMixVolHPF[0] = 0;
nVolLim = (0x08 << currMode);
bMixVolLIM[0] = (0xFF & nVolLim);
}
ret = ak7755_write_cram(AK7755_CRAMADDR_LIM_LEVEL, 3, LIMLevelTab[limlevel]);
if ( ret < 0 ) return(-1);
ret = ak7755_write_cram(AK7755_CRAMADDR_MIX_LIM_L, 3, bMixVolLIM);
if ( ret < 0 ) return(-1);
ret = ak7755_write_cram(AK7755_CRAMADDR_MIX_HPF_L, 3, bMixVolHPF);
if ( ret < 0 ) return(-1);
ret = ak7755_write_cram(AK7755_CRAMADDR_MIX_LIM_R, 3, bMixVolLIM);
if ( ret < 0 ) return(-1);
ret = ak7755_write_cram(AK7755_CRAMADDR_MIX_HPF_R, 3, bMixVolHPF);
if ( ret < 0 ) return(-1);
ak7755_data->LimVol =currMode;
return(0);
}
#endif
#endif
#if 1
static int ak7755_reads(u8 *, size_t, u8 *, size_t);
static int test_read_ram(int mode)
{
u8 tx[3], rx[512];
int i, n, plen, clen;
akdbgprt("*****[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
snd_soc_update_bits(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, 0x1, 0x1); // DLRDY bit = 1
mdelay(1);
if ( mode == 1 ) {
plen = 10;
for ( n = 0 ; n < (5 * plen) ; n++ ) rx[n] = 0;
tx[0] = 0x38;
tx[1] = 0x0;
tx[2] = 0x0;
ak7755_reads(tx, 3, rx, 5 * plen);
printk("*****%s PRAM LEN = %d *******\n", __func__, plen);
n = 0;
for ( i = 0 ; i < plen ; i ++ ) {
printk("PAddr=%x %x %x %x %x %x\n", i,(int)rx[n], (int)rx[n+1], (int)rx[n+2], (int)rx[n+3], (int)rx[n+4]);
n += 5;
}
}
else if ( mode < 5 ) {
clen = 80;
for ( n = 0 ; n < (3 * clen) ; n++ ) rx[n] = 0;
if ( mode == 2 ) tx[0] = 0x34;
else if ( mode == 3 ) {
tx[0] = 0x32;
clen = 16;
}
else tx[0] = 0x3B;
tx[1] = 0x0;
tx[2] = 0x0;
ak7755_reads(tx, 3, rx, 3 * clen);
printk("*****%s RAM CMD=%d, LEN = %d*******\n", __func__, (int)tx[0], clen);
n = 0;
for ( i = 0 ; i < clen ; i ++ ) {
printk("CAddr=%x %x %x %x\n", i,(int)rx[n], (int)rx[n+1], (int)rx[n+2]);
n += 3;
}
}
mdelay(1);
snd_soc_update_bits(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, 0x1, 0x0); // DLRDY bit = 0
return(0);
}
static const char *test_reg_select[] =
{
"read AK7755 Reg 00:24",
"read PRAM",
"read CRAM",
"read OFREG",
"read ACRAM",
};
static const struct soc_enum ak7755_enum[] =
{
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(test_reg_select), test_reg_select),
};
static int nTestRegNo = 0;
static int get_test_reg(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
/* Get the current output routing */
ucontrol->value.enumerated.item[0] = nTestRegNo;
return 0;
}
static int set_test_reg(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
u32 currMode = ucontrol->value.enumerated.item[0];
int i, value;
int regs, rege;
nTestRegNo = currMode;
if ( currMode == 0 ) {
regs = 0xC0;
rege = 0xDE;
for ( i = regs ; i <= rege ; i++ ){
value = snd_soc_read(codec, i);
printk("***AK7755 Addr,Reg=(%x, %x)\n", i, value);
}
}
else if ( currMode < 5 ) {
test_read_ram(currMode);
}
return 0;
}
#endif
static const struct snd_kcontrol_new ak7755_snd_controls[] = {
SOC_SINGLE_TLV("MIC Input Volume L",
AK7755_D2_MIC_GAIN_SETTING, 0, 0x0F, 0, mgnl_tlv),
SOC_SINGLE_TLV("MIC Input Volume R",
AK7755_D2_MIC_GAIN_SETTING, 4, 0x0F, 0, mgnr_tlv),
SOC_SINGLE_TLV("Line Out Volume 1",
AK7755_D4_LO1_LO2_VOLUME_SETTING, 0, 0x0F, 0, lovol1_tlv),
SOC_SINGLE_TLV("Line Out Volume 2",
AK7755_D4_LO1_LO2_VOLUME_SETTING, 4, 0x0F, 0, lovol2_tlv),
SOC_SINGLE_TLV("Line Out Volume 3",
AK7755_D3_LIN_LO3_VOLUME_SETTING, 0, 0x0F, 0, lovol3_tlv),
SOC_ENUM_EXT("Line Input Volume", ak7755_linein_enum[0], get_linein, set_linein),
SOC_SINGLE_TLV("ADC Digital Volume L",
AK7755_D5_ADC_DVOLUME_SETTING1, 0, 0xFF, 1, voladl_tlv),
SOC_SINGLE_TLV("ADC Digital Volume R",
AK7755_D6_ADC_DVOLUME_SETTING2, 0, 0xFF, 1, voladr_tlv),
SOC_SINGLE_TLV("ADC2 Digital Volume L",
AK7755_D7_ADC2_DVOLUME_SETTING1, 0, 0xFF, 1, volad2l_tlv),
SOC_SINGLE_TLV("ADC2 Digital Volume R",
AK7755_DD_ADC2_DVOLUME_SETTING2, 0, 0xFF, 1, volad2r_tlv),
SOC_SINGLE_TLV("DAC Digital Volume L",
AK7755_D8_DAC_DVOLUME_SETTING1, 0, 0xFF, 1, voldal_tlv),
SOC_SINGLE_TLV("DAC Digital Volume R",
AK7755_D9_DAC_DVOLUME_SETTING2, 0, 0xFF, 1, voldar_tlv),
SOC_SINGLE("ADC Mute", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 7, 1, 0),
SOC_SINGLE("ADC2 Mute", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 6, 1, 0),
SOC_SINGLE("DAC Mute", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 5, 1, 0),
SOC_SINGLE("Analog DRC Lch", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 2, 1, 0),
SOC_SINGLE("Analog DRC Rch", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 3, 1, 0),
SOC_SINGLE("MICGAIN Lch Zero-cross", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 0, 1, 0),
SOC_SINGLE("MICGAIN Rch Zero-cross", AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 1, 1, 0),
SOC_ENUM("DAC De-emphasis", ak7755_set_enum[10]),
SOC_SINGLE("JX0 Enable", AK7755_C2_SERIAL_DATA_FORMAT, 0, 1, 0),
SOC_SINGLE("JX1 Enable", AK7755_C2_SERIAL_DATA_FORMAT, 1, 1, 0),
SOC_SINGLE("JX2 Enable", AK7755_C1_CLOCK_SETTING2, 7, 1, 0),
SOC_SINGLE("JX3 Enable", AK7755_C5_ACCELARETOR_SETTING, 6, 1, 0),
SOC_ENUM("DLRAM Mode(Bank1:Bank0)", ak7755_set_enum[0]),
SOC_ENUM("DRAM Size(Bank1:Bank0)", ak7755_set_enum[1]),
SOC_ENUM("DRAM Addressing Mode(Bank1:Bank0)", ak7755_set_enum[2]),
SOC_ENUM("POMODE DLRAM Pointer 0", ak7755_set_enum[3]),
SOC_ENUM("CRAM Memory Assignment", ak7755_set_enum[4]),
SOC_ENUM("FIRMODE1 Accelerator Ch1", ak7755_set_enum[5]),
SOC_ENUM("FIRMODE2 Accelerator Ch2", ak7755_set_enum[6]),
SOC_ENUM("SUBMODE1 Accelerator Ch1", ak7755_set_enum[7]),
SOC_ENUM("SUBMODE2 Accelerator Ch2", ak7755_set_enum[8]),
SOC_ENUM("Accelerator Memory(ch1:ch2)", ak7755_set_enum[9]),
SOC_ENUM("CLKO pin", ak7755_set_enum[11]),
SOC_ENUM("CLKO Output Clock", ak7755_set_enum[12]),
SOC_ENUM_EXT("BICK fs", ak7755_bick_enum[0], get_bickfs, set_bickfs), // '15/06/15
// Added for AK7755
SOC_ENUM_EXT("DSP Firmware PRAM", ak7755_firmware_enum[0], get_DSP_write_pram, set_DSP_write_pram),
SOC_ENUM_EXT("DSP Firmware CRAM", ak7755_firmware_enum[1], get_DSP_write_cram, set_DSP_write_cram),
SOC_ENUM_EXT("DSP Firmware OFREG", ak7755_firmware_enum[2], get_DSP_write_ofreg, set_DSP_write_ofreg),
SOC_ENUM_EXT("DSP Firmware ACRAM", ak7755_firmware_enum[3], get_DSP_write_acram, set_DSP_write_acram),
#if 0
#ifdef AK7755_CRAM_BASIC_COTROL
SOC_ENUM_EXT("CRAM EQ1 Level", ak7755_cram_write_enum[0], get_cram_write_eq1, set_cram_write_eq1),
SOC_ENUM_EXT("CRAM EQ2 Level", ak7755_cram_write_enum[0], get_cram_write_eq2, set_cram_write_eq2),
SOC_ENUM_EXT("CRAM EQ3 Level", ak7755_cram_write_enum[0], get_cram_write_eq3, set_cram_write_eq3),
SOC_ENUM_EXT("CRAM EQ4 Level", ak7755_cram_write_enum[0], get_cram_write_eq4, set_cram_write_eq4),
SOC_ENUM_EXT("CRAM EQ5 Level", ak7755_cram_write_enum[0], get_cram_write_eq5, set_cram_write_eq5),
SOC_ENUM_EXT("CRAM HPF1 fc", ak7755_cram_write_enum[1], get_cram_write_hpf1fc, set_cram_write_hpf1fc),
SOC_ENUM_EXT("CRAM HPF2 fc", ak7755_cram_write_enum[1], get_cram_write_hpf2fc, set_cram_write_hpf2fc),
SOC_ENUM_EXT("CRAM Limiter Release Time", ak7755_cram_write_enum[2], get_cram_write_limrel, set_cram_write_limrel),
SOC_ENUM_EXT("CRAM Limiter Volume", ak7755_cram_write_enum[3], get_cram_write_limvol, set_cram_write_limvol),
#endif
#endif
#if 1
SOC_ENUM_EXT("Reg Read", ak7755_enum[0], get_test_reg, set_test_reg),
#endif
SOC_ENUM_EXT("SELMIX2-0", ak7755_selmix_enum[0], get_selmix, set_selmix), //SELMIX2-0 bit setting
};
/* Clock Event for DAC, ADC */
static int ak7755_clkset_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
switch (event) {
case SND_SOC_DAPM_POST_PMU: /* after widget power up */
snd_soc_update_bits(codec, AK7755_CF_RESET_POWER_SETTING, 0x08,0x08); //CRESETN(CODEC ResetN)=1
break;
}
return 0;
}
/* Clock Event */
static int ak7755_clock_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) //CONFIG_LINF
{
struct snd_soc_codec *codec = w->codec;
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
switch (event) {
case SND_SOC_DAPM_POST_PMU: /* after widget power up */
akdbgprt("\t[AK7755] %s wait=10msec\n",__FUNCTION__);
mdelay(10);
break;
case SND_SOC_DAPM_PRE_PMD: /* before widget power down */
snd_soc_update_bits(codec, AK7755_CF_RESET_POWER_SETTING, 0x08,0x00); //CODEC Reset
break;
}
return 0;
}
/* SDOUT 1 switch */
static const struct snd_kcontrol_new ak7755_out1e_control =
SOC_DAPM_SINGLE("Switch", AK7755_CA_CLK_SDOUT_SETTING, 0, 1, 0);
/* SDOUT 2 switch */
static const struct snd_kcontrol_new ak7755_out2e_control =
SOC_DAPM_SINGLE("Switch", AK7755_CA_CLK_SDOUT_SETTING, 1, 1, 0);
/* SDOUT 3 switch */
static const struct snd_kcontrol_new ak7755_out3e_control =
SOC_DAPM_SINGLE("Switch", AK7755_CA_CLK_SDOUT_SETTING, 2, 1, 0);
/* LineOut1 Switch */
static const char *ak7755_pmlo1_select_texts[] =
{"Off", "On"};
static const struct soc_enum ak7755_pmlo1_mux_enum =
SOC_ENUM_SINGLE(AK7755_CE_POWER_MANAGEMENT, 2,
ARRAY_SIZE(ak7755_pmlo1_select_texts), ak7755_pmlo1_select_texts);
// SOC_ENUM_SINGLE(0, 0,
// ARRAY_SIZE(ak7755_pmlo1_select_texts), ak7755_pmlo1_select_texts);
static const struct snd_kcontrol_new ak7755_pmlo1_mux_control =
SOC_DAPM_ENUM("OUT1 SW", ak7755_pmlo1_mux_enum);
//SOC_DAPM_ENUM_VIRT("OUT1 SW", ak7755_pmlo1_mux_enum);
/* LineOut2 Switch */
static const char *ak7755_pmlo2_select_texts[] =
{"Off", "On"};
static const struct soc_enum ak7755_pmlo2_mux_enum =
SOC_ENUM_SINGLE(AK7755_CE_POWER_MANAGEMENT, 3,
ARRAY_SIZE(ak7755_pmlo2_select_texts), ak7755_pmlo2_select_texts);
// SOC_ENUM_SINGLE(0, 0,
// ARRAY_SIZE(ak7755_pmlo2_select_texts), ak7755_pmlo2_select_texts);
static const struct snd_kcontrol_new ak7755_pmlo2_mux_control =
SOC_DAPM_ENUM("OUT2 SW", ak7755_pmlo2_mux_enum);
// SOC_DAPM_ENUM_VIRT("OUT2 SW", ak7755_pmlo2_mux_enum);
/* LineOut3 Mixer */
static const struct snd_kcontrol_new ak7755_lo3sw_mixer_controls[] = {
SOC_DAPM_SINGLE("LOSW1", AK7755_C9_ANALOG_IO_SETTING, 1, 1, 0),
SOC_DAPM_SINGLE("LOSW2", AK7755_C9_ANALOG_IO_SETTING, 2, 1, 0),
#ifndef DIGITAL_MIC //LOSW3 used only Analog MIC
SOC_DAPM_SINGLE("LOSW3", AK7755_C9_ANALOG_IO_SETTING, 3, 1, 0),
#endif
};
/* DSPIn Virt SWITCH */
static const char *ak7755_dspinad_texts[] =
{"Off", "On"};
static const struct soc_enum ak7755_dspinad_enum =
SOC_ENUM_SINGLE(0, 0,
ARRAY_SIZE(ak7755_dspinad_texts), ak7755_dspinad_texts);
static const struct soc_enum ak7755_dspinad2_enum =
SOC_ENUM_SINGLE(0, 0,
ARRAY_SIZE(ak7755_dspinad_texts), ak7755_dspinad_texts);
static const struct snd_kcontrol_new ak7755_dspinad_control =
SOC_DAPM_ENUM_VIRT("DSPINAD Switch", ak7755_dspinad_enum);
static const struct snd_kcontrol_new ak7755_dspinad2_control =
SOC_DAPM_ENUM_VIRT("DSPINAD2 Switch", ak7755_dspinad2_enum);
/* LIN MUX */
static const char *ak7755_lin_select_texts[] =
{"IN1", "IN2", "INPN1"};
static const struct soc_enum ak7755_lin_mux_enum =
SOC_ENUM_SINGLE(AK7755_C9_ANALOG_IO_SETTING, 4,
ARRAY_SIZE(ak7755_lin_select_texts), ak7755_lin_select_texts);
static const struct snd_kcontrol_new ak7755_lin_mux_control =
SOC_DAPM_ENUM("LIN Select", ak7755_lin_mux_enum);
/* RIN MUX */
static const char *ak7755_rin_select_texts[] =
{"IN3", "IN4", "INPN2"};
static const struct soc_enum ak7755_rin_mux_enum =
SOC_ENUM_SINGLE(AK7755_C9_ANALOG_IO_SETTING, 6,
ARRAY_SIZE(ak7755_rin_select_texts), ak7755_rin_select_texts);
static const struct snd_kcontrol_new ak7755_rin_mux_control =
SOC_DAPM_ENUM("RIN Select", ak7755_rin_mux_enum);
/* DAC MUX */
static const char *ak7755_seldai_select_texts[] =
{"DSP", "MIXOUT", "SDIN2", "SDIN1"};
static const struct soc_enum ak7755_seldai_mux_enum =
SOC_ENUM_SINGLE(AK7755_C8_DAC_IN_SETTING, 6,
ARRAY_SIZE(ak7755_seldai_select_texts), ak7755_seldai_select_texts);
static const struct snd_kcontrol_new ak7755_seldai_mux_control =
SOC_DAPM_ENUM("SELDAI Select", ak7755_seldai_mux_enum);
/* SDOUT1 MUX */
static const char *ak7755_seldo1_select_texts[] =
{"DSP", "DSP GP0", "SDIN1", "SDOUTAD", "EEST", "SDOUTAD2"};
static const struct soc_enum ak7755_seldo1_mux_enum =
SOC_ENUM_SINGLE(AK7755_CC_VOLUME_TRANSITION, 0,
ARRAY_SIZE(ak7755_seldo1_select_texts), ak7755_seldo1_select_texts);
static const struct snd_kcontrol_new ak7755_seldo1_mux_control =
SOC_DAPM_ENUM("SELDO1 Select", ak7755_seldo1_mux_enum);
/* SDOUT2 MUX */
static const char *ak7755_seldo2_select_texts[] =
{"DSP", "DSP GP1", "SDIN2", "SDOUTAD2"};
static const struct soc_enum ak7755_seldo2_mux_enum =
SOC_ENUM_SINGLE(AK7755_C8_DAC_IN_SETTING, 2,
ARRAY_SIZE(ak7755_seldo2_select_texts), ak7755_seldo2_select_texts);
static const struct snd_kcontrol_new ak7755_seldo2_mux_control =
SOC_DAPM_ENUM("SELDO2 Select", ak7755_seldo2_mux_enum);
/* SDOUT3 MUX */
static const char *ak7755_seldo3_select_texts[] =
{"DSP DOUT3", "MIXOUT", "DSP DOUT4", "SDOUTAD2"};
static const struct soc_enum ak7755_seldo3_mux_enum =
SOC_ENUM_SINGLE(AK7755_C8_DAC_IN_SETTING, 4,
ARRAY_SIZE(ak7755_seldo3_select_texts), ak7755_seldo3_select_texts);
static const struct snd_kcontrol_new ak7755_seldo3_mux_control =
SOC_DAPM_ENUM("SELDO3 Select", ak7755_seldo3_mux_enum);
/* SELMIX Virt SWITCH */
static const char *ak7755_selmix_select_texts[] =
{"Off", "On"};
static const struct soc_enum ak7755_sdoutad_selmix_enum =
SOC_ENUM_SINGLE(0, 0,
ARRAY_SIZE(ak7755_selmix_select_texts), ak7755_selmix_select_texts);
static const struct soc_enum ak7755_sdoutad2_selmix_enum =
SOC_ENUM_SINGLE(0, 0,
ARRAY_SIZE(ak7755_selmix_select_texts), ak7755_selmix_select_texts);
static const struct soc_enum ak7755_dsp_selmix_enum =
SOC_ENUM_SINGLE(0, 0,
ARRAY_SIZE(ak7755_selmix_select_texts), ak7755_selmix_select_texts);
static const struct snd_kcontrol_new ak7755_sdoutad_selmix_control =
SOC_DAPM_ENUM_VIRT("SELMIX Switch", ak7755_sdoutad_selmix_enum);
static const struct snd_kcontrol_new ak7755_sdoutad2_selmix_control =
SOC_DAPM_ENUM_VIRT("SELMIX Switch", ak7755_sdoutad2_selmix_enum);
static const struct snd_kcontrol_new ak7755_dsp_selmix_control =
SOC_DAPM_ENUM_VIRT("SELMIX Switch", ak7755_dsp_selmix_enum);
/* ak7755 dapm widgets */
static const struct snd_soc_dapm_widget ak7755_dapm_widgets[] = {
// ADC, DAC
#ifdef DIGITAL_MIC
SND_SOC_DAPM_INPUT("DMICIN1"),
SND_SOC_DAPM_INPUT("DMICIN2"),
SND_SOC_DAPM_ADC_E("DMIC1 Left", "NULL", AK7755_CE_POWER_MANAGEMENT, 6, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_ADC_E("DMIC1 Right", "NULL", AK7755_CE_POWER_MANAGEMENT, 7, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_ADC_E("DMIC2 Left", "NULL", AK7755_CE_POWER_MANAGEMENT, 5, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_ADC_E("DMIC2 Right", "NULL", AK7755_CF_RESET_POWER_SETTING, 1, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_SUPPLY("DMIC1 CLK", AK7755_DE_DMIC_IF_SETTING, 5, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMIC2 CLK", AK7755_DE_DMIC_IF_SETTING, 2, 0, NULL, 0),
#else
SND_SOC_DAPM_ADC_E("ADC Left", "NULL", AK7755_CE_POWER_MANAGEMENT, 6, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_ADC_E("ADC Right", "NULL", AK7755_CE_POWER_MANAGEMENT, 7, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_ADC_E("ADC2 Left", "NULL", AK7755_CE_POWER_MANAGEMENT, 5, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
#endif
SND_SOC_DAPM_DAC_E("DAC Left", "NULL", AK7755_CE_POWER_MANAGEMENT, 0, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_DAC_E("DAC Right", "NULL", AK7755_CE_POWER_MANAGEMENT, 1, 0,
ak7755_clkset_event, SND_SOC_DAPM_POST_PMU ),
SND_SOC_DAPM_SUPPLY("CLOCK", AK7755_C1_CLOCK_SETTING2, 0, 0,
ak7755_clock_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
// Analog Output
SND_SOC_DAPM_OUTPUT("Line Out1"),
SND_SOC_DAPM_OUTPUT("Line Out2"),
SND_SOC_DAPM_OUTPUT("Line Out3"),
SND_SOC_DAPM_MIXER("LineOut Amp3 Mixer", AK7755_CE_POWER_MANAGEMENT, 4, 0,
&ak7755_lo3sw_mixer_controls[0], ARRAY_SIZE(ak7755_lo3sw_mixer_controls)),
// SND_SOC_DAPM_MUX("LineOut Amp2", AK7755_CE_POWER_MANAGEMENT, 3, 0, &ak7755_pmlo2_mux_control),
// SND_SOC_DAPM_MUX("LineOut Amp1", AK7755_CE_POWER_MANAGEMENT, 2, 0, &ak7755_pmlo1_mux_control),
SND_SOC_DAPM_MUX("LineOut Amp1", SND_SOC_NOPM, 0, 0, &ak7755_pmlo1_mux_control),
SND_SOC_DAPM_MUX("LineOut Amp2", SND_SOC_NOPM, 0, 0, &ak7755_pmlo2_mux_control),
// Analog Input
SND_SOC_DAPM_INPUT("LIN"),
SND_SOC_DAPM_INPUT("IN1"),
SND_SOC_DAPM_INPUT("IN2"),
SND_SOC_DAPM_INPUT("IN3"),
SND_SOC_DAPM_INPUT("IN4"),
SND_SOC_DAPM_INPUT("INPN1"),
SND_SOC_DAPM_INPUT("INPN2"),
SND_SOC_DAPM_PGA("LineIn Amp", AK7755_CF_RESET_POWER_SETTING, 5, 0, NULL, 0),
SND_SOC_DAPM_MUX("RIN MUX", SND_SOC_NOPM, 0, 0, &ak7755_rin_mux_control),
SND_SOC_DAPM_MUX("LIN MUX", SND_SOC_NOPM, 0, 0, &ak7755_lin_mux_control),
SND_SOC_DAPM_VIRT_MUX("DSPIN SDOUTAD2", SND_SOC_NOPM, 0, 0, &ak7755_dspinad2_control),
SND_SOC_DAPM_VIRT_MUX("DSPIN SDOUTAD", SND_SOC_NOPM, 0, 0, &ak7755_dspinad_control),
// Digital Input/Output
SND_SOC_DAPM_AIF_IN("SDIN1", "Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("SDIN2", "Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("SDOUT1", "Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("SDOUT2", "Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("SDOUT3", "Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SWITCH("SDOUT3 Enable", SND_SOC_NOPM, 0, 0,
&ak7755_out3e_control),
SND_SOC_DAPM_SWITCH("SDOUT2 Enable", SND_SOC_NOPM, 0, 0,
&ak7755_out2e_control),
SND_SOC_DAPM_SWITCH("SDOUT1 Enable", SND_SOC_NOPM, 0, 0,
&ak7755_out1e_control),
SND_SOC_DAPM_PGA("SDOUTAD", SND_SOC_NOPM, 0, 0, NULL, 0), //ADC's Output
SND_SOC_DAPM_PGA("SDOUTAD2", SND_SOC_NOPM, 0, 0, NULL, 0), //ADC2's Output
SND_SOC_DAPM_PGA("DSP", AK7755_CF_RESET_POWER_SETTING, 2, 0, NULL, 0),
SND_SOC_DAPM_AIF_IN("DSP GP0", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("DSP GP1", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("EEST", NULL, 0, SND_SOC_NOPM, 0, 0),
// Multiplexer (selects 1 analog signal from many inputs) & Mixer
SND_SOC_DAPM_MUX("SDOUT3 MUX", SND_SOC_NOPM, 0, 0, &ak7755_seldo3_mux_control),
SND_SOC_DAPM_MUX("SDOUT2 MUX", SND_SOC_NOPM, 0, 0, &ak7755_seldo2_mux_control),
SND_SOC_DAPM_MUX("SDOUT1 MUX", SND_SOC_NOPM, 0, 0, &ak7755_seldo1_mux_control),
SND_SOC_DAPM_MUX("DAC MUX", SND_SOC_NOPM, 0, 0, &ak7755_seldai_mux_control),
SND_SOC_DAPM_VIRT_MUX("SELMIX DSP", SND_SOC_NOPM, 0, 0, &ak7755_dsp_selmix_control),
SND_SOC_DAPM_VIRT_MUX("SELMIX AD2", SND_SOC_NOPM, 0, 0, &ak7755_sdoutad2_selmix_control),
SND_SOC_DAPM_VIRT_MUX("SELMIX AD", SND_SOC_NOPM, 0, 0, &ak7755_sdoutad_selmix_control),
SND_SOC_DAPM_PGA("SELMIX Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
};
static const struct snd_soc_dapm_route ak7755_intercon[] =
{
#ifdef DIGITAL_MIC
{"DMIC1 Left", "NULL", "CLOCK"},
{"DMIC1 Right", "NULL", "CLOCK"},
{"DMIC2 Left", "NULL", "CLOCK"},
{"DMIC2 Right", "NULL", "CLOCK"},
{"DMICIN1", "NULL", "DMIC1 CLK"},
{"DMICIN2", "NULL", "DMIC2 CLK"},
{"DMIC1 Left", "NULL", "DMICIN1"},
{"DMIC1 Right", "NULL", "DMICIN1"},
{"DMIC2 Left", "NULL", "DMICIN2"},
{"DMIC2 Right", "NULL", "DMICIN2"},
{"SDOUTAD", "NULL", "DMIC1 Left"},
{"SDOUTAD", "NULL", "DMIC1 Right"},
{"SDOUTAD2", "NULL", "DMIC2 Left"},
{"SDOUTAD2", "NULL", "DMIC2 Right"},
#else
{"ADC Left", "NULL", "CLOCK"},
{"ADC Right", "NULL", "CLOCK"},
{"ADC2 Left", "NULL", "CLOCK"},
{"LineIn Amp", "NULL", "LIN"},
{"ADC2 Left", "NULL", "LineIn Amp"},
{"SDOUTAD2", "NULL", "ADC2 Left"},
{"LIN MUX", "IN1", "IN1"},
{"LIN MUX", "IN2", "IN2"},
{"LIN MUX", "INPN1", "INPN1"},
{"RIN MUX", "IN3", "IN3"},
{"RIN MUX", "IN4", "IN4"},
{"RIN MUX", "INPN2", "INPN2"},
{"ADC Left", "NULL", "LIN MUX"},
{"ADC Right", "NULL", "RIN MUX"},
{"SDOUTAD", "NULL", "ADC Left"},
{"SDOUTAD", "NULL", "ADC Right"},
#endif
{"DAC Left", "NULL", "CLOCK"},
{"DAC Right", "NULL", "CLOCK"},
{"DSP", "NULL", "CLOCK"},
{"DSP", "NULL", "SDIN1"},
{"DSP", "NULL", "SDIN2"},
{"DSPIN SDOUTAD", "On", "SDOUTAD"},
{"DSPIN SDOUTAD2", "On", "SDOUTAD2"},
{"DSP", "NULL", "DSPIN SDOUTAD"},
{"DSP", "NULL", "DSPIN SDOUTAD2"},
{"SELMIX AD", "On", "SDOUTAD"},
{"SELMIX AD2", "On", "SDOUTAD2"},
{"SELMIX DSP", "On", "DSP"},
{"SELMIX Mixer", "NULL", "SELMIX AD"},
{"SELMIX Mixer", "NULL", "SELMIX AD2"},
{"SELMIX Mixer", "NULL", "SELMIX DSP"},
{"DAC MUX", "MIXOUT", "SELMIX Mixer"},
{"DAC MUX", "DSP", "DSP"},
{"DAC MUX", "SDIN2", "SDIN2"},
{"DAC MUX", "SDIN1", "SDIN1"},
{"DAC Left", "NULL", "DAC MUX"},
{"DAC Right", "NULL", "DAC MUX"},
{"LineOut Amp1", "On", "DAC Left"},
{"LineOut Amp2", "On", "DAC Right"},
{"Line Out1", "NULL", "LineOut Amp1"},
{"Line Out2", "NULL", "LineOut Amp2"},
{"LineOut Amp3 Mixer", "LOSW1", "DAC Left"},
{"LineOut Amp3 Mixer", "LOSW2", "DAC Right"},
#ifndef DIGITAL_MIC //LOSW3 used only Analog MIC
{"LineOut Amp3 Mixer", "LOSW3", "LineIn Amp"},
#endif
{"Line Out3", "NULL", "LineOut Amp3 Mixer"},
{"SDOUT1 MUX", "DSP", "DSP"},
{"SDOUT1 MUX", "DSP GP0", "DSP GP0"},
{"SDOUT1 MUX", "SDIN1", "SDIN1"},
{"SDOUT1 MUX", "SDOUTAD", "SDOUTAD"},
{"SDOUT1 MUX", "EEST", "EEST"},
{"SDOUT1 MUX", "SDOUTAD2", "SDOUTAD2"},
{"SDOUT2 MUX", "DSP", "DSP"},
{"SDOUT2 MUX", "DSP GP1", "DSP GP1"},
{"SDOUT2 MUX", "SDIN2", "SDIN2"},
{"SDOUT2 MUX", "SDOUTAD2", "SDOUTAD2"},
{"SDOUT3 MUX", "DSP DOUT3", "DSP"},
{"SDOUT3 MUX", "MIXOUT", "DAC MUX"},
{"SDOUT3 MUX", "DSP DOUT4", "DSP"},
{"SDOUT3 MUX", "SDOUTAD2", "SDOUTAD2"},
{"SDOUT1 Enable", "Switch", "SDOUT1 MUX"},
{"SDOUT2 Enable", "Switch", "SDOUT2 MUX"},
{"SDOUT3 Enable", "Switch", "SDOUT3 MUX"},
{"SDOUT1", "NULL", "SDOUT1 Enable"},
{"SDOUT2", "NULL", "SDOUT2 Enable"},
{"SDOUT3", "NULL", "SDOUT3 Enable"},
};
static int ak7755_hw_params_set(struct snd_soc_codec *codec, int nfs)
{
u8 fs;
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
fs = snd_soc_read(codec, AK7755_C0_CLOCK_SETTING1);
fs &= ~AK7755_FS;
switch (nfs) {
case 8000:
fs |= AK7755_FS_8KHZ;
break;
case 11025:
fs |= AK7755_FS_12KHZ;
break;
case 16000:
fs |= AK7755_FS_16KHZ;
break;
case 22050:
fs |= AK7755_FS_24KHZ;
break;
case 32000:
fs |= AK7755_FS_32KHZ;
break;
case 44100:
case 48000:
fs |= AK7755_FS_48KHZ;
break;
case 88200:
case 96000:
fs |= AK7755_FS_96KHZ;
break;
default:
return -EINVAL;
}
snd_soc_write(codec, AK7755_C0_CLOCK_SETTING1, fs);
ak7755_set_status(RUN);
if (aec == 1){
snd_soc_update_bits(codec, AK7755_CE_POWER_MANAGEMENT, 0x80, 0x0); //If aec is enable, only CH-L enable by DSP
}
return 0;
}
static int ak7755_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
u8 format;
format = snd_soc_read(codec, AK7755_C2_SERIAL_DATA_FORMAT);
format &= ~AK7755_LRIF;
if (aec ==0){
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
ak7755->bickfs = (AK7755_AIF_BICK32 >> 4);
break;
case SNDRV_PCM_FORMAT_S24_LE:
ak7755->bickfs = (AK7755_AIF_BICK48 >> 4);
break;
case SNDRV_PCM_FORMAT_S32_LE:
ak7755->bickfs = (AK7755_AIF_BICK64 >> 4);
break;
default:
dev_err(codec->dev, "Can not support the format");
return -EINVAL;
}
}else{
ak7755->bickfs = (AK7755_AIF_BICK64 >> 4);
}
ak7755->fs = params_rate(params);
ak7755_hw_params_set(codec, ak7755->fs);
snd_soc_update_bits(codec, AK7755_C1_CLOCK_SETTING2, 0x30, (ak7755->bickfs << 4));
if ( ak7755->bickfs < 3 ) {
format &= 0x7F;
} else {
format |= 0x80;
format &= 0xF3;
format |= AK7755_TDM_INPUT_SOURCE;
}
switch (ak7755->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
format |= AK7755_LRIF_I2S_MODE;
if ( ak7755->bickfs == 2 ) { // 32fs
snd_soc_update_bits(codec, AK7755_C3_DELAY_RAM_DSP_IO, 0xF0, 0xf0); // DIF2, DOF2
snd_soc_update_bits(codec, AK7755_C6_DAC_DEM_SETTING, 0x37, 0x33); //DIF, DIFDA
snd_soc_update_bits(codec, AK7755_C7_DSP_OUT_SETTING, 0xFF, 0xf3); //DOF
}else {
snd_soc_update_bits(codec, AK7755_C3_DELAY_RAM_DSP_IO, 0xF0, 0x0); // DIF2, DOF2
snd_soc_update_bits(codec, AK7755_C6_DAC_DEM_SETTING, 0x37, 0x0); //DIF, DIFDA
snd_soc_update_bits(codec, AK7755_C7_DSP_OUT_SETTING, 0xFF, 0x0); //DOF
}
break;
case SND_SOC_DAIFMT_LEFT_J:
format |= AK7755_LRIF_MSB_MODE;
if ( ak7755->bickfs == 2 ) { // 32fs
snd_soc_update_bits(codec, AK7755_C3_DELAY_RAM_DSP_IO, 0xF0, 0xF0); // DIF2, DOF2
snd_soc_update_bits(codec, AK7755_C6_DAC_DEM_SETTING, 0x37, 0x33); //DIF, DIFDA
snd_soc_update_bits(codec, AK7755_C7_DSP_OUT_SETTING, 0xFF, 0xF3); //DOF
}
else {
snd_soc_update_bits(codec, AK7755_C3_DELAY_RAM_DSP_IO, 0xF0, 0x0); // DIF2, DOF2
snd_soc_update_bits(codec, AK7755_C6_DAC_DEM_SETTING, 0x37, 0x0); //DIF, DIFDA
snd_soc_update_bits(codec, AK7755_C7_DSP_OUT_SETTING, 0xFF, 0x0); //DOF
}
break;
/*
case SND_SOC_DAIFMT_PCM_SHORT:
format &= 0xBF; //BCKP Clear
format |= (AK7755_BCKP_BIT << 6); //BCKP set
format |= AK7755_LRIF_PCM_SHORT_MODE;
break;
case SND_SOC_DAIFMT_PCM_LONG:
format &= 0xBF; //BCKP lear
format |= (AK7755_BCKP_BIT << 6); //BCKP set
format |= AK7755_LRIF_PCM_LONG_MODE;
break;
*/
default:
return -EINVAL;
}
snd_soc_write(codec, AK7755_C2_SERIAL_DATA_FORMAT, format);
return 0;
}
static int ak7755_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
ak7755_data->rclk = freq;
return 0;
}
static int ak7755_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec); // '15/06/15
u8 mode, mode2;
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
/* set master/slave audio interface */
mode = snd_soc_read(codec, AK7755_C0_CLOCK_SETTING1);//CKM2-0(M/S)
mode &= ~AK7755_M_S;
mode2 = snd_soc_read(codec, AK7755_CA_CLK_SDOUT_SETTING);//BICKOE,LRCKOE
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
#ifdef CLOCK_MODE_BICK
mode |= AK7755_M_S_3;//CKM mode = 3(Slave, BICK)
#else
mode |= AK7755_M_S_2;//CKM mode = 2(Slave, XTI=12.288MHz)
#endif
mode2 &= ~AK7755_BICK_LRCK;//BICK = LRCK = 0
break;
case SND_SOC_DAIFMT_CBM_CFM:
#ifdef CLOCK_MODE_18_432
mode |= AK7755_M_S_1;//CKM mode = 1(Master, XTI=18.432MHz)
#else
mode |= AK7755_M_S_0;//CKM mode = 0(Master, XTI=12.288MHz)
#endif
mode2 |= AK7755_BICK_LRCK;//BICK = LRCK = 1
break;
case SND_SOC_DAIFMT_CBS_CFM:
case SND_SOC_DAIFMT_CBM_CFS:
default:
dev_err(codec->dev, "Clock mode unsupported");
return -EINVAL;
}
ak7755->fmt = fmt;
/* set mode */
snd_soc_write(codec, AK7755_C0_CLOCK_SETTING1, mode);
snd_soc_write(codec, AK7755_CA_CLK_SDOUT_SETTING, mode2);
return 0;
}
static int ak7755_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
int ret;
switch (reg) {
// case :
// ret = 1;
default:
ret = 0;
break;
}
return ret;
}
static int ak7755_readable(struct snd_soc_codec *codec, unsigned int reg)
{
return ak7755_access_masks[reg].readable != 0;
}
static inline void ak7755_write_reg_cache(
struct snd_soc_codec *codec,
u16 reg,
u16 value)
{
u8 *cache = codec->reg_cache;
//BUG_ON(reg_index > ARRAY_SIZE(ak7755_reg));
if (reg < ARRAY_SIZE(ak7755_reg))
cache[reg] = (u8)value;
}
/*
* Read ak7755 register cache
*/
static inline u32 ak7755_read_reg_cache(struct snd_soc_codec *codec, u16 reg)
{
u8 *cache = codec->reg_cache;
BUG_ON(reg > ARRAY_SIZE(ak7755_reg));
return (u32)cache[reg];
}
static unsigned int ak7755_i2c_read(
u8 *reg,
int reglen,
u8 *data,
int datalen)
{
struct i2c_msg xfer[2];
int ret;
struct i2c_client *client = ak7755_data->i2c;
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = reglen;
xfer[0].buf = reg;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = datalen;
xfer[1].buf = data;
ret = i2c_transfer(client->adapter, xfer, 2);
// akdbgprt("*****[AK7755] %s (%x,%x)\n",__FUNCTION__, (int)reg[0], (int)data[0]);
if (ret == 2)
return 0;
else if (ret < 0)
return -ret;
else
return -EIO;
}
static int ak7755_reads(u8 *tx, size_t wlen, u8 *rx, size_t rlen)
{
int ret;
akdbgprt("*****[AK7755] %s tx[0]=%x, %d, %d\n",__FUNCTION__, tx[0],wlen,rlen);
if (ak7755_data->control_type == SND_SOC_SPI) {
ret = spi_write_then_read(ak7755_data->spi, tx, wlen, rx, rlen);
}
else {
ret = ak7755_i2c_read( tx, wlen, rx, rlen);
}
return ret;
}
unsigned int ak7755_reg_read(struct snd_soc_codec *codec, unsigned int reg)
{
unsigned char tx[1], rx[1];
int wlen, rlen;
int ret;
unsigned int rdata;
wlen = 1;
rlen = 1;
tx[0] = (unsigned char)(0x7F & reg);
//akdbgprt("*****[AK7755] %s reg = %0x, tx[0]=%0x, %d, %d\n",__FUNCTION__, reg, tx[0],wlen,rlen);
if (ak7755_data->control_type == SND_SOC_SPI) {
ret = spi_write_then_read(ak7755_data->spi, tx, wlen, rx, rlen);
}
else {
ret = ak7755_i2c_read(tx, wlen, rx, rlen);
}
if (ret < 0) {
akdbgprt("\t[AK7755] %s error ret = %d\n",__FUNCTION__, ret);
rdata = -EIO;
return rdata;
}
else {
rdata = (unsigned int)rx[0];
if (ak7755_read_reg_cache(codec, reg) != rdata)
ak7755_write_reg_cache(codec, reg, rdata);
}
akdbgprt("\t[AK7755] %s addr, read data =(%x, %x)\n",__FUNCTION__, reg, (int)rdata);
return rdata;
}
static int ak7755_writes(const u8 *tx, size_t wlen)
{
int rc;
int reg = (int)tx[0];
if(fast_boot){
if(reg == AK7755_CE_POWER_MANAGEMENT)
return 0;
}
akdbgprt("![AK7755W] %s tx[0]=%x tx[1]=%x, len=%d\n",__FUNCTION__, (int)tx[0], (int)tx[1], wlen);
if (ak7755_data->control_type == SND_SOC_SPI)
rc = spi_write_then_read(ak7755_data->spi, tx, wlen, NULL, 0);
else
rc = i2c_master_send(ak7755_data->i2c, tx, wlen);
if (rc < 0) {
akdbgprt("\t[AK7755] %s error rc = %d\n",__FUNCTION__, rc);
}
return rc;
}
int ak7755_reg_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
{
unsigned char tx[3];
int wlen;
int ret;
wlen = 2;
tx[0] = reg;
tx[1] = value;
ret = ak7755_writes(tx, wlen);
if (ret >=0) {
ak7755_write_reg_cache(codec, reg, value);
}
return ret;
}
/*
* Write with Mask to AK7755 register space
*/
// ak7755_writeMask() => snd_soc_update_bits() // '16/01/13
/*********************************/
static int crc_read(void)
{
int rc;
u8 tx[1], rx[2];
tx[0] = CRC_COMMAND_READ_RESULT;
rc = ak7755_reads(tx, 1, rx, 2);
return (rc < 0) ? rc : ((rx[0] << 8) + rx[1]);
}
static int ak7755_set_status(enum ak7755_status status)
{
switch (status) {
case RUN:
snd_soc_update_bits(ak7755_data->codec, AK7755_C1_CLOCK_SETTING2, 0x1, 0x1); // CKRESETN bit = 1
mdelay(10);
snd_soc_update_bits(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, 0xc, 0xc); // CRESETN bit = DSPRESETN = 1;
mdelay(10);
break;
case DOWNLOAD:
snd_soc_update_bits(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, 0x1, 0x1); // DLRDY bit = 1
mdelay(10);
break;
case STANDBY:
snd_soc_update_bits(ak7755_data->codec, AK7755_C1_CLOCK_SETTING2, 0x1, 0x1); // CKRESETN bit = 1
mdelay(10);
snd_soc_update_bits(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, 0xc, 0x0); // CRESETN bit = DSPRESETN = 0;
mdelay(10);
break;
case SUSPEND:
case POWERDOWN:
snd_soc_update_bits(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, 0x3f, 0x0);
snd_soc_update_bits(ak7755_data->codec, AK7755_CE_POWER_MANAGEMENT, 0xFF, 0x0);
snd_soc_update_bits(ak7755_data->codec, AK7755_C1_CLOCK_SETTING2, 0x0, 0x0);
mdelay(10);
break;
default:
return -EINVAL;
}
ak7755_data->status = status;
return 0;
}
static int ak7755_ram_download(const u8 *tx_ram, u64 num, u16 crc)
{
int rc;
int nDSPRun;
u16 read_crc;
akdbgprt("\t[AK7755] %s num=%ld\n",__FUNCTION__, (long int)num);
nDSPRun = snd_soc_read(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING);
ak7755_set_status(DOWNLOAD);
rc = ak7755_writes(tx_ram, num);
if (rc < 0) {
// ak7755_set_status(STANDBY);
snd_soc_write(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, nDSPRun);
return rc;
}
if ( ( crc != 0 ) && (rc >= 0) ) {
read_crc = crc_read();
akdbgprt("\t[AK7755] %s CRC Cal=%x Read=%x\n",__FUNCTION__, (int)crc,(int)read_crc);
if ( read_crc == crc ) rc = 0;
else rc = 1;
}
// ak7755_set_status(STANDBY);
snd_soc_write(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, nDSPRun);
return rc;
}
static int calc_CRC(int length, u8 *data )
{
#define CRC16_CCITT (0x1021)
unsigned short crc = 0x0000;
int i, j;
for ( i = 0; i < length; i++ ) {
crc ^= *data++ << 8;
for ( j = 0; j < 8; j++) {
if ( crc & 0x8000) {
crc <<= 1;
crc ^= CRC16_CCITT;
}
else {
crc <<= 1;
}
}
}
akdbgprt("[AK7755] %s CRC=%x\n",__FUNCTION__, crc);
return crc;
}
static int ak7755_write_ram(
int nPCRam, // 0 : PRAM, 1 : CRAM, 2: OFREG. 3: ACRAM
u8 *upRam,
int nWSize)
{
int n, ret;
int wCRC;
akdbgprt("[AK7755] %s RamNo=%d, len=%d\n",__FUNCTION__, nPCRam, nWSize);
switch(nPCRam) {
case RAMTYPE_PRAM:
if ( nWSize > TOTAL_NUM_OF_PRAM_MAX ) {
printk("%s: PRAM Write size is over! \n", __func__);
return(-1);
}
break;
case RAMTYPE_CRAM:
if ( nWSize > TOTAL_NUM_OF_CRAM_MAX ) {
printk("%s: CRAM Write size is over! \n", __func__);
return(-1);
}
break;
case RAMTYPE_OFREG:
if ( nWSize > TOTAL_NUM_OF_OFREG_MAX ) {
printk("%s: OFREG Write size is over! \n", __func__);
return(-1);
}
break;
case RAMTYPE_ACRAM:
if ( nWSize > TOTAL_NUM_OF_ACRAM_MAX ) {
printk("%s: ACRAM Write size is over! \n", __func__);
return(-1);
}
break;
default:
break;
}
wCRC = calc_CRC(nWSize, upRam);
n = MAX_LOOP_TIMES;
do {
ret = ak7755_ram_download(upRam, nWSize, wCRC);
if ( ret >= 0 ) break;
n--;
} while ( n > 0 );
if ( ret < 0 ) {
printk("%s: RAM Write Error! RAM No = %d \n", __func__, nPCRam);
return(-1);
}
return(0);
}
static int ak7755_firmware_write_ram(u16 mode, u16 cmd)
{
int ret = 0;
int nNumMode, nMaxLen;
int nRamSize;
u8 *ram_basic;
const struct firmware *fw;
u8 *fwdn;
char szFileName[32];
akdbgprt("[AK7755] %s mode=%d, cmd=%d\n",__FUNCTION__, mode, cmd);
switch(mode) {
case RAMTYPE_PRAM:
nNumMode = sizeof(ak7755_firmware_pram) / sizeof(ak7755_firmware_pram[0]);
break;
case RAMTYPE_CRAM:
nNumMode = sizeof(ak7755_firmware_cram) / sizeof(ak7755_firmware_cram[0]);
break;
case RAMTYPE_OFREG:
nNumMode = sizeof(ak7755_firmware_ofreg) / sizeof(ak7755_firmware_ofreg[0]);
break;
case RAMTYPE_ACRAM:
nNumMode = sizeof(ak7755_firmware_acram) / sizeof(ak7755_firmware_acram[0]);
break;
default:
akdbgprt("[AK7755] %s mode Error=%d\n",__FUNCTION__, mode);
return( -EINVAL);
}
if ( cmd == 0 ) return(0);
if ( cmd >= nNumMode ) {
pr_err("%s: invalid command %d\n", __func__, cmd);
return( -EINVAL);
}
if ( cmd == 1 ) {
switch(mode) {
case RAMTYPE_PRAM:
if (aec == 0){
ram_basic = ak7755_pram_basic;
nRamSize = sizeof(ak7755_pram_basic);
}else{
ram_basic = ak7755_pram_aec;
nRamSize = sizeof(ak7755_pram_aec);
}
break;
case RAMTYPE_CRAM:
if (aec == 0){
ram_basic = ak7755_cram_basic;
nRamSize = sizeof(ak7755_cram_basic);
}else{
ram_basic = ak7755_cram_aec;
nRamSize = sizeof(ak7755_cram_aec);
}
break;
case RAMTYPE_OFREG:
ram_basic = ak7755_ofreg_basic;
nRamSize = sizeof(ak7755_ofreg_basic);
break;
case RAMTYPE_ACRAM:
ram_basic = ak7755_acram_basic;
nRamSize = sizeof(ak7755_acram_basic);
break;
default:
return( -EINVAL);
}
ret = ak7755_write_ram((int)mode, ram_basic, nRamSize);
} else {
switch(mode) {
case RAMTYPE_PRAM:
sprintf(szFileName, "ak7755_pram_%s.bin", ak7755_firmware_pram[cmd]);
nMaxLen = TOTAL_NUM_OF_PRAM_MAX;
break;
case RAMTYPE_CRAM:
sprintf(szFileName, "ak7755_cram_%s.bin", ak7755_firmware_cram[cmd]);
nMaxLen = TOTAL_NUM_OF_CRAM_MAX;
break;
case RAMTYPE_OFREG:
sprintf(szFileName, "ak7755_ofreg_%s.bin", ak7755_firmware_cram[cmd]);
nMaxLen = TOTAL_NUM_OF_OFREG_MAX;
break;
case RAMTYPE_ACRAM:
sprintf(szFileName, "ak7755_acram_%s.bin", ak7755_firmware_cram[cmd]);
nMaxLen = TOTAL_NUM_OF_ACRAM_MAX;
break;
default:
return( -EINVAL);
}
if (ak7755_data->control_type == SND_SOC_SPI) {
ret = request_firmware(&fw, szFileName, &(ak7755_data->spi->dev));
}
else {
ret = request_firmware(&fw, szFileName, &(ak7755_data->i2c->dev));
}
if (ret) {
akdbgprt("[AK7755] %s could not load firmware=%d\n", szFileName, ret);
return -EINVAL;
}
//printk("[AK7755] %s name=%s size=%d\n",__FUNCTION__, szFileName, fw->size);
if ( fw->size > nMaxLen ) {
akdbgprt("[AK7755] %s RAM Size Error : %d\n",__FUNCTION__, fw->size);
return -ENOMEM;
}
fwdn = kmalloc((unsigned long)fw->size, GFP_KERNEL);
if (fwdn == NULL) {
printk(KERN_ERR "failed to buffer vmalloc: %d\n", fw->size);
return -ENOMEM;
}
memcpy((void *)fwdn, fw->data, fw->size);
ret = ak7755_write_ram((int)mode, (u8 *)fwdn, (fw->size));
//printk("ak7755 download ram is ok, ret = %d\n", ret);
kfree(fwdn);
}
return ret;
}
static int ak7755_write_cram(
int addr,
int len,
unsigned char *cram_data)
{
int i, n, ret;
int nDSPRun;
unsigned char tx[51];
akdbgprt("[AK7755] %s addr=%d, len=%d\n",__FUNCTION__, addr, len);
if ( len > 48 ) {
akdbgprt("[AK7755] %s Length over!\n",__FUNCTION__);
return(-1);
}
nDSPRun = snd_soc_read(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING);
if ( nDSPRun & 0x4 ) {
tx[0] = 0x80 + (unsigned char)((len / 3) - 1);
tx[1] = (unsigned char)(0xFF & (addr >> 8));
tx[2] = (unsigned char)(0xFF & addr);
}
else {
ak7755_set_status(DOWNLOAD);
tx[0] = 0xB4;
tx[1] = (unsigned char)(0xFF & (addr >> 8));
tx[2] = (unsigned char)(0xFF & addr);
}
n = 3;
for ( i = 0 ; i < len; i ++ ) {
tx[n++] = cram_data[i];
}
ret = ak7755_writes(tx, n);
if ( nDSPRun & 0x4 ) {
tx[0] = 0xA4;
tx[1] = 0;
tx[2] = 0;
ret = ak7755_writes(tx, 3);
}
else {
snd_soc_write(ak7755_data->codec, AK7755_CF_RESET_POWER_SETTING, nDSPRun);
}
return ret;
}
static unsigned long ak7755_readMIR(
int nMIRNo)
{
unsigned char tx[1];
unsigned char rx[4];
unsigned long dwMIRData;
if ( ( nMIRNo < 1 ) || ( nMIRNo > 4 ) ) return(-1);
tx[0] = (unsigned char)(0x74 + (2 * nMIRNo));
ak7755_reads(tx, 1, rx, 4);
dwMIRData = ((0xFF & (unsigned long)rx[0]) << 20) + ((0xFF & (unsigned long)rx[1]) << 12) +
((0xFF & (unsigned long)rx[2]) << 4) + ((0xFF & (unsigned long)rx[3]) >> 4);
return(dwMIRData);
}
static int ak7755_reg_cmd(REG_CMD *reg_param, int len)
{
int i;
int rc;
int addr, value;
akdbgprt("*****[AK7755] %s len = %d\n",__FUNCTION__, len);
rc = 0;
for (i = 0; i < len; i++) {
addr = (int)(reg_param[i].addr);
value = (int)(reg_param[i].data);
if ( addr != 0xFF ) {
rc = snd_soc_write(ak7755_data->codec, addr, value);
if (rc < 0) {
break;
}
}
else {
mdelay(value);
}
}
if (rc != 0 ) rc = 0;
return(rc);
}
#ifdef AK7755_IO_CONTROL
static long ak7755_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{
struct ak7755_priv *ak7755 = (struct ak7755_priv*)file->private_data;
struct ak7755_wreg_handle ak7755_wreg;
struct ak7755_wcram_handle ak7755_wcram;
struct ak7755_loadram_handle ak7755_ram;
void __user *data = (void __user *)args;
int *val = (int *)args;
int i;
unsigned long dwMIRData;
int ret = 0;
REG_CMD regcmd[MAX_WREG];
unsigned char cram_data[MAX_WCRAM];
akdbgprt("*****[AK7755] %s cmd, val=%x, %x\n",__FUNCTION__, cmd, val[0]);
switch(cmd) {
case AK7755_IOCTL_WRITECRAM:
if (copy_from_user(&ak7755_wcram, data, sizeof(struct ak7755_wcram_handle)))
return -EFAULT;
if ( ( ak7755_wcram.len % 3 ) != 0 ) {
printk(KERN_ERR "[AK7755] %s CRAM len error\n",__FUNCTION__);
return -EFAULT;
}
if ( ( ak7755_wcram.len < 3 ) || ( ak7755_wcram.len > MAX_WCRAM ) ) {
printk(KERN_ERR "[AK7755] %s CRAM len error2\n",__FUNCTION__);
return -EFAULT;
}
for ( i = 0 ; i < ak7755_wcram.len ; i ++ ) {
cram_data[i] = ak7755_wcram.cram[i];
}
ret = ak7755_write_cram(ak7755_wcram.addr, ak7755_wcram.len, cram_data);
break;
case AK7755_IOCTL_WRITEREG:
if (copy_from_user(&ak7755_wreg, data, sizeof(struct ak7755_wreg_handle)))
return -EFAULT;
if ( ( ak7755_wreg.len < 1 ) || ( ak7755_wreg.len > MAX_WREG ) ) {
printk(KERN_ERR "MAXREG ERROR %d\n", ak7755_wreg.len );
return -EFAULT;
}
for ( i = 0 ; i < ak7755_wreg.len; i ++ ) {
regcmd[i].addr = ak7755_wreg.regcmd[i].addr;
regcmd[i].data = ak7755_wreg.regcmd[i].data;
}
ak7755_reg_cmd(regcmd, ak7755_wreg.len);
break;
case AK7755_IOCTL_LOADRAM:
if (copy_from_user(&ak7755_ram, data, sizeof(struct ak7755_loadram_handle)))
return -EFAULT;
ak7755_firmware_write_ram(ak7755_ram.ramtype, ak7755_ram.mode);
break;
case AK7755_IOCTL_SETSTATUS:
ret = ak7755_set_status(val[0]);
if (ret < 0) {
printk(KERN_ERR "ak7755: set_status error: \n");
return ret;
}
break;
case AK7755_IOCTL_GETSTATUS:
ret = copy_to_user(data, (const void*)&ak7755->status,
(unsigned long)sizeof(unsigned int));
if (ret < 0) {
printk(KERN_ERR "ak7755: get status error\n");
return -EFAULT;
}
break;
case AK7755_IOCTL_SETMIR:
ak7755->MIRNo = val[0];
if (ret < 0) {
printk(KERN_ERR "ak7755: set MIR error\n");
return -EFAULT;
}
break;
case AK7755_IOCTL_GETMIR:
dwMIRData = ak7755_readMIR(ak7755->MIRNo);
ret = copy_to_user(data, (const void*)&dwMIRData,
(unsigned long)sizeof(unsigned int));
if (ret < 0) {
printk(KERN_ERR "ak7755: get status error\n");
return -EFAULT;
}
break;
default:
printk(KERN_ERR "Unknown command required: %d\n", cmd);
return -EINVAL;
}
return ret;
}
static int init_ak7755_pd(struct ak7755_priv *data)
{
struct _ak7755_pd_handler *ak7755 = &ak7755_pd_handler;
if (data == NULL)
return -EFAULT;
mutex_init(&ak7755->lock);
mutex_lock(&ak7755->lock);
ak7755->data = data;
mutex_unlock(&ak7755->lock);
printk("data:%p, ak7755->data:%p\n", data, ak7755->data);
return 0;
}
static struct ak7755_priv* get_ak7755_pd(void)
{
struct _ak7755_pd_handler *ak7755 = &ak7755_pd_handler;
if (ak7755->data == NULL)
return NULL;
mutex_lock(&ak7755->lock);
ak7755->ref_count++;
mutex_unlock(&ak7755->lock);
return ak7755->data;
}
static int rel_ak7755_pd(struct ak7755_priv *data)
{
struct _ak7755_pd_handler *ak7755 = &ak7755_pd_handler;
if (ak7755->data == NULL)
return -EFAULT;
mutex_lock(&ak7755->lock);
ak7755->ref_count--;
mutex_unlock(&ak7755->lock);
data = NULL;
return 0;
}
/* AK7755 Misc driver interfaces */
static int ak7755_open(struct inode *inode, struct file *file)
{
struct ak7755_priv *ak7755;
ak7755 = get_ak7755_pd();
file->private_data = ak7755;
return 0;
}
static int ak7755_close(struct inode *inode, struct file *file)
{
struct ak7755_priv *ak7755 = (struct ak7755_priv*)file->private_data;
rel_ak7755_pd(ak7755);
return 0;
}
static const struct file_operations ak7755_fops = {
.owner = THIS_MODULE,
.open = ak7755_open,
.release = ak7755_close,
.unlocked_ioctl = ak7755_ioctl,
};
static struct miscdevice ak7755_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ak7755-dsp",
.fops = &ak7755_fops,
};
#endif
/*********************************/
// * for AK7755
static int ak7755_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
if(ak7755->amp_gpio > 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_PLAYBACK) {
gpio_direction_output(ak7755->amp_gpio, ak7755->amp_active);
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
gpio_direction_output(ak7755->amp_gpio, !ak7755->amp_active);
}
break;
default:
break;
}
}
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
return ret;
}
static int ak7755_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
akdbgprt("\t[AK7755] %s(%d) level : %d\n",__FUNCTION__,__LINE__, level);
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
ak7755_set_status(RUN);
break;
case SND_SOC_BIAS_STANDBY:
ak7755_set_status(STANDBY);
break;
case SND_SOC_BIAS_OFF:
ak7755_set_status(POWERDOWN);
break;
}
codec->dapm.bias_level = level;
return 0;
}
static int ak7755_set_dai_mute2(struct snd_soc_codec *codec, int mute)
{
int ret = 0;
//int ndt;
//akdbgprt("\t[AK7755] %s mute[%s]\n",__FUNCTION__, mute ? "ON":"OFF");
#if 0
if (mute) { //SMUTE: 1 , MUTE
ret = snd_soc_update_bits(codec, AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 0xE0, 0xE0);
}
else {
ak7755_set_status(RUN);
// SMUTE: 0 ,NORMAL operation
ret = snd_soc_update_bits(codec, AK7755_DA_MUTE_ADRC_ZEROCROSS_SET, 0xE0, 0x00);
}
ndt = 1021000 / ak7755_data->fs;
mdelay(ndt);
#endif
return ret;
}
static int ak7755_set_dai_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
ak7755_set_dai_mute2(codec, mute);
return 0;
}
#define AK7755_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_88200 |\
SNDRV_PCM_RATE_96000)
#define AK7755_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops ak7755_dai_ops = {
.hw_params = ak7755_hw_params,
.set_sysclk = ak7755_set_dai_sysclk,
.set_fmt = ak7755_set_dai_fmt,
.trigger = ak7755_trigger,
.digital_mute = ak7755_set_dai_mute,
};
struct snd_soc_dai_driver ak7755_dai[] = {
{
.name = "ak7755-AIF1",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = AK7755_RATES,
.formats = AK7755_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 4,
.rates = AK7755_RATES,
.formats = AK7755_FORMATS,
},
.ops = &ak7755_dai_ops,
},
};
static int ak7755_init_reg(struct snd_soc_codec *codec)
{
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec); // '15/06/15
akdbgprt("\t[AK7755 bias] %s(%d)\n",__FUNCTION__,__LINE__);
if(!fast_boot){
if ( ak7755->power_gpio > 0 ) {
gpio_direction_output(ak7755->power_gpio, ak7755->power_active);
}
if ( ak7755->pdn_gpio > 0 ) {
gpio_direction_output(ak7755->pdn_gpio, ak7755->pdn_active);
msleep(10);
gpio_direction_output(ak7755->pdn_gpio, !ak7755->pdn_active);
}
}
ak7755_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_update_bits(codec, AK7755_D4_LO1_LO2_VOLUME_SETTING, 0xFF, 0xFF); //LOVOL1,2=F(0dB)
snd_soc_update_bits(codec, AK7755_D3_LIN_LO3_VOLUME_SETTING, 0x0F, 0x0F); //LOVOL3=F(0dB)
snd_soc_update_bits(codec, AK7755_D2_MIC_GAIN_SETTING, 0xFF, 0xCC);
snd_soc_update_bits(codec, AK7755_D0_FUNCTION_SETTING, 0x40, 0x40); //CRCE=1(CRC Enable)
snd_soc_update_bits(codec, AK7755_C2_SERIAL_DATA_FORMAT, 0x40, AK7755_BCKP_BIT); //BCKP bit
snd_soc_update_bits(codec, AK7755_D0_FUNCTION_SETTING, 0x10, AK7755_SOCFG_BIT); //SOFG bit
#ifdef DIGITAL_MIC //Analog MIC Use
snd_soc_update_bits(codec, AK7755_DE_DMIC_IF_SETTING, 0x90, 0x90); //DMIC1=DMIC2=1(Digital MIC Use)
snd_soc_update_bits(codec, AK7755_DE_DMIC_IF_SETTING, 0x40, AK7755_DMCLKP1_BIT); //DMCLKP1 bit
snd_soc_update_bits(codec, AK7755_DE_DMIC_IF_SETTING, 0x08, AK7755_DMCLKP2_BIT); //DMCLKP2 bit
snd_soc_update_bits(codec, AK7755_C0_CLOCK_SETTING1, 0x08, 0x00);
#else
snd_soc_update_bits(codec, AK7755_C0_CLOCK_SETTING1, 0x08, 0x08); //AINE=1(Analog MIC Use)
#endif
snd_soc_write(codec, 0xCA, 0x01);
snd_soc_write(codec, 0xDA, 0x10);
snd_soc_write(codec, 0xCD, 0xC0);
snd_soc_write(codec, 0xE6, 0x01);
snd_soc_write(codec, 0xEA, 0x80);
if(aec == 1) {
/*Select DAC MUX as DSP DOUT4*/
snd_soc_update_bits(codec, AK7755_C8_DAC_IN_SETTING, 0xC0, 0x00);
/*Lineout1 power on*/
snd_soc_update_bits(codec, AK7755_CE_POWER_MANAGEMENT, 0xC7, 0xC7);
/*Select SDOUT1 MUX as DOUT1 Of DSP*/
snd_soc_update_bits(codec, AK7755_CC_VOLUME_TRANSITION, 0x07, 0x00);
} else {
/*Select DAC MUX as SDIN1*/
snd_soc_update_bits(codec, AK7755_C8_DAC_IN_SETTING, 0xC0, 0xC0);
/*Lineout1 power on*/
snd_soc_update_bits(codec, AK7755_CE_POWER_MANAGEMENT, 0xC7, 0xC7);
/*Select SDOUT1 MUX as SDOUTAD*/
snd_soc_update_bits(codec, AK7755_CC_VOLUME_TRANSITION, 0x07, 0x03);
}
if(fast_boot){
snd_soc_write(codec, 0xC0, 0x2A);
snd_soc_write(codec, 0xC2, 0x10);
snd_soc_write(codec, 0xCE, 0x4f);
}
return 0;
}
#ifdef CONFIG_OF // '16/01/13
static int ak7755_parse_dt(struct ak7755_priv *ak7755)
{
struct device *dev;
struct device_node *np;
enum of_gpio_flags flags;
if (ak7755->control_type == SND_SOC_SPI) {
dev = &(ak7755->spi->dev);
}
else {
dev = &(ak7755->i2c->dev);
}
np = dev->of_node;
if (!np)
return -1;
printk("Read PDN pin from device tree\n");
ak7755->pdn_gpio = of_get_named_gpio_flags(np, "ak7755,pdn-gpio", 0, &flags);
ak7755->pdn_active = !!(flags & OF_GPIO_ACTIVE_LOW);
if(ak7755->pdn_gpio < 0 || !gpio_is_valid(ak7755->pdn_gpio)) {
printk(KERN_ERR "ak7755 pdn pin(%u) is invalid\n", ak7755->pdn_gpio);
ak7755->pdn_gpio = -1;
return -1;
}
ak7755->power_gpio = of_get_named_gpio_flags(np, "ak7755,pwr-gpio", 0, &flags);
ak7755->power_active = !!(flags & OF_GPIO_ACTIVE_LOW);
if (ak7755->power_gpio < 0 || !gpio_is_valid(ak7755->power_gpio)) {
ak7755->power_gpio = -1;
}
ak7755->amp_gpio = of_get_named_gpio_flags(np, "ak7755,amp-gpio", 0, &flags);
ak7755->amp_active = !!(flags & OF_GPIO_ACTIVE_LOW);
if (ak7755->amp_gpio < 0 || !gpio_is_valid(ak7755->amp_gpio)) {
ak7755->amp_gpio = -1;
}
return 0;
}
#endif
static int ak7755_set_reg_table(void)
{
int i;
int n;
n = 0;
do {
ak7755_reg[n] = 0;
ak7755_access_masks[n].readable = 0;
ak7755_access_masks[n].writable = 0;
n ++;
} while ( n < AK7755_C0_CLOCK_SETTING1 );
i = 0;
do {
ak7755_reg[n] = ak7755_reg2[i] ;
ak7755_access_masks[n].readable = ak7755_access_masks2[i].readable;
ak7755_access_masks[n].writable = ak7755_access_masks2[i].writable;
i++;
n++;
} while ( n < AK7755_MAX_REGISTERS);
return(0);
}
static int ak7755_probe(struct snd_soc_codec *codec)
{
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
#ifndef CONFIG_OF
struct ak7755_platform_data *pdata = codec->dev->platform_data; // '15/06/15
#endif
int ret = 0;
int i;
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak7755->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
#ifdef AK7755_CONTIF_DEBUG
codec->read = ak7755_reg_read;
codec->write = ak7755_reg_write;
#endif
akdbgprt("\t[AK7755] %s(%d) ak7755=%x\n",__FUNCTION__,__LINE__, (int)ak7755);
ak7755->codec = codec;
#ifdef CONFIG_OF
ret = ak7755_parse_dt(ak7755);
#else
if ( pdata != NULL ) {
ak7755->pdn_gpio = pdata->pdn_gpio;
}
#endif
if(!fast_boot){
if (gpio_is_valid(ak7755->pdn_gpio))
ret = devm_gpio_request(codec->dev, ak7755->pdn_gpio, "ak7755 pdn");
if (ret < 0){
dev_err(codec->dev, "Failed to request pdn pin for ak7755: %d\n", ret);
return ret;
}
if (gpio_is_valid(ak7755->power_gpio))
ret = devm_gpio_request(codec->dev, ak7755->power_gpio, "ak7755 power");
if (ret < 0){
dev_err(codec->dev, "Failed to request power pin for ak7755: %d\n", ret);
return ret;
}
if (gpio_is_valid(ak7755->amp_gpio))
ret = devm_gpio_request(codec->dev, ak7755->amp_gpio, "ak7755 amplifier");
if (ret < 0){
dev_err(codec->dev, "Failed to request amplifier pin for ak7755: %d\n", ret);
return ret;
}
}
ak7755_set_reg_table();
ak7755_init_reg(codec);
akdbgprt("\t[AK7755 Effect] %s(%d)\n",__FUNCTION__,__LINE__);
ak7755->fs = 48000;
ak7755->rclk = 0;
ak7755->lign = 7; //lign:7 = LIGN:0(0dB)
ak7755->selmix = 0; //SDOUTAD(L,R)
ak7755->MIRNo = 1;
ak7755->status = POWERDOWN;
ak7755->DSPPramMode = 0;
ak7755->DSPCramMode = 0;
ak7755->DSPOfregMode = 0;
ak7755->DSPAcramMode = 0;
for ( i = 0 ; i < 5 ; i ++ ) ak7755->EQLevel[i] = 24;
ak7755->HPFfc[0] = 0;
ak7755->HPFfc[1] = 0;
ak7755->LimRel = 2;
ak7755->LimVol = 0;
ak7755->bickfs = (AK7755_AUDIO_IF_MODE >> 4);
akdbgprt("\t[AK7755 init_ak7755_pd] %s(%d)\n",__FUNCTION__,__LINE__);
#ifdef AK7755_IO_CONTROL
init_ak7755_pd(ak7755);
#endif
return ret;
}
static int ak7755_remove(struct snd_soc_codec *codec)
{
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
ak7755_set_bias_level(codec, SND_SOC_BIAS_OFF);
if ( ak7755->pdn_gpio > 0 ) {
gpio_set_value(ak7755->pdn_gpio, 0);
gpio_free(ak7755->pdn_gpio);
}
return 0;
}
static int ak7755_suspend(struct snd_soc_codec *codec)
{
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
ak7755_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if ( ak7755->pdn_gpio > 0 ) {
gpio_set_value(ak7755->pdn_gpio, 0);
}
else {
#ifdef AK7755_PD_SUSPEND
//snd_soc_cache_init(codec);
#endif
}
return 0;
}
static int ak7755_resume(struct snd_soc_codec *codec)
{
struct ak7755_priv *ak7755 = snd_soc_codec_get_drvdata(codec);
if ( ak7755->pdn_gpio > 0 ) {
gpio_set_value(ak7755->pdn_gpio, 0);
msleep(2);
gpio_set_value(ak7755->pdn_gpio, 1);
}
mdelay(2);
ak7755_firmware_write_ram(RAMTYPE_PRAM, ak7755_data->DSPPramMode);
ak7755_firmware_write_ram(RAMTYPE_CRAM, ak7755_data->DSPCramMode);
snd_soc_cache_sync(codec);
snd_soc_write(codec, 0xE6, 0x01);
snd_soc_write(codec, 0xEA, 0x80);
ak7755_set_bias_level(codec, SND_SOC_BIAS_ON);
printk("ak7755_resume done...\n");
return 0;
}
struct snd_soc_codec_driver soc_codec_dev_ak7755 = {
.probe = ak7755_probe,
.remove = ak7755_remove,
.suspend = ak7755_suspend,
.resume = ak7755_resume,
//.idle_bias_off = false,
.set_bias_level = ak7755_set_bias_level,
.reg_cache_size = ARRAY_SIZE(ak7755_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = ak7755_reg,
.readable_register = ak7755_readable,
.volatile_register = ak7755_volatile,
.controls = ak7755_snd_controls,
.num_controls = ARRAY_SIZE(ak7755_snd_controls),
.dapm_widgets = ak7755_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak7755_dapm_widgets),
.dapm_routes = ak7755_intercon,
.num_dapm_routes = ARRAY_SIZE(ak7755_intercon),
};
EXPORT_SYMBOL_GPL(soc_codec_dev_ak7755);
#ifdef CONFIG_OF
static struct of_device_id ak7755_if_dt_ids[] = {
{ .compatible = "akm,ak7755"},
{ }
};
MODULE_DEVICE_TABLE(of, ak7755_if_dt_ids);
#endif
#ifdef AK7755_I2C_IF
static int ak7755_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct ak7755_priv *ak7755;
int ret=0;
akdbgprt("\t[AK7755] %s(%d)\n",__FUNCTION__,__LINE__);
ak7755 = kzalloc(sizeof(struct ak7755_priv), GFP_KERNEL);
if (ak7755 == NULL) return -ENOMEM;
i2c_set_clientdata(i2c, ak7755);
ak7755->control_type = SND_SOC_I2C;
ak7755->i2c = i2c;
ak7755_data = ak7755;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_ak7755, &ak7755_dai[0], ARRAY_SIZE(ak7755_dai));
if (ret < 0){
kfree(ak7755);
akdbgprt("\t[AK7755 Error!] %s(%d)\n",__FUNCTION__,__LINE__);
}
return ret;
}
static int ak7755_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
kfree(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id ak7755_i2c_id[] = {
{ "ak7755", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak7755_i2c_id);
static struct i2c_driver ak7755_i2c_driver = {
.driver = {
.name = "ak7755",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(ak7755_if_dt_ids),
#endif
},
.probe = ak7755_i2c_probe,
.remove = ak7755_i2c_remove,
.id_table = ak7755_i2c_id,
};
#else
static int ak7755_spi_probe(struct spi_device *spi)
{
struct ak7755_priv *ak7755;
int ret;
akdbgprt("\t[AK7755] %s spi=%x\n",__FUNCTION__, (int)spi);
printk("AK7755 SPI probe\n");
ak7755 = kzalloc(sizeof(struct ak7755_priv), GFP_KERNEL);
if (!ak7755)
return -ENOMEM;
ak7755->control_type = SND_SOC_SPI;
spi->bits_per_word = 8; // bits
spi->max_speed_hz = 1500000;
spi->mode = SPI_MODE_3;
akdbgprt("\t[AK7755] %s spi=%x, spi->chip_select = %d\n, cs_gpio = %d",__FUNCTION__, \
(int)spi, spi->chip_select, spi->cs_gpio);
ak7755->spi = spi;
ak7755_data = ak7755;
spi_set_drvdata(spi, ak7755);
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_ak7755, &ak7755_dai[0], ARRAY_SIZE(ak7755_dai));
if (ret < 0)
kfree(ak7755);
ak7755_data = ak7755;
return 0;
}
static int ak7755_spi_remove(struct spi_device *spi)
{
kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver ak7755_spi_driver = {
.driver = {
.name = "ak7755",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(ak7755_if_dt_ids),
#endif
},
.probe = ak7755_spi_probe,
.remove = ak7755_spi_remove,
};
#endif
static int __init ak7755_modinit(void)
{
int ret = 0;
akdbgprt("\t[AK7755] %s(%d)\n", __FUNCTION__,__LINE__);
#ifdef AK7755_I2C_IF
ret = i2c_add_driver(&ak7755_i2c_driver);
if ( ret != 0 ) {
printk(KERN_ERR "Failed to register AK7755 I2C driver: %d\n", ret);
}
#else
ret = spi_register_driver(&ak7755_spi_driver);
if ( ret != 0 ) {
printk(KERN_ERR "Failed to register AK7755 SPI driver: %d\n", ret);
}
#endif
#ifdef AK7755_IO_CONTROL
ret = misc_register(&ak7755_misc);
if (ret < 0) {
printk(KERN_ERR "Failed to register AK7755 MISC driver: %d\n", ret);
}
#endif
return ret;
}
module_init(ak7755_modinit);
static void __exit ak7755_exit(void)
{
#ifdef AK7755_I2C_IF
i2c_del_driver(&ak7755_i2c_driver);
#else
spi_unregister_driver(&ak7755_spi_driver);
#endif
#ifdef AK7755_IO_CONTROL
misc_deregister(&ak7755_misc);
#endif
}
module_exit(ak7755_exit);
MODULE_AUTHOR("Junichi Wakasugi <wakasugi.jb@om.asahi-kasei.co.jp>");
MODULE_DESCRIPTION("ASoC ak7755 codec driver");
MODULE_LICENSE("GPL");