blob: 1e5777d44c15b261a2435dae730f2d67408c5335 [file] [log] [blame]
/*
* zx297520v3_nau8810.c -- zx297520v3-nau8810 ALSA SoC Audio board driver
*
* Copyright (C) 2022, ZTE Corporation.
*
* Based on smdk_wm8994.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "../codecs/nau8810.h"
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/delay.h>
//#include <sound/tlv.h>
//#include <sound/soc.h>
//#include <sound/jack.h>
//#include <sound/zx29_snd_platform.h>
//#include <mach/iomap.h>
//#include <mach/board.h>
#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include "i2s.h"
#define ZX29_I2S_TOP_LOOP_REG 0x60
#define NAU_CLK_ID 0
#if 1
#define ZXIC_MCLK 26000000
#define ZXIC_PLL_CLKIN_MCLK 0
#define zx_reg_sync_write(v, a) \
do { \
iowrite32(v, a); \
} while (0)
#define zx_read_reg(addr) \
ioread32(addr)
#define zx_write_reg(addr, val) \
zx_reg_sync_write(val, addr)
struct zx29_board_data {
const char *name;
struct device *dev;
int codec_refclk;
int gpio_pwen;
int gpio_pdn;
void __iomem *sys_base_va;
struct pinctrl *p;
struct pinctrl_state *s;
struct pinctrl_state *s_sleep;
};
struct zx29_board_data *s_board = 0;
//#define AON_WIFI_BT_CLK_CFG2 ((volatile unsigned int *)(ZX_TOP_CRM_BASE + 0x94))
/* Default ZX29s */
static struct zx29_board_data zx29_platform_data = {
.codec_refclk = ZXIC_MCLK,
};
static struct platform_device *zx29_snd_device;
static DEFINE_RAW_SPINLOCK(codec_pa_lock);
static int set_path_stauts_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int get_path_stauts_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
#ifdef USE_ALSA_VOICE_FUNC
extern int zDrv_Audio_Printf(void *pFormat, ...);
extern int zDrvVp_GetVol_Wrap(void);
extern int zDrvVp_SetVol_Wrap(int volume);
extern int zDrvVp_GetPath_Wrap(void);
extern int zDrvVp_SetPath_Wrap(int path);
extern int zDrvVp_SetMute_Wrap(bool enable);
extern bool zDrvVp_GetMute_Wrap(void);
extern int zDrvVp_SetTone_Wrap(int toneNum);
static int vp_GetPath(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_SetPath(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_SetVol(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_GetVol(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_SetMute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_GetMute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_SetTone(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int vp_getTone(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int audio_GetPath(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
static int audio_SetPath(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
//static const DECLARE_TLV_DB_SCALE(vp_path_tlv, 0, 300, 0);
static const char * const vpath_in_text[] = {
"handset", "speak", "headset", "bluetooth",
};
static const char *tone_class[] = {
"Lowpower", "Sms", "Callstd", "Alarm", "Calltime",
};
static const struct soc_enum vpath_in_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(vpath_in_text), vpath_in_text);
static const struct soc_enum tone_class_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tone_class), tone_class),
};
static const struct snd_kcontrol_new vp_snd_controls[] = {
SOC_ENUM_EXT("voice processing path select",vpath_in_enum,vp_GetPath,vp_SetPath),
//SOC_SINGLE_EXT_TLV("voice processing path Volume",0, 5, 5, 0,vp_GetVol, vp_SetVol,vp_path_tlv),
SOC_SINGLE_EXT("voice processing path Volume",0, 5, 5, 0,vp_GetVol, vp_SetVol),
SOC_SINGLE_EXT("voice uplink mute", 0, 1, 1, 0,vp_GetMute, vp_SetMute),
SOC_ENUM_EXT("voice tone sel", tone_class_enum[0], vp_getTone, vp_SetTone),
SOC_SINGLE_BOOL_EXT("path stauts dump", 0,get_path_stauts_switch, set_path_stauts_switch),
SOC_ENUM_EXT("audio path select",vpath_in_enum,audio_GetPath,audio_SetPath),
};
static int curtonetype = 0;
static int vp_getTone(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = curtonetype;
return 0;
}
static int vp_SetTone(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
int vol = 0,ret = 0, tonenum;
tonenum = ucontrol->value.integer.value[0];
curtonetype = tonenum;
//printk("Alsa vp_SetTone tonenum=%d\n", tonenum);
//ret = CPPS_FUNC(cpps_callbacks, zDrvVp_SetTone_Wrap)(tonenum);
if(ret < 0)
{
printk(KERN_ERR "vp_SetTone fail = %d\n", tonenum);
return ret;
}
return 0;
}
static int vp_SetMute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
int enable = 0,ret = 0;
enable = ucontrol->value.integer.value[0];
//ret = CPPS_FUNC(cpps_callbacks, zDrvVp_SetMute_Wrap)(enable);
if(ret < 0)
{
printk(KERN_ERR "vp_SetMute fail = %d\n",enable);
return ret;
}
return 0;
}
static int vp_GetMute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
//ucontrol->value.integer.value[0] = CPPS_FUNC(cpps_callbacks, zDrvVp_GetMute_Wrap)();
return 0;
}
static int vp_SetVol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int vol = 0,ret = 0;
vol = ucontrol->value.integer.value[0];
//ret = CPPS_FUNC(cpps_callbacks, zDrvVp_SetVol_Wrap)(vol);
if(ret < 0)
{
printk(KERN_ERR "vp_SetVol fail = %d\n",vol);
return ret;
}
return 0;
}
static int vp_GetVol(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
//ucontrol->value.integer.value[0] = CPPS_FUNC(cpps_callbacks, zDrvVp_GetVol_Wrap)();
return 0;
}
static int vp_GetPath(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
//ucontrol->value.enumerated.item[0] = CPPS_FUNC(cpps_callbacks, zDrvVp_GetPath_Wrap)();
return 0;
}
static int vp_SetPath(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int ret = 0,path = 0;
unsigned long flags;
path = ucontrol->value.enumerated.item[0];
//ret = CPPS_FUNC(cpps_callbacks, zDrvVp_SetPath_Wrap)(path);
if(ret < 0)
{
printk(KERN_ERR "vp_SetPath fail = %d\n",path);
return ret;
}
#ifdef _USE_7520V3_PHONE_TYPE_C31F
switch (path) {
case 0:
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
mdelay(1);
gpio_set_value(ZX29_GPIO_40, GPIO_LOW);
break;
case 1:
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
mdelay(1);
raw_spin_lock_irqsave(&codec_pa_lock, flags);
gpio_set_value(ZX29_GPIO_39, GPIO_HIGH);
udelay(2);
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
udelay(2);
gpio_set_value(ZX29_GPIO_39, GPIO_HIGH);
raw_spin_unlock_irqrestore(&codec_pa_lock, flags);
gpio_set_value(ZX29_GPIO_40, GPIO_HIGH);
break;
case 2:
break;
case 3:
break;
default:
break;
}
#endif
return 0;
}
static int curpath = 0;
static int audio_GetPath(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = curpath;
return 0;
}
static int audio_SetPath(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int ret = 0,path = 0;
unsigned long flags;
path = ucontrol->value.enumerated.item[0];
curpath = path;
#ifdef _USE_7520V3_PHONE_TYPE_C31F
switch (path) {
case 0:
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
mdelay(1);
gpio_set_value(ZX29_GPIO_40, GPIO_LOW);
break;
case 1:
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
mdelay(1);
raw_spin_lock_irqsave(&codec_pa_lock, flags);
gpio_set_value(ZX29_GPIO_39, GPIO_HIGH);
udelay(2);
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
udelay(2);
gpio_set_value(ZX29_GPIO_39, GPIO_HIGH);
raw_spin_unlock_irqrestore(&codec_pa_lock, flags);
gpio_set_value(ZX29_GPIO_40, GPIO_HIGH);
break;
case 2:
break;
case 3:
break;
default:
break;
}
#endif
return 0;
}
typedef enum
{
VP_PATH_HANDSET =0,
VP_PATH_SPEAKER,
VP_PATH_HEADSET,
VP_PATH_BLUETOOTH,
VP_PATH_BLUETOOTH_NO_NR,
VP_PATH_HSANDSPK,
VP_PATH_OFF = 255,
MAX_VP_PATH = VP_PATH_OFF
}T_ZDrv_VpPath;
extern int zDrvVp_Loop(T_ZDrv_VpPath path);
//#else
static const struct snd_kcontrol_new machine_snd_controls[] = {
SOC_SINGLE_BOOL_EXT("path stauts dump", 0,get_path_stauts_switch, set_path_stauts_switch),
};
//extern int rt5670_hs_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
int path_stauts_switch = 0;
static int set_path_stauts_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_path *p;
int path_stauts_switch = ucontrol->value.integer.value[0];
if (path_stauts_switch == 1)
{
list_for_each_entry(p, &card->paths, list){
//print_audio("Alsa path name (%s),longname (%s),sink (%s),source (%s),connect %d \n", p->name,p->long_name,p->sink->name,p->source->name,p->connect);
//printk("Alsa path longname %s,sink %s,source %s,connect %d \n", p->long_name,p->sink->name,p->source->name,p->connect);
}
}
return 0;
}
static int get_path_stauts_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = path_stauts_switch;
return 0;
};
#endif
#ifdef CONFIG_SND_SOC_JACK_DECTEC
static struct snd_soc_jack codec_headset;
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin codec_headset_pins[] = {
{
.pin = "Headphone",
.mask = SND_JACK_HEADPHONE,
},
};
#endif
static int zx29startup(struct snd_pcm_substream *substream)
{
// int ret = 0;
print_audio("Alsa Entered func %s\n", __func__);
//CPPS_FUNC(cpps_callbacks, zDrv_Audio_Printf)("Alsa: zx29_startup device=%d,stream=%d\n", substream->pcm->device, substream->stream);
struct snd_pcm *pcmC0D0p = snd_lookup_minor_data(16, SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
struct snd_pcm *pcmC0D1p = snd_lookup_minor_data(17, SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
struct snd_pcm *pcmC0D2p = snd_lookup_minor_data(18, SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
struct snd_pcm *pcmC0D3p = snd_lookup_minor_data(19, SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
if ((pcmC0D0p == NULL) || (pcmC0D1p == NULL) || (pcmC0D2p == NULL) || (pcmC0D3p == NULL))
return -EINVAL;
if ((pcmC0D0p->streams[0].substream_opened && pcmC0D1p->streams[0].substream_opened) ||
(pcmC0D0p->streams[0].substream_opened && pcmC0D2p->streams[0].substream_opened) ||
(pcmC0D0p->streams[0].substream_opened && pcmC0D3p->streams[0].substream_opened) ||
(pcmC0D1p->streams[0].substream_opened && pcmC0D2p->streams[0].substream_opened) ||
(pcmC0D1p->streams[0].substream_opened && pcmC0D3p->streams[0].substream_opened) ||
(pcmC0D2p->streams[0].substream_opened && pcmC0D3p->streams[0].substream_opened))
BUG();
#if 0
unsigned long flags;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
mdelay(1);
raw_spin_lock_irqsave(&codec_pa_lock, flags);
gpio_set_value(ZX29_GPIO_125, GPIO_HIGH);
udelay(2);
gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
udelay(2);
gpio_set_value(ZX29_GPIO_125, GPIO_HIGH);
udelay(2);
gpio_set_value(ZX29_GPIO_125, GPIO_LOW);
udelay(2);
gpio_set_value(ZX29_GPIO_125, GPIO_HIGH);
raw_spin_unlock_irqrestore(&codec_pa_lock, flags);
}
#endif
return 0;
}
static void zx29_shutdown(struct snd_pcm_substream *substream)
{
//CPPS_FUNC(cpps_callbacks, zDrv_Audio_Printf)("Alsa: zx297520xx_shutdown device=%d, stream=%d\n", substream->pcm->device, substream->stream);
// print_audio("Alsa Entered func %s, stream=%d\n", __func__, substream->stream);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
#ifdef _USE_7520V3_PHONE_TYPE_C31F
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
mdelay(1);
gpio_set_value(ZX29_GPIO_40, GPIO_LOW);
#endif
}
if (snd_soc_dai_active(cpu_dai))
return;
}
static void zx29_shutdown2(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
//CPPS_FUNC(cpps_callbacks, zDrv_Audio_Printf)("Alsa: zx29_shutdown2 device=%d, stream=%d\n", substream->pcm->device, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
#ifdef _USE_7520V3_PHONE_TYPE_C31F
gpio_set_value(ZX29_GPIO_39, GPIO_LOW);
mdelay(1);
gpio_set_value(ZX29_GPIO_40, GPIO_LOW);
#endif
#ifdef USE_ALSA_VOICE_FUNC
//CPPS_FUNC(cpps_callbacks, zDrvVp_Loop)(VP_PATH_OFF);
#endif
}
if (snd_soc_dai_active(cpu_dai))
return;
}
static int zx29_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
//struct snd_soc_codec *codec = rtd->codec;
//struct snd_soc_dapm_context *dapm = &codec->dapm;
//snd_soc_dapm_enable_pin(dapm, "HPOL");
//snd_soc_dapm_enable_pin(dapm, "HPOR");
/* Other pins NC */
// snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
// print_audio("Alsa Entered func %s\n", __func__);
return 0;
}
static int zx29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
print_audio("Alsa: Entered func %s\n", __func__);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
int rfs = 0, frq_out = 0;
switch (params_rate(params)) {
case 8000:
case 16000:
case 11025:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
rfs = 32;
break;
default:
{
ret = -EINVAL;
print_audio("Alsa: rate=%d not support,ret=%d!\n", params_rate(params),ret);
return ret;
}
}
frq_out = params_rate(params) * rfs * 2;
/* Set the Codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
/* Set the AP DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: ap dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8810_SCLK_PLL, ZXIC_MCLK, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
/* Set the Codec DAI clk */
ret =snd_soc_dai_set_pll(codec_dai, 0, NAU8810_SCLK_PLL,
ZXIC_MCLK, params_rate(params)*256);
if (ret < 0){
print_audio("Alsa: codec dai clk snd_soc_dai_set_pll fail,ret=%d!\n",ret);
return ret;
}
/* Set the AP DAI clk */
ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_26M, SND_SOC_CLOCK_IN);
//ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_26M, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: cpu dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
print_audio("Alsa: Entered func %s end\n", __func__);
return 0;
}
static int zx29_hw_params_lp(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
print_audio("Alsa: Entered func %s\n", __func__);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
int rfs = 0, frq_out = 0;
switch (params_rate(params)) {
case 8000:
case 16000:
case 11025:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
rfs = 32;
break;
default:
{
ret = -EINVAL;
print_audio("Alsa: rate=%d not support,ret=%d!\n", params_rate(params),ret);
return ret;
}
}
frq_out = params_rate(params) * rfs * 2;
/* Set the Codec DAI configuration */
/*
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
*/
/* Set the AP DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: ap dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
/* Set the Codec DAI clk */
/*ret =snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_BCLK1,
fs*datawidth*2, 256*fs);
if (ret < 0){
print_audio("Alsa: codec dai clk snd_soc_dai_set_pll fail,ret=%d!\n",ret);
return ret;
}
*/
/*
ret = snd_soc_dai_set_sysclk(codec_dai, ES8312_CLKID_MCLK,ZXIC_MCLK, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
*/
/* Set the AP DAI clk */
ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_26M, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: cpu dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
print_audio("Alsa: Entered func %s end\n", __func__);
return 0;
}
static int zx29_hw_params_voice(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
print_audio("Alsa: Entered func %s\n", __func__);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
int rfs = 0, frq_out = 0;
switch (params_rate(params)) {
case 8000:
case 16000:
case 11025:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
rfs = 32;
break;
default:
{
ret = -EINVAL;
print_audio("Alsa: rate=%d not support,ret=%d!\n", params_rate(params),ret);
return ret;
}
}
frq_out = params_rate(params) * rfs * 2;
/* Set the Codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8810_SCLK_MCLK, ZXIC_MCLK, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8810_SCLK_PLL, ZXIC_MCLK, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
/* Set the Codec DAI clk */
ret =snd_soc_dai_set_pll(codec_dai, 0, NAU8810_SCLK_PLL,
ZXIC_MCLK, params_rate(params)*256);
if (ret < 0){
print_audio("Alsa: codec dai clk snd_soc_dai_set_pll fail,ret=%d!\n",ret);
return ret;
}
print_audio("Alsa: Entered func %s end\n", __func__);
return 0;
}
static int zx29_hw_params_tdm(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
print_audio("Alsa: Entered func %s\n", __func__);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
int rfs = 0, frq_out = 0;
switch (params_rate(params)) {
case 8000:
case 16000:
case 11025:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
rfs = 32;
break;
default:
{
ret = -EINVAL;
print_audio("Alsa: rate=%d not support,ret=%d!\n", params_rate(params),ret);
return ret;
}
}
//frq_out = params_rate(params) * rfs * 2;
/* Set the Codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
/* Set the AP DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: ap dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8810_SCLK_MCLK, params_rate(params)*256, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
/* Set the AP DAI clk */
//ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_26M, SND_SOC_CLOCK_IN);
ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_104M, SND_SOC_CLOCK_IN);
//ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_122M88, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: cpu dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
print_audio("Alsa: Entered func %s end\n", __func__);
return 0;
}
static int zx29_hw_params_lp_tdm(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
print_audio("Alsa: Entered func %s\n", __func__);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
int rfs = 0, frq_out = 0;
switch (params_rate(params)) {
case 8000:
case 16000:
case 11025:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
rfs = 32;
break;
default:
{
ret = -EINVAL;
print_audio("Alsa: rate=%d not support,ret=%d!\n", params_rate(params),ret);
return ret;
}
}
//frq_out = params_rate(params) * rfs * 2;
/* Set the Codec DAI configuration */
/*
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
*/
/* Set the AP DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: ap dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
/* Set the Codec DAI clk */
/*ret =snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_BCLK1,
fs*datawidth*2, 256*fs);
if (ret < 0){
print_audio("Alsa: codec dai clk snd_soc_dai_set_pll fail,ret=%d!\n",ret);
return ret;
}
*/
/*
ret = snd_soc_dai_set_sysclk(codec_dai, ES8312_CLKID_MCLK,ZXIC_MCLK, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
*/
/* Set the AP DAI clk */
//ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_26M, SND_SOC_CLOCK_IN);
ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_104M, SND_SOC_CLOCK_IN);
//ret = snd_soc_dai_set_sysclk(cpu_dai, ZX29_I2S_WCLK_SEL,ZX29_I2S_WCLK_FREQ_122M88, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: cpu dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
print_audio("Alsa: Entered func %s end\n", __func__);
return 0;
}
static int zx29_hw_params_voice_tdm(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
print_audio("Alsa: Entered func %s\n", __func__);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
int ret;
int rfs = 0, frq_out = 0;
switch (params_rate(params)) {
case 8000:
case 16000:
case 11025:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
rfs = 32;
break;
default:
{
ret = -EINVAL;
print_audio("Alsa: rate=%d not support,ret=%d!\n", params_rate(params),ret);
return ret;
}
}
frq_out = params_rate(params) * rfs * 2;
/* Set the Codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_fmt fail,ret=%d!\n",ret);
return ret;
}
//ret = snd_soc_dai_set_sysclk(codec_dai, NAU8810_SCLK_PLL, ZXIC_MCLK, SND_SOC_CLOCK_IN);
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8810_SCLK_MCLK, params_rate(params)*256, SND_SOC_CLOCK_IN);
if (ret < 0){
print_audio("Alsa: codec dai snd_soc_dai_set_sysclk fail,ret=%d!\n",ret);
return ret;
}
print_audio("Alsa: Entered func %s end\n", __func__);
return 0;
}
int zx29_prepare2(struct snd_pcm_substream *substream)
{
int path, ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
//ret = CPPS_FUNC(cpps_callbacks, zDrvVp_Loop)(VP_PATH_SPEAKER);
if (ret < 0)
return -1;
}
return 0;
}
static int zx29_late_probe(struct snd_soc_card *card)
{
//struct snd_soc_codec *codec = card->rtd[0].codec;
//struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
int ret;
// print_audio("Alsa zx29_late_probe entry!\n");
#ifdef CONFIG_SND_SOC_JACK_DECTEC
ret = snd_soc_jack_new(codec, "Headset",
SND_JACK_HEADSET |SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
&codec_headset);
if (ret)
return ret;
ret = snd_soc_jack_add_pins(&codec_headset,
ARRAY_SIZE(codec_headset_pins),
codec_headset_pins);
if (ret)
return ret;
#ifdef CONFIG_SND_SOC_codec
//rt5670_hs_detect(codec, &codec_headset);
#endif
#endif
return 0;
}
static struct snd_soc_ops zx29_ops = {
//.startup = zx29_startup,
.shutdown = zx29_shutdown,
#ifdef CONFIG_USE_TOP_TDM
.hw_params = zx29_hw_params_tdm,
#else
.hw_params = zx29_hw_params,
#endif
};
static struct snd_soc_ops zx29_ops_lp = {
//.startup = zx29_startup,
.shutdown = zx29_shutdown,
#ifdef CONFIG_USE_TOP_TDM
.hw_params = zx29_hw_params_lp_tdm,
#else
.hw_params = zx29_hw_params_lp,
#endif
};
static struct snd_soc_ops zx29_ops1 = {
//.startup = zx29_startup,
.shutdown = zx29_shutdown,
//.hw_params = zx29_hw_params1,
};
static struct snd_soc_ops zx29_ops2 = {
//.startup = zx29_startup,
.shutdown = zx29_shutdown2,
//.hw_params = zx29_hw_params1,
.prepare = zx29_prepare2,
};
static struct snd_soc_ops voice_ops = {
.startup = zx29startup,
.shutdown = zx29_shutdown2,
#ifdef CONFIG_USE_TOP_TDM
.hw_params = zx29_hw_params_voice_tdm,
#else
.hw_params = zx29_hw_params_voice,
#endif
//.prepare = zx29_prepare2,
};
enum {
MERR_DPCM_AUDIO = 0,
MERR_DPCM_DEEP_BUFFER,
MERR_DPCM_COMPR,
};
#if 0
static struct snd_soc_card zxic_soc_card = {
.name = "zx29_nau8810",
.owner = THIS_MODULE,
.dai_link = &zxic_dai_link,
.num_links = ARRAY_SIZE(zxic_dai_link),
#ifdef USE_ALSA_VOICE_FUNC
.controls = vp_snd_controls,
.num_controls = ARRAY_SIZE(vp_snd_controls),
#endif
// .late_probe = zx29_late_probe,
};
#endif
static int zx29_setup_pins(struct zx29_board_data *codec_pins, char *fun)
{
int ret;
//ret = gpio_request(codec_pins->codec_refclk, "codec_refclk");
if (ret < 0) {
printk(KERN_ERR "zx297520xx SoC Audio: %s pin already in use\n", fun);
return ret;
}
//zx29_gpio_config(codec_pins->codec_refclk, GPIO17_CLK_OUT2);
#ifdef _USE_7520V3_PHONE_TYPE_C31F
ret = gpio_request_one(ZX29_GPIO_39, GPIOF_OUT_INIT_LOW, "codec_pa");
if (ret < 0) {
printk(KERN_ERR "zx297520xx SoC Audio: codec_pa in use\n");
return ret;
}
ret = gpio_request_one(ZX29_GPIO_40, GPIOF_OUT_INIT_LOW, "codec_sw");
if (ret < 0) {
printk(KERN_ERR "zx297520xx SoC Audio: codec_sw in use\n");
return ret;
}
#endif
return 0;
}
#endif
static int zx29_remove(struct platform_device *pdev)
{
gpio_free(zx29_platform_data.codec_refclk);
platform_device_unregister(zx29_snd_device);
return 0;
}
#if 0
/*
* Default CFG switch settings to use this driver:
* ZX29
*/
/*
* Configure audio route as :-
* $ amixer sset 'DAC1' on,on
* $ amixer sset 'Right Headphone Mux' 'DAC'
* $ amixer sset 'Left Headphone Mux' 'DAC'
* $ amixer sset 'DAC1R Mixer AIF1.1' on
* $ amixer sset 'DAC1L Mixer AIF1.1' on
* $ amixer sset 'IN2L' on
* $ amixer sset 'IN2L PGA IN2LN' on
* $ amixer sset 'MIXINL IN2L' on
* $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on
* $ amixer sset 'IN2R' on
* $ amixer sset 'IN2R PGA IN2RN' on
* $ amixer sset 'MIXINR IN2R' on
* $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on
*/
/* ZX29 has a 16.934MHZ crystal attached to nau8810 */
#define ZX29_CODEC_FREQ 16934000
static int zx29_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
unsigned int pll_out;
int ret;
/* AIF1CLK should be >=3MHz for optimal performance */
if (params_width(params) == 24)
pll_out = params_rate(params) * 384;
else if (params_rate(params) == 8000 || params_rate(params) == 11025)
pll_out = params_rate(params) * 512;
else
pll_out = params_rate(params) * 256;
ret = snd_soc_dai_set_pll(codec_dai, AK4940_FLL1, AK4940_FLL_SRC_MCLK1,
ZX29_AK4940_FREQ, pll_out);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(codec_dai, AK4940_SYSCLK_FLL1,
pll_out, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
return 0;
}
/*
* ZX29 AK4940 DAI operations.
*/
static struct snd_soc_ops zx29_ops = {
.hw_params = smdk_hw_params,
};
static int zx29_codec_init_paiftx(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
/* Other pins NC */
snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
snd_soc_dapm_nc_pin(dapm, "SPKOUTLN");
snd_soc_dapm_nc_pin(dapm, "SPKOUTLP");
snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
snd_soc_dapm_nc_pin(dapm, "SPKOUTRN");
snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
snd_soc_dapm_nc_pin(dapm, "IN1LP");
snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
snd_soc_dapm_nc_pin(dapm, "IN1RP");
snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
return 0;
}
#endif
enum {
AUDIO_DL_MEDIA = 0,
AUDIO_DL_VOICE,
AUDIO_DL_2G_AND_3G_VOICE,
AUDIO_DL_VP_LOOP,
AUDIO_DL_3G_VOICE,
AUDIO_DL_MAX,
};
SND_SOC_DAILINK_DEF(dummy, \
DAILINK_COMP_ARRAY(COMP_DUMMY()));
//SND_SOC_DAILINK_DEF(cpu_i2s0, \
// DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
SND_SOC_DAILINK_DEF(cpu_i2s0, \
DAILINK_COMP_ARRAY(COMP_CPU("1405000.i2s")));
SND_SOC_DAILINK_DEF(cpu_tdm, \
DAILINK_COMP_ARRAY(COMP_CPU("1412000.tdm")));
SND_SOC_DAILINK_DEF(voice_cpu, \
DAILINK_COMP_ARRAY(COMP_CPU("soc:voice_audio")));
SND_SOC_DAILINK_DEF(voice_2g_3g, \
DAILINK_COMP_ARRAY(COMP_CPU("voice_2g_3g-dai")));
SND_SOC_DAILINK_DEF(voice_3g, \
DAILINK_COMP_ARRAY(COMP_CPU("voice_3g-dai")));
//SND_SOC_DAILINK_DEF(nau8810, \
// DAILINK_COMP_ARRAY(COMP_CODEC("nau8810.1-0012", "nau8810-aif")));
SND_SOC_DAILINK_DEF(dummy_cpu, \
DAILINK_COMP_ARRAY(COMP_CPU("soc:zx29_snd_dummy")));
//SND_SOC_DAILINK_DEF(dummy_platform, \
// DAILINK_COMP_ARRAY(COMP_PLATFORM("soc:zx29_snd_dummy")));
SND_SOC_DAILINK_DEF(dummy_codec, \
DAILINK_COMP_ARRAY(COMP_CODEC("soc:zx29_snd_dummy", "zx29_snd_dummy_dai")));
SND_SOC_DAILINK_DEF(nau8810_codec, \
DAILINK_COMP_ARRAY(COMP_CODEC("nau8810.1-001a", "nau8810-hifi")));
//SND_SOC_DAILINK_DEF(media_platform, \
// DAILINK_COMP_ARRAY(COMP_PLATFORM("zx29-pcm-audio")));
SND_SOC_DAILINK_DEF(media_platform, \
DAILINK_COMP_ARRAY(COMP_PLATFORM("1405000.i2s")));
SND_SOC_DAILINK_DEF(media_platform_tdm, \
DAILINK_COMP_ARRAY(COMP_PLATFORM("1412000.tdm")));
//SND_SOC_DAILINK_DEF(voice_cpu, \
// DAILINK_COMP_ARRAY(COMP_CPU("E1D02000.i2s")));
SND_SOC_DAILINK_DEF(voice_platform, \
DAILINK_COMP_ARRAY(COMP_PLATFORM("soc:voice_audio")));
//static struct snd_soc_dai_link zx29_dai_link[] = {
struct snd_soc_dai_link zx29_dai_link[] = {
{
.name = "zx29_snd_dummy",//codec name
.stream_name = "zx29_snd_dumy",
//.nonatomic = true,
//.dynamic = 1,
//.dpcm_playback = 1,
.ops = &zx29_ops_lp,
.init = zx29_init_paiftx,
#ifdef CONFIG_USE_TOP_TDM
SND_SOC_DAILINK_REG(cpu_tdm, dummy_codec, media_platform_tdm),
#else
SND_SOC_DAILINK_REG(cpu_i2s0, dummy_codec, media_platform),
#endif
},
#if 1
{
.name = "media",//codec name
.stream_name = "MultiMedia",
//.nonatomic = true,
//.dynamic = 1,
//.dpcm_playback = 1,
.ops = &zx29_ops,
.init = zx29_init_paiftx,
#ifdef CONFIG_USE_TOP_TDM
SND_SOC_DAILINK_REG(cpu_tdm, nau8810_codec, media_platform_tdm),
#else
SND_SOC_DAILINK_REG(cpu_i2s0, nau8810_codec, media_platform),
#endif
},
{
.name = "voice",//codec name
.stream_name = "voice",
//.nonatomic = true,
//.dynamic = 1,
//.dpcm_playback = 1,
.ops = &voice_ops,
.init = zx29_init_paiftx,
SND_SOC_DAILINK_REG(voice_cpu, nau8810_codec, voice_platform),
},
{
.name = "voice_2g3g_teak",//codec name
.stream_name = "voice_2g3g_teak",
//.nonatomic = true,
//.dynamic = 1,
//.dpcm_playback = 1,
.ops = &voice_ops,
.init = zx29_init_paiftx,
SND_SOC_DAILINK_REG(voice_cpu, nau8810_codec, voice_platform),
},
{
.name = "voice_3g",//codec name
.stream_name = "voice_3g",
//.nonatomic = true,
//.dynamic = 1,
//.dpcm_playback = 1,
.ops = &voice_ops,
.init = zx29_init_paiftx,
SND_SOC_DAILINK_REG(voice_cpu, nau8810_codec, voice_platform),
},
{
.name = "loop_test",//codec name
.stream_name = "loop_test",
//.nonatomic = true,
//.dynamic = 1,
//.dpcm_playback = 1,
//.ops = &zx29_ops,
.ops = &voice_ops,
.init = zx29_init_paiftx,
SND_SOC_DAILINK_REG(voice_cpu, nau8810_codec, dummy),
},
#endif
};
static struct snd_soc_card zx29_soc_card = {
.name = "zx29-sound-card",
.owner = THIS_MODULE,
.dai_link = zx29_dai_link,
.num_links = ARRAY_SIZE(zx29_dai_link),
#ifdef USE_ALSA_VOICE_FUNC
.controls = vp_snd_controls,
.num_controls = ARRAY_SIZE(vp_snd_controls),
#endif
};
static const struct of_device_id zx29_nau8810_of_match[] = {
{ .compatible = "zxic,zx29_nau8810", .data = &zx29_platform_data },
{},
};
MODULE_DEVICE_TABLE(of, zx29_nau8810_of_match);
static void zx29_i2s_top_pin_cfg(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pinctrl *p;
struct pinctrl_state *s;
struct pinctrl_state *s_sleep;
int ret = 0;
printk("%s start \n",__func__);
struct resource *res;
void __iomem *reg_base;
unsigned int val;
struct zx29_board_data *info = s_board;
pr_info("%s: board name(%s)!\n", __func__,info->name);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "soc_sys");
if (!res) {
dev_err(dev, "Reg region missing (%s)\n", "soc_sys");
//return -ENXIO;
}
#if 0
reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR(reg_base )) {
dev_err(dev, "Reg region ioremap (%s) err=%li\n", "soc_sys",PTR_ERR(reg_base ));
//return PTR_ERR(reg_base );
}
#else
reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
#endif
//#if 1 //CONFIG_USE_PIN_I2S0
#if defined(CONFIG_USE_TOP_I2S0)
dev_info(dev, "%s: arm i2s1 to top i2s0!!\n", __func__);
//9300
//top i2s1 cfg
val = zx_read_reg(reg_base+ZX29_I2S_TOP_LOOP_REG);
val &= ~(0x7<<0);
val |= 0x1<<0; // inter arm_i2s1--top i2s1
zx_write_reg(reg_base+ZX29_I2S_TOP_LOOP_REG, val);
#elif defined(CONFIG_USE_TOP_I2S1)//defined(CONFIG_USE_PIN_I2S1)
//8501evb
dev_info(dev, "%s: arm i2s1 to top i2s1!\n", __func__);
//top i2s2 cfg
val = zx_read_reg(reg_base+ZX29_I2S_TOP_LOOP_REG);
//val &= 0xfffffff8;
val &= ~(0x7<<16);
val |= 0x1<<16;// inter arm_i2s1--top i2s2
zx_write_reg(reg_base+ZX29_I2S_TOP_LOOP_REG, val);
#endif
p = devm_pinctrl_get(dev);
if (IS_ERR(p)) {
dev_err(dev, "%s: pinctrl get failure ,p=0x%llx,dev=0x%llx!!\n", __func__,p,dev);
return;
}
dev_info(dev, "%s: get pinctrl ,p=0x%llx,dev=0x%llx!!\n", __func__,p,dev);
#if defined(CONFIG_USE_TOP_I2S0)
dev_info(dev, "%s: top_i2s0 pinctrl sel!!\n", __func__);
s = pinctrl_lookup_state(p, "top_i2s0");
if (IS_ERR(s)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
dev_info(dev, "%s: get top_i2s sleep pinctrl sel!!\n", __func__);
s_sleep = pinctrl_lookup_state(p, "topi2s0_sleep");
if (IS_ERR(s_sleep)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
#elif defined(CONFIG_USE_TOP_I2S1)
dev_info(dev, "%s: top_i2s1 pinctrl sel!!\n", __func__);
s = pinctrl_lookup_state(p, "top_i2s1");
if (IS_ERR(s)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
dev_info(dev, "%s: get top_i2s sleep pinctrl sel!!\n", __func__);
s_sleep = pinctrl_lookup_state(p, "topi2s1_sleep");
if (IS_ERR(s_sleep)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
#elif defined(CONFIG_USE_TOP_TDM)
dev_info(dev, "%s: top_tdm pinctrl sel!!\n", __func__);
s = pinctrl_lookup_state(p, "top_tdm");
if (IS_ERR(s)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
dev_info(dev, "%s: get top_i2s sleep pinctrl sel!!\n", __func__);
s_sleep = pinctrl_lookup_state(p, "toptdm_sleep");
if (IS_ERR(s_sleep)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
#else
dev_info(dev, "%s: default top_i2s pinctrl sel!!\n", __func__);
s = pinctrl_lookup_state(p, "top_i2s0");
if (IS_ERR(s)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
dev_info(dev, "%s: get top_i2s sleep pinctrl sel!!\n", __func__);
s_sleep = pinctrl_lookup_state(p, "topi2s0_sleep");
if (IS_ERR(s_sleep)) {
devm_pinctrl_put(p);
dev_err(dev, " get state failure!!\n");
return;
}
#endif
if(info != NULL){
info->p = p;
info->s = s;
info->s_sleep = s_sleep;
}
ret = pinctrl_select_state(p, s);
if (ret < 0) {
devm_pinctrl_put(p);
dev_err(dev, " select state failure!!\n");
return;
}
dev_info(dev, "%s: set pinctrl end!\n", __func__);
}
#ifdef CONFIG_PA_SA51034
//sa51034
#define SA51034_DEBUG
#define SA51034_01_LATCHED_FAULT 0x01
#define SA51034_02_STATUS_LOAD_DIAGNOSTIC 0x02
#define SA51034_03_CONTROL 0x03
#define SA51034_MAX_REGISTER SA51034_03_CONTROL
struct sa51034_priv {
struct i2c_client *i2c;
struct regmap *regmap;
int pwen_gpio;//add new
int mute_gpio;
int fs;
};
static int sa51034_set_mute(struct sa51034_priv *sa51034,int mute);
static int sa51034_get_mute(struct sa51034_priv *sa51034,int *mute);
struct sa51034_priv *g_sa51034 = NULL;
/* ak4940 register cache & default register settings */
static const struct reg_default sa51034_reg[] = {
{ 0x01, 0x00 }, /* SA51034_00_LATCHED_FAULT */
{ 0x02, 0x00 }, /* SA51034_01_STATUS_LOAD_DIAGNOSTIC */
{ 0x03, 0x00 }, /* SA51034_02_CONTROL */
};
static const char * const pa_gain_select_texts[] = {
"20dB", "26dB","30dB", "36dB",
};
static const char * const power_limit_select_texts[] = {
"PL-5V", "PL-5.9V","PL-7V", "PL-8.4V","PL-9.8V", "PL-11.8V","PL-14V", "PL-disV",
};
static const struct soc_enum pa_gain_enum[] = {
SOC_ENUM_SINGLE(SA51034_03_CONTROL, 6,
ARRAY_SIZE(pa_gain_select_texts), pa_gain_select_texts),
};
static const struct soc_enum power_limit_enum[] = {
SOC_ENUM_SINGLE(SA51034_03_CONTROL, 3,
ARRAY_SIZE(power_limit_select_texts), power_limit_select_texts),
};
static const char * const reg_select[] = {
"read PA Reg 01:03",
};
static const struct soc_enum pa_enum2[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(reg_select),reg_select),
};
static int get_reg(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component;
struct device *dev;
u32 currMode = ucontrol->value.enumerated.item[0];
int i, ret;
int regs, rege;
unsigned int value;
if(g_sa51034 == NULL){
pr_err("g_sa51034 null return %s\n", __func__);
return -1;
}
dev = &g_sa51034->i2c->dev;
component = snd_soc_lookup_component(dev, NULL);
regs = 0x1;
rege = 0x4;
for (i = regs; i < rege; i++) {
value = snd_soc_component_read(component, i);
if (value < 0) {
pr_err("pa %s(%d),err value=%d\n", __func__, __LINE__, value);
return value;
}
pr_info("pa 2c_read Addr,Reg=(%x, %x)\n", i, value);
}
return 0;
}
int pa_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
//struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct snd_soc_component *component;
struct device *dev;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, item;
unsigned int reg_val;
int ret;
if(g_sa51034 == NULL){
pr_err("g_sa51034 null return %s\n", __func__);
return -1;
}
dev = &g_sa51034->i2c->dev;
component = snd_soc_lookup_component(dev, NULL);
reg_val = snd_soc_component_read(component, e->reg);
if (reg_val < 0) {
pr_err("pa %s(%d),err reg_val=%d\n", __func__, __LINE__, reg_val);
return reg_val;
}
val = (reg_val >> e->shift_l) & e->mask;
item = snd_soc_enum_val_to_item(e, val);
ucontrol->value.enumerated.item[0] = item;
if (e->shift_l != e->shift_r) {
val = (reg_val >> e->shift_r) & e->mask;
item = snd_soc_enum_val_to_item(e, val);
ucontrol->value.enumerated.item[1] = item;
}
return 0;
}
int pa_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
//struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct snd_soc_component *component;
struct device *dev;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int *item = ucontrol->value.enumerated.item;
unsigned int val;
unsigned int mask;
if(g_sa51034 == NULL){
pr_err("g_sa51034 null return %s\n", __func__);
return -1;
}
dev = &g_sa51034->i2c->dev;
component = snd_soc_lookup_component(dev, NULL);
if (item[0] >= e->items)
return -EINVAL;
val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
mask = e->mask << e->shift_l;
if (e->shift_l != e->shift_r) {
if (item[1] >= e->items)
return -EINVAL;
val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
mask |= e->mask << e->shift_r;
}
return snd_soc_component_update_bits(component, e->reg, mask, val);
}
static int pa_SetMute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
int mute = 0,ret = 0;
if(g_sa51034 == NULL){
pr_err("g_sa51034 null return %s\n", __func__);
return -1;
}
mute = ucontrol->value.integer.value[0];
ret = sa51034_set_mute(g_sa51034,mute);
if(ret < 0)
{
printk(KERN_ERR "sa51034_set_mute fail ret=%d,mute=%d\n",ret,mute);
return ret;
}
return 0;
}
static int pa_GetMute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
int mute = 0,ret = 0;
if(g_sa51034 == NULL){
pr_err("g_sa51034 null return %s\n", __func__);
return -1;
}
ret = sa51034_get_mute(g_sa51034,&mute);
if(ret < 0)
{
printk(KERN_ERR "sa51034_get_mute fail ret= %d\n",ret);
return ret;
}
pr_info("[SA51034] %s mute gpio val=%d,integer.value[0]=%d\n", __func__, mute,ucontrol->value.integer.value[0]);
ucontrol->value.integer.value[0] = mute;
return 0;
}
const struct snd_kcontrol_new pa_controls[] =
{
SOC_ENUM_EXT("PA gain", pa_gain_enum[0], pa_get_enum_double, pa_put_enum_double),
SOC_ENUM_EXT("Power limit", power_limit_enum[0], pa_get_enum_double, pa_put_enum_double),
SOC_ENUM_EXT("PA Reg Read", pa_enum2[0], get_reg, NULL),
SOC_SINGLE_EXT("pa mute", 0, 0, 1, 0,pa_GetMute, pa_SetMute),
};
int pa_controls_size = sizeof(pa_controls) / sizeof(pa_controls[0]);
static bool sa51034_volatile(struct device *dev, unsigned int reg)
{
bool ret;
#ifdef SA51034_DEBUG
ret = true;
#else
ret = false;
#endif
return ret;
}
static bool sa51034_readable(struct device *dev, unsigned int reg)
{
if (reg <= SA51034_MAX_REGISTER)
return true;
else
return false;
}
static bool sa51034_writeable(struct device *dev, unsigned int reg)
{
if (reg <= SA51034_MAX_REGISTER)
return true;
else
return false;
}
static const struct regmap_config sa51034_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SA51034_MAX_REGISTER,
.volatile_reg = sa51034_volatile,
.writeable_reg = sa51034_writeable,
.readable_reg = sa51034_readable,
.reg_defaults = sa51034_reg,
.num_reg_defaults = ARRAY_SIZE(sa51034_reg),
.cache_type = REGCACHE_RBTREE,
};
static const struct snd_soc_component_driver pa_asoc_component = {
.name = "pa_component",
//.controls = pa_controls,
//.num_controls = ARRAY_SIZE(pa_controls),
};
static const struct of_device_id sa51034_i2c_dt_ids[] = {
{ .compatible = "sa51034"},
{ }
};
MODULE_DEVICE_TABLE(of, sa51034_i2c_dt_ids);
static int sa51034_gpio_request(struct sa51034_priv *sa51034)
{
struct device *dev;
struct device_node *np;
int ret;
dev = &(sa51034->i2c->dev);
np = dev->of_node;
if (!np)
return 0;
pr_info( "Read PDN pin from device tree\n");
sa51034->pwen_gpio = of_get_named_gpio(np, "sa51034,ctrl-gpio", 0);
if (sa51034->pwen_gpio < 0) {
pr_err( "sa51034 pwen pin of_get_named_gpio fail\n");
sa51034->pwen_gpio = -1;
return -1;
}
if (!gpio_is_valid(sa51034->pwen_gpio)) {
pr_err( "sa51034 pwen_gpio pin(%u) is invalid\n", sa51034->pwen_gpio);
sa51034->pwen_gpio = -1;
return -1;
}
sa51034->mute_gpio = of_get_named_gpio(np, "sa51034,ctrl-gpio", 1);
if (sa51034->mute_gpio < 0) {
pr_err( "sa51034 mute_gpio pin of_get_named_gpio fail\n");
sa51034->mute_gpio = -1;
return -1;
}
if (!gpio_is_valid(sa51034->mute_gpio)) {
pr_err( "sa51034 mute_gpio pin(%u) is invalid\n", sa51034->mute_gpio);
sa51034->mute_gpio = -1;
return -1;
}
pr_info( "sa51034 get pwen_gpio pin(%u) mute_gpio pin(%u)\n", sa51034->pwen_gpio,sa51034->mute_gpio);
if (sa51034->pwen_gpio != -1) {
ret = devm_gpio_request(dev,sa51034->pwen_gpio, "sa51034 pwen");
if (ret < 0){
pr_err( "sa51034 pwen_gpio request fail,ret=%d\n",ret);
return ret;
}
pr_info("\t[sa51034] %s :pwen_gpio gpio_request ret = %d\n", __func__, ret);
gpio_direction_output(sa51034->pwen_gpio, 0);
}
if (sa51034->mute_gpio != -1) {
ret = devm_gpio_request(dev,sa51034->mute_gpio, "sa51034 mute");
if (ret < 0){
pr_err( "sa51034 mute_gpio request fail,ret=%d\n",ret);
return ret;
}
pr_info("\t[AK4940] %s : mute_gpio gpio_request ret = %d\n", __func__, ret);
gpio_direction_output(sa51034->mute_gpio, 1);
}
return 0;
}
static int sa51034_set_mute(struct sa51034_priv *sa51034,int mute)
{
//struct snd_soc_component *component = dai->component;
//struct ak4940_priv *ak4940 = snd_soc_component_get_drvdata(component);
int ret = 0;
//int ndt;
pr_info("[SA51034] %s mute=%d\n", __func__, mute);
if (sa51034->mute_gpio == -1) {
pr_err( "sa51034 %s mute_gpio invalid return\n",__func__);
return -1;
}
//ndt = 4080000 / sa51034->fs;
if (mute) {
/* SMUTE: 1 , MUTE */
ret = gpio_direction_output(sa51034->mute_gpio, 1);
//mdelay(ndt);
} else{
/* SMUTE: 0 ,NORMAL operation */
ret = gpio_direction_output(sa51034->mute_gpio, 0);
//mdelay(ndt);
}
return ret;
}
static int sa51034_get_mute(struct sa51034_priv *sa51034,int *mute)
{
int ret = 0;
if (sa51034->mute_gpio == -1) {
pr_err( "sa51034 %s mute_gpio invalid return\n",__func__);
return -1;
}
*mute = gpio_get_value(sa51034->mute_gpio);
pr_info("[SA51034] %s mute gpio val=%d\n", __func__, *mute);
return ret;
}
static int sa51034_set_pwen(struct sa51034_priv *sa51034,int en)
{
//struct snd_soc_component *component = dai->component;
//struct ak4940_priv *ak4940 = snd_soc_component_get_drvdata(component);
int ret = 0;
//int ndt;
pr_info("\t[SA51034] %s en[%s]\n", __func__, en ? "ON":"OFF");
if (sa51034->pwen_gpio == -1) {
pr_err( "sa51034 %s pwen_gpio invalid return\n",__func__);
return -1;
}
//ndt = 4080000 / sa51034->fs;
if (en) {
/* SMUTE: 1 , MUTE */
ret = gpio_direction_output(sa51034->pwen_gpio, 1);
//mdelay(ndt);
} else{
/* SMUTE: 0 ,NORMAL operation */
ret = gpio_direction_output(sa51034->pwen_gpio, 0);
//mdelay(ndt);
}
return ret;
}
static int sa51034_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
struct sa51034_priv *sa51034;
int ret = 0;
unsigned int val;
pr_info("\t[sa51034] %s(%d),i2c->addr=0x%x\n", __func__, __LINE__,i2c->addr);
sa51034 = devm_kzalloc(&i2c->dev, sizeof(struct sa51034_priv), GFP_KERNEL);
if (sa51034 == NULL)
return -ENOMEM;
sa51034->regmap = devm_regmap_init_i2c(i2c, &sa51034_regmap);
if (IS_ERR(sa51034->regmap)) {
devm_kfree(&i2c->dev, sa51034);
return PTR_ERR(sa51034->regmap);
}
i2c_set_clientdata(i2c, sa51034);
sa51034->i2c = i2c;
ret = devm_snd_soc_register_component(&i2c->dev, &pa_asoc_component,
NULL, 0);
if (ret) {
pr_err( "pa component register failed,ret=%d\n",ret);
return ret;
}
pr_info("[sa51034] %s(%d) pa component register end,ret=0x%x\n", __func__, __LINE__,ret);
sa51034_gpio_request(sa51034);
sa51034_set_pwen(sa51034,1);
//sa51034_set_mute(sa51034,0);
g_sa51034 = sa51034;
pr_info("\t[sa51034] %s end\n", __func__);
return ret;
}
static const struct i2c_device_id sa51034_i2c_id[] = {
{ "sa51034", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sa51034_i2c_id);
static struct i2c_driver sa51034_i2c_driver = {
.driver = {
.name = "sa51034",
.of_match_table = of_match_ptr(sa51034_i2c_dt_ids),
},
.probe = sa51034_i2c_probe,
//.remove = sa51034_i2c_remove,
.id_table = sa51034_i2c_id,
};
static int sa51034_init(void)
{
pr_info("\t[sa51034] %s(%d)\n", __func__, __LINE__);
return i2c_add_driver(&sa51034_i2c_driver);
}
#endif
static int zx29_audio_probe(struct platform_device *pdev)
{
int ret;
struct device_node *np = pdev->dev.of_node;
struct snd_soc_card *card = &zx29_soc_card;
struct zx29_board_data *board;
const struct of_device_id *id;
enum of_gpio_flags flags;
unsigned int idx;
struct device *dev = &pdev->dev;
dev_info(&pdev->dev,"zx29_audio_probe start!\n");
card->dev = &pdev->dev;
board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
if (!board)
return -ENOMEM;
/*
if (np) {
zx29_dai_link[0].cpus->dai_name = NULL;
zx29_dai_link[0].cpus->of_node = of_parse_phandle(np,
"zxic,i2s-controller", 0);
if (!zx29_dai_link[0].cpus->of_node) {
dev_err(&pdev->dev,
"Property 'zxic,i2s-controller' missing or invalid\n");
ret = -EINVAL;
}
zx29_dai_link[0].platforms->name = NULL;
zx29_dai_link[0].platforms->of_node = zx29_dai_link[0].cpus->of_node;
#if 0
zx29_dai_link[0].codecs->of_node = of_parse_phandle(np,
"zxic,audio-codec", 0);
if (!zx29_dai_link[0].codecs->of_node) {
dev_err(&pdev->dev,
"Property 'zxic,audio-codec' missing or invalid\n");
return -EINVAL;
}
#endif
}
*/
id = of_match_device(of_match_ptr(zx29_nau8810_of_match), &pdev->dev);
if (id)
*board = *((struct zx29_board_data *)id->data);
board->name = "zx29_nau8810";
board->dev = &pdev->dev;
//platform_set_drvdata(pdev, board);
s_board = board;
#if 0
board->gpio_pwen = of_get_gpio_flags(dev->of_node, 0, &flags);
if (!gpio_is_valid(board->gpio_pwen)) {
dev_err(dev," gpio_pwen no found\n");
return -EBUSY;
}
dev_info(dev, "board->gpio_pwen=0x%x flags = %d\n",board->gpio_pwen,flags);
ret = devm_gpio_request(&pdev->dev,board->gpio_pwen, "codec_pwen");
if (ret < 0) {
dev_err(dev,"gpio_pwen request error.\n");
return ret;
}
board->gpio_pdn = of_get_gpio_flags(dev->of_node, 1, &flags);
if (!gpio_is_valid(board->gpio_pdn)) {
dev_err(dev," gpio_pdn no found\n");
return -EBUSY;
}
dev_info(dev, "board->gpio_pdn=0x%x flags = %d\n",board->gpio_pdn,flags);
ret = devm_gpio_request(&pdev->dev,board->gpio_pdn, "codec_pdn");
if (ret < 0) {
dev_err(dev,"gpio_pdn request error.\n");
return ret;
}
#endif
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret){
dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
return ret;
}
zx29_i2s_top_pin_cfg(pdev);
//codec_power_on(board,1);
#ifdef CONFIG_PA_SA51034
dev_info(&pdev->dev,"zx29_audio_probe start sa51034_init!\n");
ret = sa51034_init();
if (ret != 0) {
pr_err("sa51034_init Failed to register I2C driver: %d\n", ret);
//return ret;
}
else{
for (idx = 0; idx < ARRAY_SIZE(pa_controls); idx++) {
ret = snd_ctl_add(card->snd_card,
snd_ctl_new1(&pa_controls[idx],
NULL));
if (ret < 0){
return ret;
}
}
}
ret = 0;
#endif
dev_info(&pdev->dev,"zx29_audio_probe end!\n");
return ret;
}
#ifdef CONFIG_PM
static int zx29_audio_suspend(struct platform_device * pdev, pm_message_t state)
{
pr_info("%s: start!\n",__func__);
//pinctrl_pm_select_sleep_state(&pdev->dev);
return 0;
}
static int zx29_audio_resume(struct platform_device *pdev)
{
pr_info("%s: start!\n",__func__);
//pinctrl_pm_select_default_state(&pdev->dev);
return 0;
}
int zx29_snd_soc_suspend(struct device *dev)
{
int ret = 0;
struct zx29_board_data *info = s_board;
pr_info("%s: start!\n",__func__);
//pinctrl_pm_select_sleep_state(dev);
if((info->p != NULL)&&(info->s_sleep != NULL)){
ret = pinctrl_select_state(info->p, info->s_sleep);
if (ret < 0) {
//devm_pinctrl_put(info->p);
dev_err(dev, " select state failure!!\n");
//return;
}
dev_info(dev, "%s: set pinctrl sleep end!\n", __func__);
}
return snd_soc_suspend(dev);
}
int zx29_snd_soc_resume(struct device *dev)
{
int ret = 0;
struct zx29_board_data *info = s_board;
pr_info("%s: start!\n",__func__);
//pinctrl_pm_select_default_state(dev);
if((info->p != NULL)&&(info->s != NULL)){
ret = pinctrl_select_state(info->p, info->s);
if (ret < 0) {
//devm_pinctrl_put(info->p);
dev_err(dev, " select state failure!!\n");
//return;
}
dev_info(dev, "%s: set pinctrl active end!\n", __func__);
}
return snd_soc_resume(dev);
}
#else
static int zx29_audio_suspend(struct platform_device * pdev, pm_message_t state)
{
return 0;
}
static int zx29_audio_resume(struct platform_device *pdev)
{
return 0;
}
int zx29_snd_soc_suspend(struct device *dev)
{
return snd_soc_suspend(dev);
}
int zx29_snd_soc_resume(struct device *dev)
{
return snd_soc_resume(dev);
}
#endif
struct dev_pm_ops zx29_snd_soc_pm_ops = {
.suspend = zx29_snd_soc_suspend,
.resume = zx29_snd_soc_resume,
.freeze = snd_soc_suspend,
.thaw = snd_soc_resume,
.poweroff = snd_soc_poweroff,
.restore = snd_soc_resume,
};
static struct platform_driver zx29_platform_driver = {
.driver = {
.name = "zx29_nau8810",
.of_match_table = of_match_ptr(zx29_nau8810_of_match),
//.pm = &snd_soc_pm_ops,
.pm = &zx29_snd_soc_pm_ops,
},
.probe = zx29_audio_probe,
//.remove = zx29_remove,
};
#if 0
static int zx29_probe(struct platform_device *pdev)
{
int ret;
print_audio("Alsa zx297520xx SoC Audio driver\n");
zx29_platform_data = pdev->dev.platform_data;
if (zx29_platform_data == NULL) {
printk(KERN_ERR "Alsa zx297520xx SoC Audio: unable to find platform data\n");
return -ENODEV;
}
if (zx297520xx_setup_pins(zx29_platform_data, "codec") < 0)
return -EBUSY;
zx29_i2s_top_reg_cfg();
zx29_snd_device = platform_device_alloc("soc-audio", -1);
if (!zx29_snd_device) {
printk(KERN_ERR "Alsa zx297520xx SoC Audio: Unable to register\n");
return -ENOMEM;
}
platform_set_drvdata(zx29_snd_device, &zxic_soc_card);
// platform_device_add_data(zx29xx_nau8810_snd_device, &zx29xx_nau8810, sizeof(zx29xx_nau8810));
ret = platform_device_add(zx29_snd_device);
if (ret) {
printk(KERN_ERR "Alsa zx29 SoC Audio: Unable to add\n");
platform_device_put(zx29_snd_device);
}
return ret;
}
#endif
module_platform_driver(zx29_platform_driver);
MODULE_DESCRIPTION("zx29 ALSA SoC audio driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:zx29-audio-nau8810");