blob: cbb05872bb3743387be99acfe7ed0d5753bbfff7 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/mfd/msm-adie-codec.h>
16#include <linux/clk.h>
17#include <linux/err.h>
18#include <linux/debugfs.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070019#include <linux/pm_qos.h>
20
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <asm/uaccess.h>
22#include <mach/qdsp5v2/snddev_icodec.h>
23#include <mach/qdsp5v2/audio_dev_ctl.h>
24#include <mach/qdsp5v2/audio_interct.h>
25#include <mach/qdsp5v2/mi2s.h>
26#include <mach/qdsp5v2/afe.h>
27#include <mach/qdsp5v2/lpa.h>
28#include <mach/qdsp5v2/marimba_profile.h>
29#include <mach/vreg.h>
30#include <mach/pmic.h>
31#include <linux/wakelock.h>
32#include <mach/debug_mm.h>
33#include <mach/rpc_pmapp.h>
34#include <mach/qdsp5v2/audio_acdb_def.h>
35#include <linux/slab.h>
Stephen Boyd2fcabf92012-05-30 10:41:11 -070036#include <mach/cpuidle.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38#define SMPS_AUDIO_PLAYBACK_ID "AUPB"
39#define SMPS_AUDIO_RECORD_ID "AURC"
40
41#define SNDDEV_ICODEC_PCM_SZ 32 /* 16 bit / sample stereo mode */
42#define SNDDEV_ICODEC_MUL_FACTOR 3 /* Multi by 8 Shift by 3 */
43#define SNDDEV_ICODEC_CLK_RATE(freq) \
44 (((freq) * (SNDDEV_ICODEC_PCM_SZ)) << (SNDDEV_ICODEC_MUL_FACTOR))
45
46#ifdef CONFIG_DEBUG_FS
47static struct adie_codec_action_unit debug_rx_actions[] =
48 HANDSET_RX_8000_OSR_256;
49
50static struct adie_codec_action_unit debug_tx_lb_actions[] = {
51 { ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF },
52 { ADIE_CODEC_ACTION_ENTRY,
53 ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x01)},
54 { ADIE_CODEC_ACTION_ENTRY,
55 ADIE_CODEC_PACK_ENTRY(0x80, 0x01, 0x00) },
56 { ADIE_CODEC_ACTION_ENTRY,
57 ADIE_CODEC_PACK_ENTRY(0x8A, 0x30, 0x30)},
58 { ADIE_CODEC_ACTION_ENTRY,
59 ADIE_CODEC_PACK_ENTRY(0x11, 0xfc, 0xfc)},
60 { ADIE_CODEC_ACTION_ENTRY,
61 ADIE_CODEC_PACK_ENTRY(0x13, 0xfc, 0x58)},
62 { ADIE_CODEC_ACTION_ENTRY,
63 ADIE_CODEC_PACK_ENTRY(0x14, 0xff, 0x65)},
64 { ADIE_CODEC_ACTION_ENTRY,
65 ADIE_CODEC_PACK_ENTRY(0x15, 0xff, 0x64)},
66 { ADIE_CODEC_ACTION_ENTRY,
67 ADIE_CODEC_PACK_ENTRY(0x82, 0xff, 0x5C)},
68 { ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY },
69 { ADIE_CODEC_ACTION_ENTRY,
70 ADIE_CODEC_PACK_ENTRY(0x0D, 0xF0, 0xd0)},
71 { ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8},
72 { ADIE_CODEC_ACTION_ENTRY,
73 ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x14)},
74 { ADIE_CODEC_ACTION_ENTRY,
75 ADIE_CODEC_PACK_ENTRY(0x86, 0xff, 0x00)},
76 { ADIE_CODEC_ACTION_ENTRY,
77 ADIE_CODEC_PACK_ENTRY(0x8A, 0x50, 0x40)},
78 { ADIE_CODEC_ACTION_ENTRY,
79 ADIE_CODEC_PACK_ENTRY(0x91, 0xFF, 0x01)}, /* Start loop back */
80 { ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY},
81 { ADIE_CODEC_ACTION_ENTRY,
82 ADIE_CODEC_PACK_ENTRY(0x8A, 0x10, 0x30)},
83 { ADIE_CODEC_ACTION_ENTRY,
84 ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)},
85 { ADIE_CODEC_ACTION_ENTRY,
86 ADIE_CODEC_PACK_ENTRY(0x83, 0x14, 0x00)},
87 { ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},
88 { ADIE_CODEC_ACTION_ENTRY,
89 ADIE_CODEC_PACK_ENTRY(0x11, 0xff, 0x00)}
90};
91
92static struct adie_codec_action_unit debug_tx_actions[] =
93 HANDSET_TX_8000_OSR_256;
94
95static struct adie_codec_hwsetting_entry debug_rx_settings[] = {
96 {
97 .freq_plan = 8000,
98 .osr = 256,
99 .actions = debug_rx_actions,
100 .action_sz = ARRAY_SIZE(debug_rx_actions),
101 }
102};
103
104static struct adie_codec_hwsetting_entry debug_tx_settings[] = {
105 {
106 .freq_plan = 8000,
107 .osr = 256,
108 .actions = debug_tx_actions,
109 .action_sz = ARRAY_SIZE(debug_tx_actions),
110 }
111};
112
113static struct adie_codec_hwsetting_entry debug_tx_lb_settings[] = {
114 {
115 .freq_plan = 8000,
116 .osr = 256,
117 .actions = debug_tx_lb_actions,
118 .action_sz = ARRAY_SIZE(debug_tx_lb_actions),
119 }
120};
121
122static struct adie_codec_dev_profile debug_rx_profile = {
123 .path_type = ADIE_CODEC_RX,
124 .settings = debug_rx_settings,
125 .setting_sz = ARRAY_SIZE(debug_rx_settings),
126};
127
128static struct adie_codec_dev_profile debug_tx_profile = {
129 .path_type = ADIE_CODEC_TX,
130 .settings = debug_tx_settings,
131 .setting_sz = ARRAY_SIZE(debug_tx_settings),
132};
133
134static struct adie_codec_dev_profile debug_tx_lb_profile = {
135 .path_type = ADIE_CODEC_TX,
136 .settings = debug_tx_lb_settings,
137 .setting_sz = ARRAY_SIZE(debug_tx_lb_settings),
138};
139#endif /* CONFIG_DEBUG_FS */
140
141/* Context for each internal codec sound device */
142struct snddev_icodec_state {
143 struct snddev_icodec_data *data;
144 struct adie_codec_path *adie_path;
145 u32 sample_rate;
146 u32 enabled;
147};
148
149/* Global state for the driver */
150struct snddev_icodec_drv_state {
151 struct mutex rx_lock;
152 struct mutex lb_lock;
153 struct mutex tx_lock;
154 u32 rx_active; /* ensure one rx device at a time */
155 u32 tx_active; /* ensure one tx device at a time */
156 struct clk *rx_mclk;
157 struct clk *rx_sclk;
158 struct clk *tx_mclk;
159 struct clk *tx_sclk;
160 struct clk *lpa_codec_clk;
161 struct clk *lpa_core_clk;
162 struct clk *lpa_p_clk;
163 struct lpa_drv *lpa;
164
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700165 struct pm_qos_request rx_pm_qos_req;
166 struct pm_qos_request tx_pm_qos_req;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700167};
168
169static struct snddev_icodec_drv_state snddev_icodec_drv;
170
171static int snddev_icodec_open_rx(struct snddev_icodec_state *icodec)
172{
173 int trc, err;
174 int smps_mode = PMAPP_SMPS_MODE_VOTE_PWM;
175 struct msm_afe_config afe_config;
176 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
177 struct lpa_codec_config lpa_config;
178
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700179 pm_qos_update_request(&drv->rx_pm_qos_req,
180 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181
182 if ((icodec->data->acdb_id == ACDB_ID_HEADSET_SPKR_MONO) ||
183 (icodec->data->acdb_id == ACDB_ID_HEADSET_SPKR_STEREO)) {
184 /* Vote PMAPP_SMPS_MODE_VOTE_PFM for headset */
185 smps_mode = PMAPP_SMPS_MODE_VOTE_PFM;
186 MM_DBG("snddev_icodec_open_rx: PMAPP_SMPS_MODE_VOTE_PFM \n");
187 } else
188 MM_DBG("snddev_icodec_open_rx: PMAPP_SMPS_MODE_VOTE_PWM \n");
189
190 /* Vote for SMPS mode*/
191 err = pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
192 PMAPP_VREG_S4, smps_mode);
193 if (err != 0)
194 MM_ERR("pmapp_smps_mode_vote error %d\n", err);
195
196 /* enable MI2S RX master block */
197 /* enable MI2S RX bit clock */
198 trc = clk_set_rate(drv->rx_mclk,
199 SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
200 if (IS_ERR_VALUE(trc))
201 goto error_invalid_freq;
Vinay Vakac82b9b82012-07-02 15:33:38 +0530202 clk_prepare_enable(drv->rx_mclk);
203 clk_prepare_enable(drv->rx_sclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 /* clk_set_rate(drv->lpa_codec_clk, 1); */ /* Remove if use pcom */
Vinay Vakac82b9b82012-07-02 15:33:38 +0530205 clk_prepare_enable(drv->lpa_p_clk);
206 clk_prepare_enable(drv->lpa_codec_clk);
207 clk_prepare_enable(drv->lpa_core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208
209 /* Enable LPA sub system
210 */
211 drv->lpa = lpa_get();
212 if (!drv->lpa)
213 goto error_lpa;
214 lpa_config.sample_rate = icodec->sample_rate;
215 lpa_config.sample_width = 16;
216 lpa_config.output_interface = LPA_OUTPUT_INTF_WB_CODEC;
217 lpa_config.num_channels = icodec->data->channel_mode;
218 lpa_cmd_codec_config(drv->lpa, &lpa_config);
219
220 /* Set audio interconnect reg to LPA */
221 audio_interct_codec(AUDIO_INTERCT_LPA);
222
223 /* Set MI2S */
224 mi2s_set_codec_output_path((icodec->data->channel_mode == 2 ?
225 MI2S_CHAN_STEREO : MI2S_CHAN_MONO_PACKED), WT_16_BIT);
226
227 if (icodec->data->voltage_on)
228 icodec->data->voltage_on();
229
230 /* Configure ADIE */
231 trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
232 if (IS_ERR_VALUE(trc))
233 goto error_adie;
234 /* OSR default to 256, can be changed for power optimization
235 * If OSR is to be changed, need clock API for setting the divider
236 */
237 adie_codec_setpath(icodec->adie_path, icodec->sample_rate, 256);
238 /* Start AFE */
239 afe_config.sample_rate = icodec->sample_rate / 1000;
240 afe_config.channel_mode = icodec->data->channel_mode;
241 afe_config.volume = AFE_VOLUME_UNITY;
242 trc = afe_enable(AFE_HW_PATH_CODEC_RX, &afe_config);
243 if (IS_ERR_VALUE(trc))
244 goto error_afe;
245 lpa_cmd_enable_codec(drv->lpa, 1);
246 /* Enable ADIE */
247 adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_READY);
248 adie_codec_proceed_stage(icodec->adie_path,
249 ADIE_CODEC_DIGITAL_ANALOG_READY);
250
251 /* Enable power amplifier */
252 if (icodec->data->pamp_on)
253 icodec->data->pamp_on();
254
255 icodec->enabled = 1;
256
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700257 pm_qos_update_request(&drv->rx_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 return 0;
259
260error_afe:
261 adie_codec_close(icodec->adie_path);
262 icodec->adie_path = NULL;
263error_adie:
264 lpa_put(drv->lpa);
265error_lpa:
Vinay Vakac82b9b82012-07-02 15:33:38 +0530266 clk_disable_unprepare(drv->lpa_p_clk);
267 clk_disable_unprepare(drv->lpa_codec_clk);
268 clk_disable_unprepare(drv->lpa_core_clk);
269 clk_disable_unprepare(drv->rx_sclk);
270 clk_disable_unprepare(drv->rx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271error_invalid_freq:
272
273 MM_ERR("encounter error\n");
274
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700275 pm_qos_update_request(&drv->rx_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 return -ENODEV;
277}
278
279static int snddev_icodec_open_tx(struct snddev_icodec_state *icodec)
280{
281 int trc;
282 int i, err;
283 struct msm_afe_config afe_config;
284 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;;
285
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700286 pm_qos_update_request(&drv->tx_pm_qos_req,
287 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288
289 /* Vote for PWM mode*/
290 err = pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
291 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_PWM);
292 if (err != 0)
293 MM_ERR("pmapp_smps_mode_vote error %d\n", err);
294
295 /* Reuse pamp_on for TX platform-specific setup */
296 if (icodec->data->pamp_on)
297 icodec->data->pamp_on();
298
299 for (i = 0; i < icodec->data->pmctl_id_sz; i++) {
300 pmic_hsed_enable(icodec->data->pmctl_id[i],
301 PM_HSED_ENABLE_PWM_TCXO);
302 }
303
304 /* enable MI2S TX master block */
305 /* enable MI2S TX bit clock */
306 trc = clk_set_rate(drv->tx_mclk,
307 SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
308 if (IS_ERR_VALUE(trc))
309 goto error_invalid_freq;
Vinay Vakac82b9b82012-07-02 15:33:38 +0530310 clk_prepare_enable(drv->tx_mclk);
311 clk_prepare_enable(drv->tx_sclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312
313 /* Set MI2S */
314 mi2s_set_codec_input_path((icodec->data->channel_mode ==
315 REAL_STEREO_CHANNEL_MODE ? MI2S_CHAN_STEREO :
316 (icodec->data->channel_mode == 2 ?
317 MI2S_CHAN_STEREO : MI2S_CHAN_MONO_RAW)),
318 WT_16_BIT);
319 /* Configure ADIE */
320 trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
321 if (IS_ERR_VALUE(trc))
322 goto error_adie;
323 /* Enable ADIE */
324 adie_codec_setpath(icodec->adie_path, icodec->sample_rate, 256);
325 adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_READY);
326 adie_codec_proceed_stage(icodec->adie_path,
327 ADIE_CODEC_DIGITAL_ANALOG_READY);
328
329 /* Start AFE */
330 afe_config.sample_rate = icodec->sample_rate / 1000;
331 afe_config.channel_mode = icodec->data->channel_mode;
332 afe_config.volume = AFE_VOLUME_UNITY;
333 trc = afe_enable(AFE_HW_PATH_CODEC_TX, &afe_config);
334 if (IS_ERR_VALUE(trc))
335 goto error_afe;
336
337
338 icodec->enabled = 1;
339
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700340 pm_qos_update_request(&drv->tx_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 return 0;
342
343error_afe:
344 adie_codec_close(icodec->adie_path);
345 icodec->adie_path = NULL;
346error_adie:
Vinay Vakac82b9b82012-07-02 15:33:38 +0530347 clk_disable_unprepare(drv->tx_sclk);
348 clk_disable_unprepare(drv->tx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349error_invalid_freq:
350
351 /* Disable mic bias */
352 for (i = 0; i < icodec->data->pmctl_id_sz; i++) {
353 pmic_hsed_enable(icodec->data->pmctl_id[i],
354 PM_HSED_ENABLE_OFF);
355 }
356
357 if (icodec->data->pamp_off)
358 icodec->data->pamp_off();
359
360 MM_ERR("encounter error\n");
361
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700362 pm_qos_update_request(&drv->tx_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 return -ENODEV;
364}
365
366static int snddev_icodec_close_lb(struct snddev_icodec_state *icodec)
367{
368 /* Disable power amplifier */
369 if (icodec->data->pamp_off)
370 icodec->data->pamp_off();
371
372 if (icodec->adie_path) {
373 adie_codec_proceed_stage(icodec->adie_path,
374 ADIE_CODEC_DIGITAL_OFF);
375 adie_codec_close(icodec->adie_path);
376 icodec->adie_path = NULL;
377 }
378 if (icodec->data->voltage_off)
379 icodec->data->voltage_off();
380
381 return 0;
382}
383
384static int snddev_icodec_close_rx(struct snddev_icodec_state *icodec)
385{
386 int err;
387 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
388
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700389 pm_qos_update_request(&drv->rx_pm_qos_req,
390 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391
392 /* Remove the vote for SMPS mode*/
393 err = pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
394 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
395 if (err != 0)
396 MM_ERR("pmapp_smps_mode_vote error %d\n", err);
397
398 /* Disable power amplifier */
399 if (icodec->data->pamp_off)
400 icodec->data->pamp_off();
401
402 /* Disable ADIE */
403 adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_OFF);
404 adie_codec_close(icodec->adie_path);
405 icodec->adie_path = NULL;
406
407 afe_disable(AFE_HW_PATH_CODEC_RX);
408
409 if (icodec->data->voltage_off)
410 icodec->data->voltage_off();
411
412 /* Disable LPA Sub system */
413 lpa_cmd_enable_codec(drv->lpa, 0);
414 lpa_put(drv->lpa);
415
416 /* Disable LPA clocks */
Vinay Vakac82b9b82012-07-02 15:33:38 +0530417 clk_disable_unprepare(drv->lpa_p_clk);
418 clk_disable_unprepare(drv->lpa_codec_clk);
419 clk_disable_unprepare(drv->lpa_core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420
421 /* Disable MI2S RX master block */
422 /* Disable MI2S RX bit clock */
Vinay Vakac82b9b82012-07-02 15:33:38 +0530423 clk_disable_unprepare(drv->rx_sclk);
424 clk_disable_unprepare(drv->rx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425
426 icodec->enabled = 0;
427
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700428 pm_qos_update_request(&drv->rx_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 return 0;
430}
431
432static int snddev_icodec_close_tx(struct snddev_icodec_state *icodec)
433{
434 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
435 int i, err;
436
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700437 pm_qos_update_request(&drv->tx_pm_qos_req,
438 msm_cpuidle_get_deep_idle_latency());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439
440 /* Remove the vote for SMPS mode*/
441 err = pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
442 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
443 if (err != 0)
444 MM_ERR("pmapp_smps_mode_vote error %d\n", err);
445
446 afe_disable(AFE_HW_PATH_CODEC_TX);
447
448 /* Disable ADIE */
449 adie_codec_proceed_stage(icodec->adie_path, ADIE_CODEC_DIGITAL_OFF);
450 adie_codec_close(icodec->adie_path);
451 icodec->adie_path = NULL;
452
453 /* Disable MI2S TX master block */
454 /* Disable MI2S TX bit clock */
Vinay Vakac82b9b82012-07-02 15:33:38 +0530455 clk_disable_unprepare(drv->tx_sclk);
456 clk_disable_unprepare(drv->tx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457
458 /* Disable mic bias */
459 for (i = 0; i < icodec->data->pmctl_id_sz; i++) {
460 pmic_hsed_enable(icodec->data->pmctl_id[i],
461 PM_HSED_ENABLE_OFF);
462 }
463
464 /* Reuse pamp_off for TX platform-specific setup */
465 if (icodec->data->pamp_off)
466 icodec->data->pamp_off();
467
468 icodec->enabled = 0;
469
Stephen Boyd2fcabf92012-05-30 10:41:11 -0700470 pm_qos_update_request(&drv->tx_pm_qos_req, PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 return 0;
472}
473
474static int snddev_icodec_open_lb(struct snddev_icodec_state *icodec)
475{
476 int trc;
477 trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
478 if (IS_ERR_VALUE(trc))
479 pr_err("%s: adie codec open failed\n", __func__);
480 else
481 adie_codec_setpath(icodec->adie_path,
482 icodec->sample_rate, 256);
483
484 if (icodec->adie_path)
485 adie_codec_proceed_stage(icodec->adie_path,
486 ADIE_CODEC_DIGITAL_ANALOG_READY);
487 if (icodec->data->pamp_on)
488 icodec->data->pamp_on();
489
490 icodec->enabled = 1;
491 return 0;
492}
493
494static int snddev_icodec_set_device_volume_impl(
495 struct msm_snddev_info *dev_info, u32 volume)
496{
497 struct snddev_icodec_state *icodec;
498 u8 afe_path_id;
499
500 int rc = 0;
501
502 icodec = dev_info->private_data;
503
504 if (icodec->data->capability & SNDDEV_CAP_RX)
505 afe_path_id = AFE_HW_PATH_CODEC_RX;
506 else
507 afe_path_id = AFE_HW_PATH_CODEC_TX;
508
509 if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_DIGITAL) {
510
511 rc = adie_codec_set_device_digital_volume(icodec->adie_path,
512 icodec->data->channel_mode ==
513 REAL_STEREO_CHANNEL_MODE ?
514 2 : icodec->data->channel_mode, volume);
515 if (rc < 0) {
516 MM_ERR("unable to set_device_digital_volume for"
517 "%s volume in percentage = %u\n",
518 dev_info->name, volume);
519 return rc;
520 }
521
522 } else if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_ANALOG) {
523 rc = adie_codec_set_device_analog_volume(icodec->adie_path,
524 icodec->data->channel_mode ==
525 REAL_STEREO_CHANNEL_MODE ?
526 2 : icodec->data->channel_mode, volume);
527 if (rc < 0) {
528 MM_ERR("unable to set_device_analog_volume for"
529 "%s volume in percentage = %u\n",
530 dev_info->name, volume);
531 return rc;
532 }
533 }
534 else {
535 MM_ERR("Invalid device volume control\n");
536 return -EPERM;
537 }
538 return rc;
539}
540
541static int snddev_icodec_close(struct msm_snddev_info *dev_info)
542{
543 int rc = 0;
544 struct snddev_icodec_state *icodec;
545 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
546 if (!dev_info) {
547 rc = -EINVAL;
548 goto error;
549 }
550
551 icodec = dev_info->private_data;
552
553 if (icodec->data->capability & SNDDEV_CAP_RX) {
554 mutex_lock(&drv->rx_lock);
555 if (!drv->rx_active) {
556 mutex_unlock(&drv->rx_lock);
557 rc = -EPERM;
558 goto error;
559 }
560 rc = snddev_icodec_close_rx(icodec);
561 if (!IS_ERR_VALUE(rc))
562 drv->rx_active = 0;
563 mutex_unlock(&drv->rx_lock);
564 } else if (icodec->data->capability & SNDDEV_CAP_LB) {
565 mutex_lock(&drv->lb_lock);
566 rc = snddev_icodec_close_lb(icodec);
567 mutex_unlock(&drv->lb_lock);
568 } else {
569 mutex_lock(&drv->tx_lock);
570 if (!drv->tx_active) {
571 mutex_unlock(&drv->tx_lock);
572 rc = -EPERM;
573 goto error;
574 }
575 rc = snddev_icodec_close_tx(icodec);
576 if (!IS_ERR_VALUE(rc))
577 drv->tx_active = 0;
578 mutex_unlock(&drv->tx_lock);
579 }
580
581error:
582 return rc;
583}
584
585static int snddev_icodec_open(struct msm_snddev_info *dev_info)
586{
587 int rc = 0;
588 struct snddev_icodec_state *icodec;
589 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
590
591 if (!dev_info) {
592 rc = -EINVAL;
593 goto error;
594 }
595
596 icodec = dev_info->private_data;
597
598 if (icodec->data->capability & SNDDEV_CAP_RX) {
599 mutex_lock(&drv->rx_lock);
600 if (drv->rx_active) {
601 mutex_unlock(&drv->rx_lock);
602 rc = -EBUSY;
603 goto error;
604 }
605 rc = snddev_icodec_open_rx(icodec);
606
607 if (!IS_ERR_VALUE(rc)) {
608 drv->rx_active = 1;
609 if ((icodec->data->dev_vol_type & (
610 SNDDEV_DEV_VOL_DIGITAL |
611 SNDDEV_DEV_VOL_ANALOG)))
612 rc = snddev_icodec_set_device_volume_impl(
613 dev_info, dev_info->dev_volume);
614 if (IS_ERR_VALUE(rc)) {
615 MM_ERR("Failed to set device volume"
616 " impl for rx device\n");
617 snddev_icodec_close(dev_info);
618 mutex_unlock(&drv->rx_lock);
619 goto error;
620 }
621 }
622 mutex_unlock(&drv->rx_lock);
623 } else if (icodec->data->capability & SNDDEV_CAP_LB) {
624 mutex_lock(&drv->lb_lock);
625 rc = snddev_icodec_open_lb(icodec);
626 if (!IS_ERR_VALUE(rc)) {
627 if ((icodec->data->dev_vol_type & (
628 SNDDEV_DEV_VOL_DIGITAL |
629 SNDDEV_DEV_VOL_ANALOG)))
630 rc = snddev_icodec_set_device_volume_impl(
631 dev_info,
632 dev_info->dev_volume);
633 if (rc < 0)
634 MM_ERR("failed to set device volume\n");
635 }
636 mutex_unlock(&drv->lb_lock);
637 } else {
638 mutex_lock(&drv->tx_lock);
639 if (drv->tx_active) {
640 mutex_unlock(&drv->tx_lock);
641 rc = -EBUSY;
642 goto error;
643 }
644 rc = snddev_icodec_open_tx(icodec);
645
646 if (!IS_ERR_VALUE(rc)) {
647 drv->tx_active = 1;
648 if ((icodec->data->dev_vol_type & (
649 SNDDEV_DEV_VOL_DIGITAL |
650 SNDDEV_DEV_VOL_ANALOG)))
651 rc = snddev_icodec_set_device_volume_impl(
652 dev_info, dev_info->dev_volume);
653 if (IS_ERR_VALUE(rc)) {
654 MM_ERR("Failed to set device volume"
655 " impl for tx device\n");
656 snddev_icodec_close(dev_info);
657 mutex_unlock(&drv->tx_lock);
658 goto error;
659 }
660 }
661 mutex_unlock(&drv->tx_lock);
662 }
663error:
664 return rc;
665}
666
667static int snddev_icodec_check_freq(u32 req_freq)
668{
669 int rc = -EINVAL;
670
671 if ((req_freq != 0) && (req_freq >= 8000) && (req_freq <= 48000)) {
672 if ((req_freq == 8000) || (req_freq == 11025) ||
673 (req_freq == 12000) || (req_freq == 16000) ||
674 (req_freq == 22050) || (req_freq == 24000) ||
675 (req_freq == 32000) || (req_freq == 44100) ||
676 (req_freq == 48000)) {
677 rc = 0;
678 } else
679 MM_INFO("Unsupported Frequency:%d\n", req_freq);
680 }
681 return rc;
682}
683
684static int snddev_icodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
685{
686 int rc;
687 struct snddev_icodec_state *icodec;
688
689 if (!dev_info) {
690 rc = -EINVAL;
691 goto error;
692 }
693
694 icodec = dev_info->private_data;
695 if (adie_codec_freq_supported(icodec->data->profile, rate) != 0) {
696 rc = -EINVAL;
697 goto error;
698 } else {
699 if (snddev_icodec_check_freq(rate) != 0) {
700 rc = -EINVAL;
701 goto error;
702 } else
703 icodec->sample_rate = rate;
704 }
705
706 if (icodec->enabled) {
707 snddev_icodec_close(dev_info);
708 snddev_icodec_open(dev_info);
709 }
710
711 return icodec->sample_rate;
712
713error:
714 return rc;
715}
716
717static int snddev_icodec_enable_sidetone(struct msm_snddev_info *dev_info,
718 u32 enable)
719{
720 int rc = 0;
721 struct snddev_icodec_state *icodec;
722 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
723
724 if (!dev_info) {
725 MM_ERR("invalid dev_info\n");
726 rc = -EINVAL;
727 goto error;
728 }
729
730 icodec = dev_info->private_data;
731
732 if (icodec->data->capability & SNDDEV_CAP_RX) {
733 mutex_lock(&drv->rx_lock);
734 if (!drv->rx_active || !dev_info->opened) {
735 MM_ERR("dev not active\n");
736 rc = -EPERM;
737 mutex_unlock(&drv->rx_lock);
738 goto error;
739 }
740 rc = adie_codec_enable_sidetone(icodec->adie_path, enable);
741 mutex_unlock(&drv->rx_lock);
742 } else {
743 rc = -EINVAL;
744 MM_ERR("rx device only\n");
745 }
746
747error:
748 return rc;
749
750}
751
752int snddev_icodec_set_device_volume(struct msm_snddev_info *dev_info,
753 u32 volume)
754{
755 struct snddev_icodec_state *icodec;
756 struct mutex *lock;
757 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
758 int rc = -EPERM;
759
760 if (!dev_info) {
761 MM_INFO("device not intilized.\n");
762 return -EINVAL;
763 }
764
765 icodec = dev_info->private_data;
766
767 if (!(icodec->data->dev_vol_type & (SNDDEV_DEV_VOL_DIGITAL
768 | SNDDEV_DEV_VOL_ANALOG))) {
769
770 MM_INFO("device %s does not support device volume "
771 "control.", dev_info->name);
772 return -EPERM;
773 }
774 dev_info->dev_volume = volume;
775
776 if (icodec->data->capability & SNDDEV_CAP_RX)
777 lock = &drv->rx_lock;
778 else if (icodec->data->capability & SNDDEV_CAP_LB)
779 lock = &drv->lb_lock;
780 else
781 lock = &drv->tx_lock;
782
783 mutex_lock(lock);
784
785 rc = snddev_icodec_set_device_volume_impl(dev_info,
786 dev_info->dev_volume);
787 mutex_unlock(lock);
788 return rc;
789}
790
791static int snddev_icodec_probe(struct platform_device *pdev)
792{
793 int rc = 0, i;
794 struct snddev_icodec_data *pdata;
795 struct msm_snddev_info *dev_info;
796 struct snddev_icodec_state *icodec;
797
798 if (!pdev || !pdev->dev.platform_data) {
799 printk(KERN_ALERT "Invalid caller \n");
800 rc = -1;
801 goto error;
802 }
803 pdata = pdev->dev.platform_data;
804 if ((pdata->capability & SNDDEV_CAP_RX) &&
805 (pdata->capability & SNDDEV_CAP_TX)) {
806 MM_ERR("invalid device data either RX or TX\n");
807 goto error;
808 }
809 icodec = kzalloc(sizeof(struct snddev_icodec_state), GFP_KERNEL);
810 if (!icodec) {
811 rc = -ENOMEM;
812 goto error;
813 }
814 dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
815 if (!dev_info) {
816 kfree(icodec);
817 rc = -ENOMEM;
818 goto error;
819 }
820
821 dev_info->name = pdata->name;
822 dev_info->copp_id = pdata->copp_id;
823 dev_info->acdb_id = pdata->acdb_id;
824 dev_info->private_data = (void *) icodec;
825 dev_info->dev_ops.open = snddev_icodec_open;
826 dev_info->dev_ops.close = snddev_icodec_close;
827 dev_info->dev_ops.set_freq = snddev_icodec_set_freq;
828 dev_info->dev_ops.set_device_volume = snddev_icodec_set_device_volume;
829 dev_info->capability = pdata->capability;
830 dev_info->opened = 0;
831 msm_snddev_register(dev_info);
832 icodec->data = pdata;
833 icodec->sample_rate = pdata->default_sample_rate;
834 dev_info->sample_rate = pdata->default_sample_rate;
835 if (pdata->capability & SNDDEV_CAP_RX) {
836 for (i = 0; i < VOC_RX_VOL_ARRAY_NUM; i++) {
837 dev_info->max_voc_rx_vol[i] =
838 pdata->max_voice_rx_vol[i];
839 dev_info->min_voc_rx_vol[i] =
840 pdata->min_voice_rx_vol[i];
841 }
842 /*sidetone is enabled only for the device which
843 property set for side tone*/
844 if (pdata->property & SIDE_TONE_MASK)
845 dev_info->dev_ops.enable_sidetone =
846 snddev_icodec_enable_sidetone;
847 else
848 dev_info->dev_ops.enable_sidetone = NULL;
849 } else {
850 dev_info->dev_ops.enable_sidetone = NULL;
851 }
852
853error:
854 return rc;
855}
856
857static int snddev_icodec_remove(struct platform_device *pdev)
858{
859 return 0;
860}
861
862static struct platform_driver snddev_icodec_driver = {
863 .probe = snddev_icodec_probe,
864 .remove = snddev_icodec_remove,
865 .driver = { .name = "snddev_icodec" }
866};
867
868#ifdef CONFIG_DEBUG_FS
869static struct dentry *debugfs_sdev_dent;
870static struct dentry *debugfs_afelb;
871static struct dentry *debugfs_adielb;
872static struct adie_codec_path *debugfs_rx_adie;
873static struct adie_codec_path *debugfs_tx_adie;
874
875static int snddev_icodec_debug_open(struct inode *inode, struct file *file)
876{
877 file->private_data = inode->i_private;
878 MM_INFO("snddev_icodec: debug intf %s\n", (char *) file->private_data);
879 return 0;
880}
881
882static void debugfs_adie_loopback(u32 loop)
883{
884 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
885
886 if (loop) {
887
888 /* enable MI2S RX master block */
889 /* enable MI2S RX bit clock */
890 clk_set_rate(drv->rx_mclk,
891 SNDDEV_ICODEC_CLK_RATE(8000));
Vinay Vakac82b9b82012-07-02 15:33:38 +0530892 clk_prepare_enable(drv->rx_mclk);
893 clk_prepare_enable(drv->rx_sclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894
895 MM_INFO("configure ADIE RX path\n");
896 /* Configure ADIE */
897 adie_codec_open(&debug_rx_profile, &debugfs_rx_adie);
898 adie_codec_setpath(debugfs_rx_adie, 8000, 256);
899 adie_codec_proceed_stage(debugfs_rx_adie,
900 ADIE_CODEC_DIGITAL_ANALOG_READY);
901
902 MM_INFO("Enable Handset Mic bias\n");
903 pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_PWM_TCXO);
904 /* enable MI2S TX master block */
905 /* enable MI2S TX bit clock */
906 clk_set_rate(drv->tx_mclk,
907 SNDDEV_ICODEC_CLK_RATE(8000));
Vinay Vakac82b9b82012-07-02 15:33:38 +0530908 clk_prepare_enable(drv->tx_mclk);
909 clk_prepare_enable(drv->tx_sclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910
911 MM_INFO("configure ADIE TX path\n");
912 /* Configure ADIE */
913 adie_codec_open(&debug_tx_lb_profile, &debugfs_tx_adie);
914 adie_codec_setpath(debugfs_tx_adie, 8000, 256);
915 adie_codec_proceed_stage(debugfs_tx_adie,
916 ADIE_CODEC_DIGITAL_ANALOG_READY);
917 } else {
918 /* Disable ADIE */
919 adie_codec_proceed_stage(debugfs_rx_adie,
920 ADIE_CODEC_DIGITAL_OFF);
921 adie_codec_close(debugfs_rx_adie);
922 adie_codec_proceed_stage(debugfs_tx_adie,
923 ADIE_CODEC_DIGITAL_OFF);
924 adie_codec_close(debugfs_tx_adie);
925
926 pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_OFF);
927
928 /* Disable MI2S RX master block */
929 /* Disable MI2S RX bit clock */
Vinay Vakac82b9b82012-07-02 15:33:38 +0530930 clk_disable_unprepare(drv->rx_sclk);
931 clk_disable_unprepare(drv->rx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932
933 /* Disable MI2S TX master block */
934 /* Disable MI2S TX bit clock */
Vinay Vakac82b9b82012-07-02 15:33:38 +0530935 clk_disable_unprepare(drv->tx_sclk);
936 clk_disable_unprepare(drv->tx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937 }
938}
939
940static void debugfs_afe_loopback(u32 loop)
941{
942 int trc;
943 struct msm_afe_config afe_config;
944 struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
945 struct lpa_codec_config lpa_config;
946
947 if (loop) {
948 /* Vote for SMPS mode*/
949 pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
950 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_PWM);
951
952 /* enable MI2S RX master block */
953 /* enable MI2S RX bit clock */
954 trc = clk_set_rate(drv->rx_mclk,
955 SNDDEV_ICODEC_CLK_RATE(8000));
956 if (IS_ERR_VALUE(trc))
957 MM_ERR("failed to set clk rate\n");
Vinay Vakac82b9b82012-07-02 15:33:38 +0530958 clk_prepare_enable(drv->rx_mclk);
959 clk_prepare_enable(drv->rx_sclk);
960 clk_prepare_enable(drv->lpa_p_clk);
961 clk_prepare_enable(drv->lpa_codec_clk);
962 clk_prepare_enable(drv->lpa_core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 /* Enable LPA sub system
964 */
965 drv->lpa = lpa_get();
966 if (!drv->lpa)
967 MM_ERR("failed to enable lpa\n");
968 lpa_config.sample_rate = 8000;
969 lpa_config.sample_width = 16;
970 lpa_config.output_interface = LPA_OUTPUT_INTF_WB_CODEC;
971 lpa_config.num_channels = 1;
972 lpa_cmd_codec_config(drv->lpa, &lpa_config);
973 /* Set audio interconnect reg to LPA */
974 audio_interct_codec(AUDIO_INTERCT_LPA);
975 mi2s_set_codec_output_path(MI2S_CHAN_MONO_PACKED, WT_16_BIT);
976 MM_INFO("configure ADIE RX path\n");
977 /* Configure ADIE */
978 adie_codec_open(&debug_rx_profile, &debugfs_rx_adie);
979 adie_codec_setpath(debugfs_rx_adie, 8000, 256);
980 lpa_cmd_enable_codec(drv->lpa, 1);
981
982 /* Start AFE for RX */
983 afe_config.sample_rate = 0x8;
984 afe_config.channel_mode = 1;
985 afe_config.volume = AFE_VOLUME_UNITY;
986 MM_INFO("enable afe\n");
987 trc = afe_enable(AFE_HW_PATH_CODEC_RX, &afe_config);
988 if (IS_ERR_VALUE(trc))
989 MM_ERR("fail to enable afe RX\n");
990 adie_codec_proceed_stage(debugfs_rx_adie,
991 ADIE_CODEC_DIGITAL_READY);
992 adie_codec_proceed_stage(debugfs_rx_adie,
993 ADIE_CODEC_DIGITAL_ANALOG_READY);
994
995 /* Vote for PWM mode*/
996 pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
997 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_PWM);
998
999 MM_INFO("Enable Handset Mic bias\n");
1000 pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_PWM_TCXO);
1001
1002 /* enable MI2S TX master block */
1003 /* enable MI2S TX bit clock */
1004 clk_set_rate(drv->tx_mclk,
1005 SNDDEV_ICODEC_CLK_RATE(8000));
Vinay Vakac82b9b82012-07-02 15:33:38 +05301006 clk_prepare_enable(drv->tx_mclk);
1007 clk_prepare_enable(drv->tx_sclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001008 /* Set MI2S */
1009 mi2s_set_codec_input_path(MI2S_CHAN_MONO_PACKED, WT_16_BIT);
1010 MM_INFO("configure ADIE TX path\n");
1011 /* Configure ADIE */
1012 adie_codec_open(&debug_tx_profile, &debugfs_tx_adie);
1013 adie_codec_setpath(debugfs_tx_adie, 8000, 256);
1014 adie_codec_proceed_stage(debugfs_tx_adie,
1015 ADIE_CODEC_DIGITAL_READY);
1016 adie_codec_proceed_stage(debugfs_tx_adie,
1017 ADIE_CODEC_DIGITAL_ANALOG_READY);
1018 /* Start AFE for TX */
1019 afe_config.sample_rate = 0x8;
1020 afe_config.channel_mode = 1;
1021 afe_config.volume = AFE_VOLUME_UNITY;
1022 trc = afe_enable(AFE_HW_PATH_CODEC_TX, &afe_config);
1023 if (IS_ERR_VALUE(trc))
1024 MM_ERR("failed to enable AFE TX\n");
1025 /* Set the volume level to non unity, to avoid
1026 loopback effect */
1027 afe_device_volume_ctrl(AFE_HW_PATH_CODEC_RX, 0x0500);
1028
1029 /* enable afe loopback */
1030 afe_loopback(1);
1031 MM_INFO("AFE loopback enabled\n");
1032 } else {
1033 /* disable afe loopback */
1034 afe_loopback(0);
1035 /* Remove the vote for SMPS mode*/
1036 pmapp_smps_mode_vote(SMPS_AUDIO_PLAYBACK_ID,
1037 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
1038
1039 /* Disable ADIE */
1040 adie_codec_proceed_stage(debugfs_rx_adie,
1041 ADIE_CODEC_DIGITAL_OFF);
1042 adie_codec_close(debugfs_rx_adie);
1043 /* Disable AFE for RX */
1044 afe_disable(AFE_HW_PATH_CODEC_RX);
1045
1046 /* Disable LPA Sub system */
1047 lpa_cmd_enable_codec(drv->lpa, 0);
1048 lpa_put(drv->lpa);
1049
1050 /* Disable LPA clocks */
Vinay Vakac82b9b82012-07-02 15:33:38 +05301051 clk_disable_unprepare(drv->lpa_p_clk);
1052 clk_disable_unprepare(drv->lpa_codec_clk);
1053 clk_disable_unprepare(drv->lpa_core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054
1055 /* Disable MI2S RX master block */
1056 /* Disable MI2S RX bit clock */
Vinay Vakac82b9b82012-07-02 15:33:38 +05301057 clk_disable_unprepare(drv->rx_sclk);
1058 clk_disable_unprepare(drv->rx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059
1060 pmapp_smps_mode_vote(SMPS_AUDIO_RECORD_ID,
1061 PMAPP_VREG_S4, PMAPP_SMPS_MODE_VOTE_DONTCARE);
1062
1063 /* Disable AFE for TX */
1064 afe_disable(AFE_HW_PATH_CODEC_TX);
1065
1066 /* Disable ADIE */
1067 adie_codec_proceed_stage(debugfs_tx_adie,
1068 ADIE_CODEC_DIGITAL_OFF);
1069 adie_codec_close(debugfs_tx_adie);
1070 /* Disable MI2S TX master block */
1071 /* Disable MI2S TX bit clock */
Vinay Vakac82b9b82012-07-02 15:33:38 +05301072 clk_disable_unprepare(drv->tx_sclk);
1073 clk_disable_unprepare(drv->tx_mclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074 pmic_hsed_enable(PM_HSED_CONTROLLER_0, PM_HSED_ENABLE_OFF);
1075 MM_INFO("AFE loopback disabled\n");
1076 }
1077}
1078
1079static ssize_t snddev_icodec_debug_write(struct file *filp,
1080 const char __user *ubuf, size_t cnt, loff_t *ppos)
1081{
1082 char *lb_str = filp->private_data;
1083 char cmd;
1084
1085 if (get_user(cmd, ubuf))
1086 return -EFAULT;
1087
1088 MM_INFO("%s %c\n", lb_str, cmd);
1089
1090 if (!strcmp(lb_str, "adie_loopback")) {
1091 switch (cmd) {
1092 case '1':
1093 debugfs_adie_loopback(1);
1094 break;
1095 case '0':
1096 debugfs_adie_loopback(0);
1097 break;
1098 }
1099 } else if (!strcmp(lb_str, "afe_loopback")) {
1100 switch (cmd) {
1101 case '1':
1102 debugfs_afe_loopback(1);
1103 break;
1104 case '0':
1105 debugfs_afe_loopback(0);
1106 break;
1107 }
1108 }
1109
1110 return cnt;
1111}
1112
1113static const struct file_operations snddev_icodec_debug_fops = {
1114 .open = snddev_icodec_debug_open,
1115 .write = snddev_icodec_debug_write
1116};
1117#endif
1118
1119static int __init snddev_icodec_init(void)
1120{
1121 s32 rc;
1122 struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
1123
1124 rc = platform_driver_register(&snddev_icodec_driver);
1125 if (IS_ERR_VALUE(rc))
1126 goto error_platform_driver;
1127 icodec_drv->rx_mclk = clk_get(NULL, "mi2s_codec_rx_m_clk");
1128 if (IS_ERR(icodec_drv->rx_mclk))
1129 goto error_rx_mclk;
1130 icodec_drv->rx_sclk = clk_get(NULL, "mi2s_codec_rx_s_clk");
1131 if (IS_ERR(icodec_drv->rx_sclk))
1132 goto error_rx_sclk;
1133 icodec_drv->tx_mclk = clk_get(NULL, "mi2s_codec_tx_m_clk");
1134 if (IS_ERR(icodec_drv->tx_mclk))
1135 goto error_tx_mclk;
1136 icodec_drv->tx_sclk = clk_get(NULL, "mi2s_codec_tx_s_clk");
1137 if (IS_ERR(icodec_drv->tx_sclk))
1138 goto error_tx_sclk;
1139 icodec_drv->lpa_codec_clk = clk_get(NULL, "lpa_codec_clk");
1140 if (IS_ERR(icodec_drv->lpa_codec_clk))
1141 goto error_lpa_codec_clk;
1142 icodec_drv->lpa_core_clk = clk_get(NULL, "lpa_core_clk");
1143 if (IS_ERR(icodec_drv->lpa_core_clk))
1144 goto error_lpa_core_clk;
1145 icodec_drv->lpa_p_clk = clk_get(NULL, "lpa_pclk");
1146 if (IS_ERR(icodec_drv->lpa_p_clk))
1147 goto error_lpa_p_clk;
1148
1149#ifdef CONFIG_DEBUG_FS
1150 debugfs_sdev_dent = debugfs_create_dir("snddev_icodec", 0);
1151 if (debugfs_sdev_dent) {
1152 debugfs_afelb = debugfs_create_file("afe_loopback",
1153 S_IFREG | S_IWUGO, debugfs_sdev_dent,
1154 (void *) "afe_loopback", &snddev_icodec_debug_fops);
1155 debugfs_adielb = debugfs_create_file("adie_loopback",
1156 S_IFREG | S_IWUGO, debugfs_sdev_dent,
1157 (void *) "adie_loopback", &snddev_icodec_debug_fops);
1158 }
1159#endif
1160 mutex_init(&icodec_drv->rx_lock);
1161 mutex_init(&icodec_drv->lb_lock);
1162 mutex_init(&icodec_drv->tx_lock);
1163 icodec_drv->rx_active = 0;
1164 icodec_drv->tx_active = 0;
1165 icodec_drv->lpa = NULL;
Stephen Boyd2fcabf92012-05-30 10:41:11 -07001166 pm_qos_add_request(&icodec_drv->tx_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
1167 PM_QOS_DEFAULT_VALUE);
1168 pm_qos_add_request(&icodec_drv->rx_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
1169 PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 return 0;
1171
1172error_lpa_p_clk:
1173 clk_put(icodec_drv->lpa_core_clk);
1174error_lpa_core_clk:
1175 clk_put(icodec_drv->lpa_codec_clk);
1176error_lpa_codec_clk:
1177 clk_put(icodec_drv->tx_sclk);
1178error_tx_sclk:
1179 clk_put(icodec_drv->tx_mclk);
1180error_tx_mclk:
1181 clk_put(icodec_drv->rx_sclk);
1182error_rx_sclk:
1183 clk_put(icodec_drv->rx_mclk);
1184error_rx_mclk:
1185 platform_driver_unregister(&snddev_icodec_driver);
1186error_platform_driver:
1187
1188 MM_ERR("encounter error\n");
1189 return -ENODEV;
1190}
1191
1192static void __exit snddev_icodec_exit(void)
1193{
1194 struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
1195
1196#ifdef CONFIG_DEBUG_FS
1197 if (debugfs_afelb)
1198 debugfs_remove(debugfs_afelb);
1199 if (debugfs_adielb)
1200 debugfs_remove(debugfs_adielb);
1201 if (debugfs_sdev_dent)
1202 debugfs_remove(debugfs_sdev_dent);
1203#endif
1204 platform_driver_unregister(&snddev_icodec_driver);
1205
1206 clk_put(icodec_drv->rx_sclk);
1207 clk_put(icodec_drv->rx_mclk);
1208 clk_put(icodec_drv->tx_sclk);
1209 clk_put(icodec_drv->tx_mclk);
1210 return;
1211}
1212
1213module_init(snddev_icodec_init);
1214module_exit(snddev_icodec_exit);
1215
1216MODULE_DESCRIPTION("ICodec Sound Device driver");
1217MODULE_VERSION("1.0");
1218MODULE_LICENSE("GPL v2");