2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 /*******************************************************************************
24 * voice call platform driver
34 *------------------------------------------------------------------------------
40 *******************************************************************************/
43 /*****************************************************************************
44 * C O M P I L E R F L A G S
45 *****************************************************************************/
48 /*****************************************************************************
49 * E X T E R N A L R E F E R E N C E S
50 *****************************************************************************/
52 #include <linux/dma-mapping.h>
53 #include "AudDrv_Common.h"
54 #include "AudDrv_Def.h"
55 #include "AudDrv_Afe.h"
56 #include "AudDrv_Ana.h"
57 #include "AudDrv_Clk.h"
58 #include "AudDrv_Kernel.h"
59 #include "mt_soc_afe_control.h"
60 #include "mt_soc_digital_type.h"
61 #include "mt_soc_pcm_common.h"
64 * function implementation
67 static int mtk_voice_probe(struct platform_device
*pdev
);
68 static int mtk_voice_close(struct snd_pcm_substream
*substream
);
69 static int mtk_soc_voice_new(struct snd_soc_pcm_runtime
*rtd
);
70 static int mtk_voice_platform_probe(struct snd_soc_platform
*platform
);
72 static uint16 Voice_Status
= 0;
73 static AudioDigtalI2S mAudioDigitalI2S
;
74 #define VOICE_UL_ON (1<<0)
75 #define VOICE_DL_ON (1<<1)
76 bool get_voice_status(void)
78 return (Voice_Status
!= 0) | GetExternalModemStatus();
80 EXPORT_SYMBOL(get_voice_status
);
81 static AudioDigitalPCM Voice1Pcm
=
83 .mTxLchRepeatSel
= Soc_Aud_TX_LCH_RPT_TX_LCH_NO_REPEAT
,
84 .mVbt16kModeSel
= Soc_Aud_VBT_16K_MODE_VBT_16K_MODE_DISABLE
,
85 .mExtModemSel
= Soc_Aud_EXT_MODEM_MODEM_2_USE_INTERNAL_MODEM
,
86 .mExtendBckSyncLength
= 0,
87 .mExtendBckSyncTypeSel
= Soc_Aud_PCM_SYNC_TYPE_BCK_CYCLE_SYNC
,
88 .mSingelMicSel
= Soc_Aud_BT_MODE_DUAL_MIC_ON_TX
,
89 .mAsyncFifoSel
= Soc_Aud_BYPASS_SRC_SLAVE_USE_ASRC
,
90 .mSlaveModeSel
= Soc_Aud_PCM_CLOCK_SOURCE_SALVE_MODE
,
91 .mPcmWordLength
= Soc_Aud_PCM_WLEN_LEN_PCM_16BIT
,
92 .mPcmModeWidebandSel
= false,
93 .mPcmFormat
= Soc_Aud_PCM_FMT_PCM_MODE_B
,
97 static struct snd_pcm_hw_constraint_list constraints_sample_rates
=
99 .count
= ARRAY_SIZE(soc_voice_supported_sample_rates
),
100 .list
= soc_voice_supported_sample_rates
,
104 static struct snd_pcm_hardware mtk_pcm_hardware
=
106 .info
= (SNDRV_PCM_INFO_MMAP
|
107 SNDRV_PCM_INFO_INTERLEAVED
|
108 SNDRV_PCM_INFO_RESUME
|
109 SNDRV_PCM_INFO_MMAP_VALID
),
110 .formats
= SND_SOC_STD_MT_FMTS
,
111 .rates
= SOC_NORMAL_USE_RATE
,
112 .rate_min
= SOC_NORMAL_USE_RATE_MIN
,
113 .rate_max
= SOC_NORMAL_USE_RATE_MAX
,
114 .channels_min
= SOC_NORMAL_USE_CHANNELS_MIN
,
115 .channels_max
= SOC_NORMAL_USE_CHANNELS_MAX
,
116 .buffer_bytes_max
= MAX_BUFFER_SIZE
,
117 .period_bytes_max
= MAX_PERIOD_SIZE
,
123 static int mtk_voice_pcm_open(struct snd_pcm_substream
*substream
)
125 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
131 printk("mtk_voice_pcm_open\n");
133 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
135 printk("%s with SNDRV_PCM_STREAM_CAPTURE \n",__func__
);
136 runtime
->rate
= 16000;
137 if(Voice_Status
!= 0)
142 runtime
->hw
= mtk_pcm_hardware
;
143 memcpy((void *)(&(runtime
->hw
)), (void *)&mtk_pcm_hardware
, sizeof(struct snd_pcm_hardware
));
145 ret
= snd_pcm_hw_constraint_list(runtime
, 0, SNDRV_PCM_HW_PARAM_RATE
,
146 &constraints_sample_rates
);
147 ret
= snd_pcm_hw_constraint_integer(runtime
, SNDRV_PCM_HW_PARAM_PERIODS
);
151 printk("snd_pcm_hw_constraint_integer failed\n");
154 //print for hw pcm information
155 printk("mtk_voice_pcm_open runtime rate = %d channels = %d \n", runtime
->rate
, runtime
->channels
);
157 runtime
->hw
.info
|= SNDRV_PCM_INFO_INTERLEAVED
;
158 runtime
->hw
.info
|= SNDRV_PCM_INFO_NONINTERLEAVED
;
160 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
162 printk("SNDRV_PCM_STREAM_PLAYBACK mtkalsa_voice_constraints\n");
163 runtime
->rate
= 16000;
172 printk("mtk_voice_close\n");
173 mtk_voice_close(substream
);
176 printk("mtk_voice_pcm_open return\n");
180 static void ConfigAdcI2S(struct snd_pcm_substream
*substream
)
182 mAudioDigitalI2S
.mLR_SWAP
= Soc_Aud_LR_SWAP_NO_SWAP
;
183 mAudioDigitalI2S
.mBuffer_Update_word
= 8;
184 mAudioDigitalI2S
.mFpga_bit_test
= 0;
185 mAudioDigitalI2S
.mFpga_bit
= 0;
186 mAudioDigitalI2S
.mloopback
= 0;
187 mAudioDigitalI2S
.mINV_LRCK
= Soc_Aud_INV_LRCK_NO_INVERSE
;
188 mAudioDigitalI2S
.mI2S_FMT
= Soc_Aud_I2S_FORMAT_I2S
;
189 mAudioDigitalI2S
.mI2S_WLEN
= Soc_Aud_I2S_WLEN_WLEN_16BITS
;
190 mAudioDigitalI2S
.mI2S_SAMPLERATE
= (substream
->runtime
->rate
);
193 static int mtk_voice_close(struct snd_pcm_substream
*substream
)
195 printk("mtk_voice_close \n");
197 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
199 printk("%s with SNDRV_PCM_STREAM_PLAYBACK \n",__func__
);
200 SetConnection(Soc_Aud_InterCon_DisConnect
, Soc_Aud_InterConnectionInput_I14
, Soc_Aud_InterConnectionOutput_O03
);
201 SetConnection(Soc_Aud_InterCon_DisConnect
, Soc_Aud_InterConnectionInput_I14
, Soc_Aud_InterConnectionOutput_O04
);
202 SetI2SDacEnable(false);
203 SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC
, false);
204 Voice_Status
&= ~VOICE_DL_ON
;
205 if(Voice_Status
== 0)
207 SetModemPcmEnable(MODEM_1
, false);
211 AudDrv_ADC_Clk_Off();
213 else if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
215 printk("%s with SNDRV_PCM_STREAM_CAPTURE \n",__func__
);
216 SetConnection(Soc_Aud_InterCon_DisConnect
, Soc_Aud_InterConnectionInput_I03
, Soc_Aud_InterConnectionOutput_O17
);
217 SetConnection(Soc_Aud_InterCon_DisConnect
, Soc_Aud_InterConnectionInput_I04
, Soc_Aud_InterConnectionOutput_O18
);
218 SetI2SAdcEnable(false);
219 SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_ADC
, false);
221 Voice_Status
&= ~VOICE_UL_ON
;
222 if(Voice_Status
== 0)
224 SetModemPcmEnable(MODEM_1
, false);
228 AudDrv_ADC_Clk_Off();
234 static int mtk_voice_trigger(struct snd_pcm_substream
*substream
, int cmd
)
236 printk("mtk_voice_trigger cmd = %d\n", cmd
);
239 case SNDRV_PCM_TRIGGER_START
:
240 case SNDRV_PCM_TRIGGER_RESUME
:
241 case SNDRV_PCM_TRIGGER_STOP
:
242 case SNDRV_PCM_TRIGGER_SUSPEND
:
248 static int mtk_voice_pcm_copy(struct snd_pcm_substream
*substream
,
249 int channel
, snd_pcm_uframes_t pos
,
250 void __user
*dst
, snd_pcm_uframes_t count
)
255 static int mtk_voice_pcm_silence(struct snd_pcm_substream
*substream
,
256 int channel
, snd_pcm_uframes_t pos
,
257 snd_pcm_uframes_t count
)
259 printk("mtk_voice_pcm_silence \n");
260 return 0; /* do nothing */
263 static void *dummy_page
[2];
264 static struct page
*mtk_pcm_page(struct snd_pcm_substream
*substream
,
265 unsigned long offset
)
267 return virt_to_page(dummy_page
[substream
->stream
]); /* the same page */
270 static int mtk_voice1_prepare(struct snd_pcm_substream
*substream
)
272 struct snd_pcm_runtime
*runtimeStream
= substream
->runtime
;
273 printk("mtk_voice1_prepare rate = %d channels = %d period_size = %lu\n",
274 runtimeStream
->rate
, runtimeStream
->channels
, runtimeStream
->period_size
);
276 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
278 printk("%s with SNDRV_PCM_STREAM_PLAYBACK \n",__func__
);
279 SetConnection(Soc_Aud_InterCon_Connection
, Soc_Aud_InterConnectionInput_I14
, Soc_Aud_InterConnectionOutput_O03
);
280 SetConnection(Soc_Aud_InterCon_Connection
, Soc_Aud_InterConnectionInput_I14
, Soc_Aud_InterConnectionOutput_O04
);
282 SetI2SDacOut(substream
->runtime
->rate
);
283 SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC
, true);
284 SetI2SDacEnable(true);
287 else if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
289 printk("%s with SNDRV_PCM_STREAM_CAPTURE \n",__func__
);
290 SetConnection(Soc_Aud_InterCon_Connection
, Soc_Aud_InterConnectionInput_I03
, Soc_Aud_InterConnectionOutput_O17
);
291 SetConnection(Soc_Aud_InterCon_Connection
, Soc_Aud_InterConnectionInput_I04
, Soc_Aud_InterConnectionOutput_O18
);
292 ConfigAdcI2S(substream
);
293 SetI2SAdcIn(&mAudioDigitalI2S
);
294 SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_IN_ADC
, true);
295 SetI2SAdcEnable(true);
299 if(Voice_Status
== 0)
301 Voice1Pcm
.mPcmModeWidebandSel
= (runtimeStream
->rate
== 8000) ? Soc_Aud_PCM_MODE_PCM_MODE_8K
: Soc_Aud_PCM_MODE_PCM_MODE_16K
;
302 Voice1Pcm
.mAsyncFifoSel
= Soc_Aud_BYPASS_SRC_SLAVE_USE_ASYNC_FIFO
;
303 SetModemPcmConfig(MODEM_1
, Voice1Pcm
);
304 SetModemPcmEnable(MODEM_1
, true);
306 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
308 Voice_Status
|= VOICE_DL_ON
;
310 else if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
312 Voice_Status
|= VOICE_UL_ON
;
318 static int mtk_pcm_hw_params(struct snd_pcm_substream
*substream
,
319 struct snd_pcm_hw_params
*hw_params
)
322 printk("mtk_pcm_hw_params \n");
326 static int mtk_voice_hw_free(struct snd_pcm_substream
*substream
)
328 PRINTK_AUDDRV("mtk_voice_hw_free \n");
329 return snd_pcm_lib_free_pages(substream
);
332 static struct snd_pcm_ops mtk_voice_ops
=
334 .open
= mtk_voice_pcm_open
,
335 .close
= mtk_voice_close
,
336 .ioctl
= snd_pcm_lib_ioctl
,
337 .hw_params
= mtk_pcm_hw_params
,
338 .hw_free
= mtk_voice_hw_free
,
339 .prepare
= mtk_voice1_prepare
,
340 .trigger
= mtk_voice_trigger
,
341 .copy
= mtk_voice_pcm_copy
,
342 .silence
= mtk_voice_pcm_silence
,
343 .page
= mtk_pcm_page
,
346 static struct snd_soc_platform_driver mtk_soc_voice_platform
=
348 .ops
= &mtk_voice_ops
,
349 .pcm_new
= mtk_soc_voice_new
,
350 .probe
= mtk_voice_platform_probe
,
353 static int mtk_voice_probe(struct platform_device
*pdev
)
355 printk("mtk_voice_probe\n");
357 pdev
->dev
.coherent_dma_mask
= DMA_BIT_MASK(64);
358 if (!pdev
->dev
.dma_mask
)
360 pdev
->dev
.dma_mask
= &pdev
->dev
.coherent_dma_mask
;
363 if (pdev
->dev
.of_node
)
365 dev_set_name(&pdev
->dev
, "%s", MT_SOC_VOICE
);
367 printk("%s: dev name %s\n", __func__
, dev_name(&pdev
->dev
));
368 return snd_soc_register_platform(&pdev
->dev
,
369 &mtk_soc_voice_platform
);
372 static int mtk_soc_voice_new(struct snd_soc_pcm_runtime
*rtd
)
375 printk("%s\n", __func__
);
379 static int mtk_voice_platform_probe(struct snd_soc_platform
*platform
)
381 printk("mtk_voice_platform_probe\n");
385 static int mtk_voice_remove(struct platform_device
*pdev
)
387 pr_debug("%s\n", __func__
);
388 snd_soc_unregister_platform(&pdev
->dev
);
393 //supend and resume function
394 static int mtk_voice_pm_ops_suspend(struct device
*device
)
396 // if now in phone call state, not suspend!!
397 bool b_modem1_speech_on
;
398 bool b_modem2_speech_on
;
399 AudDrv_Clk_On();//should enable clk for access reg
400 b_modem1_speech_on
= (bool)(Afe_Get_Reg(PCM2_INTF_CON
) & 0x1);
401 b_modem2_speech_on
= (bool)(Afe_Get_Reg(PCM_INTF_CON
) & 0x1);
402 AudDrv_Clk_Off();//should enable clk for access reg
403 if (b_modem1_speech_on
== true || b_modem2_speech_on
== true)
405 clkmux_sel(MT_MUX_AUDINTBUS
, 0, "AUDIO"); //select 26M
411 static int mtk_voice_pm_ops_resume(struct device
*device
)
413 bool b_modem1_speech_on
;
414 bool b_modem2_speech_on
;
415 AudDrv_Clk_On();//should enable clk for access reg
416 b_modem1_speech_on
= (bool)(Afe_Get_Reg(PCM2_INTF_CON
) & 0x1);
417 b_modem2_speech_on
= (bool)(Afe_Get_Reg(PCM_INTF_CON
) & 0x1);
419 if (b_modem1_speech_on
== true || b_modem2_speech_on
== true)
421 clkmux_sel(MT_MUX_AUDINTBUS
, 1, "AUDIO"); //mainpll
427 struct dev_pm_ops mtk_voice_pm_ops
=
429 .suspend
= mtk_voice_pm_ops_suspend
,
430 .resume
= mtk_voice_pm_ops_resume
,
435 .restore_noirq
= NULL
,
439 static const struct of_device_id mt_soc_pcm_voice_of_ids
[] =
441 { .compatible
= "mediatek,mt_soc_pcm_voice", },
446 static struct platform_driver mtk_voice_driver
=
449 .name
= MT_SOC_VOICE
,
450 .owner
= THIS_MODULE
,
452 .of_match_table
= mt_soc_pcm_voice_of_ids
,
455 .pm
= &mtk_voice_pm_ops
,
458 .probe
= mtk_voice_probe
,
459 .remove
= mtk_voice_remove
,
463 static struct platform_device
*soc_mtk_voice_dev
;
466 static int __init
mtk_soc_voice_platform_init(void)
469 printk("%s\n", __func__
);
471 soc_mtk_voice_dev
= platform_device_alloc(MT_SOC_VOICE
, -1);
472 if (!soc_mtk_voice_dev
)
477 ret
= platform_device_add(soc_mtk_voice_dev
);
480 platform_device_put(soc_mtk_voice_dev
);
484 ret
= platform_driver_register(&mtk_voice_driver
);
489 module_init(mtk_soc_voice_platform_init
);
491 static void __exit
mtk_soc_voice_platform_exit(void)
494 printk("%s\n", __func__
);
495 platform_driver_unregister(&mtk_voice_driver
);
497 module_exit(mtk_soc_voice_platform_exit
);
499 MODULE_DESCRIPTION("AFE PCM module platform driver");
500 MODULE_LICENSE("GPL");