| /* |
| * 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"); |