blob: f3ccb339dc30ce4c5618a934a6c005491e6bb65f [file] [log] [blame]
Venkat Sudhir459d6f52012-12-04 12:00:13 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Venkat Sudhir64f66302012-10-30 09:30:16 -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/clk.h>
14#include <linux/delay.h>
15#include <linux/gpio.h>
16#include <linux/of_gpio.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/qpnp/clkdiv.h>
20#include <sound/core.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <sound/pcm.h>
24#include <sound/jack.h>
Venkat Sudhir56959f12013-01-05 15:45:46 -080025#include <sound/q6afe-v2.h>
Venkat Sudhir64f66302012-10-30 09:30:16 -070026#include <asm/mach-types.h>
27#include <mach/socinfo.h>
28#include <qdsp6v2/msm-pcm-routing-v2.h>
29#include "../codecs/wcd9320.h"
Prashanth Reddyf9536572013-02-13 12:17:08 -080030#include <linux/io.h>
Venkat Sudhir64f66302012-10-30 09:30:16 -070031
Venkat Sudhir64f66302012-10-30 09:30:16 -070032/* Spk control */
33#define MDM9625_SPK_ON 1
34
35/* MDM9625 run Taiko at 12.288 Mhz.
36 * At present MDM supports 12.288mhz
37 * only. Taiko supports 9.6 MHz also.
38 */
39#define MDM_MCLK_CLK_12P288MHZ 12288000
40#define MDM_MCLK_CLK_9P6HZ 9600000
41#define MDM_IBIT_CLK_DIV_1P56MHZ 7
Prashanth Reddyf9536572013-02-13 12:17:08 -080042#define MDM_MI2S_AUXPCM_PRIM_INTF 0
43#define MDM_MI2S_AUXPCM_SEC_INTF 1
Venkat Sudhir459d6f52012-12-04 12:00:13 -080044
Prashanth Reddyf9536572013-02-13 12:17:08 -080045#define LPAIF_OFFSET 0xFE000000
46#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
47#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
48
49#define I2S_SEL 0
50#define I2S_PCM_SEL 1
51#define I2S_PCM_SEL_OFFSET 1
Venkat Sudhir64f66302012-10-30 09:30:16 -070052
53/* Machine driver Name*/
54#define MDM9625_MACHINE_DRV_NAME "mdm9625-asoc-taiko"
55
Venkat Sudhir459d6f52012-12-04 12:00:13 -080056/* I2S GPIO */
57struct msm_i2s_gpio {
58 unsigned gpio_no;
59 const char *gpio_name;
60};
61
62struct msm_i2s_ctrl {
63 struct msm_i2s_gpio *pin_data;
64 struct clk *cdc_bit_clk;
65 u32 cnt;
Venkat Sudhir64f66302012-10-30 09:30:16 -070066};
Venkat Sudhir459d6f52012-12-04 12:00:13 -080067struct mdm9625_machine_data {
68 u32 mclk_freq;
69 struct msm_i2s_gpio *mclk_pin;
70 struct msm_i2s_ctrl *pri_ctrl;
Venkat Sudhir56959f12013-01-05 15:45:46 -080071 u32 prim_clk_usrs;
Venkat Sudhir64f66302012-10-30 09:30:16 -070072};
Venkat Sudhir64f66302012-10-30 09:30:16 -070073
Venkat Sudhir56959f12013-01-05 15:45:46 -080074static const struct afe_clk_cfg lpass_default = {
75 AFE_API_VERSION_I2S_CONFIG,
76 Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
77 Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
78 Q6AFE_LPASS_CLK_SRC_INTERNAL,
79 Q6AFE_LPASS_CLK_ROOT_DEFAULT,
80 Q6AFE_LPASS_MODE_BOTH_VALID,
81 0,
82};
83
84
Venkat Sudhir459d6f52012-12-04 12:00:13 -080085#define GPIO_NAME_INDEX 0
86#define DT_PARSE_INDEX 1
87
Prashanth Reddyf9536572013-02-13 12:17:08 -080088static int mdm9625_auxpcm_rate = 8000;
89void *lpaif_pri_muxsel_virt_addr;
Venkat Sudhir459d6f52012-12-04 12:00:13 -080090
91static char *mdm_i2s_gpio_name[][2] = {
92 {"PRIM_MI2S_WS", "prim-i2s-gpio-ws"},
93 {"PRIM_MI2S_DIN", "prim-i2s-gpio-din"},
94 {"PRIM_MI2S_DOUT", "prim-i2s-gpio-dout"},
95 {"PRIM_MI2S_SCLK", "prim-i2s-gpio-sclk"},
Venkat Sudhir64f66302012-10-30 09:30:16 -070096};
Venkat Sudhir459d6f52012-12-04 12:00:13 -080097
98static char *mdm_mclk_gpio[][2] = {
99 {"MI2S_MCLK", "prim-i2s-gpio-mclk"},
100};
101
Venkat Sudhir64f66302012-10-30 09:30:16 -0700102static struct mutex cdc_mclk_mutex;
103static int mdm9625_mi2s_rx_ch = 1;
104static int mdm9625_mi2s_tx_ch = 1;
105static int msm_spk_control;
Prashanth Reddyf9536572013-02-13 12:17:08 -0800106static atomic_t aux_ref_count;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700107static atomic_t mi2s_ref_count;
108
Venkat Sudhir64f66302012-10-30 09:30:16 -0700109static int mdm9625_enable_codec_ext_clk(struct snd_soc_codec *codec,
110 int enable, bool dapm);
111
112void *def_taiko_mbhc_cal(void);
113
114static struct wcd9xxx_mbhc_config mbhc_cfg = {
115 .read_fw_bin = false,
116 .calibration = NULL,
117 .micbias = MBHC_MICBIAS2,
118 .mclk_cb_fn = mdm9625_enable_codec_ext_clk,
119 .mclk_rate = MDM_MCLK_CLK_12P288MHZ,
120 .gpio = 0,
121 .gpio_irq = 0,
122 .gpio_level_insert = 1,
123 .detect_extn_cable = true,
124 .insert_detect = true,
125 .swap_gnd_mic = NULL,
126};
127
128#define WCD9XXX_MBHC_DEF_BUTTONS 8
129#define WCD9XXX_MBHC_DEF_RLOADS 5
130
Prashanth Reddyf9536572013-02-13 12:17:08 -0800131static int mdm9625_set_gpio(struct snd_pcm_substream *substream,
132 u32 intf)
Venkat Sudhir64f66302012-10-30 09:30:16 -0700133{
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800134 struct snd_soc_pcm_runtime *rtd = substream->private_data;
135 struct snd_soc_card *card = rtd->card;
136 struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
137 struct msm_i2s_ctrl *i2s_ctrl = NULL;
138 struct msm_i2s_gpio *pin_data = NULL;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700139 int rtn = 0;
140 int i;
141 int j;
142
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800143 if (pdata == NULL) {
144 pr_err("%s: pdata is NULL\n", __func__);
145 rtn = -EINVAL;
146 goto err;
147 }
148
Prashanth Reddyf9536572013-02-13 12:17:08 -0800149 if (intf == MDM_MI2S_AUXPCM_PRIM_INTF) {
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800150 i2s_ctrl = pdata->pri_ctrl;
Prashanth Reddyf9536572013-02-13 12:17:08 -0800151 }
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800152 else {
153 pr_err("%s: Wrong I2S Interface\n", __func__);
154 rtn = -EINVAL;
155 goto err;
156 }
157 if (i2s_ctrl == NULL || i2s_ctrl->pin_data == NULL) {
158 pr_err("%s: Intf ptr NULL\n", __func__);
159 rtn = -EINVAL;
160 goto err;
161 }
162 pin_data = i2s_ctrl->pin_data;
163 for (i = 0; i < i2s_ctrl->cnt; i++, pin_data++) {
164 rtn = gpio_request(pin_data->gpio_no,
165 pin_data->gpio_name);
166 pr_debug("%s: gpio = %d, gpio name = %s\n"
167 "rtn = %d\n", __func__,
168 pin_data->gpio_no,
169 pin_data->gpio_name,
170 rtn);
171 if (rtn) {
172 pr_err("%s: Failed to request gpio %d\n",
173 __func__, pin_data->gpio_no);
174 /* Release all the GPIO on failure */
175 for (j = i; j >= 0; j--)
176 gpio_free(pin_data->gpio_no);
177 goto err;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700178 }
Venkat Sudhir64f66302012-10-30 09:30:16 -0700179 }
180err:
181 return rtn;
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800182
Venkat Sudhir64f66302012-10-30 09:30:16 -0700183}
184
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800185static int mdm9625_mi2s_free_gpios(struct snd_pcm_substream *substream,
186 u32 intf)
Venkat Sudhir64f66302012-10-30 09:30:16 -0700187{
188 int i;
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800189 struct snd_soc_pcm_runtime *rtd = substream->private_data;
190 struct snd_soc_card *card = rtd->card;
191 struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
192 struct msm_i2s_ctrl *i2s_ctrl = NULL;
193 struct msm_i2s_gpio *pin_data = NULL;
194 int rtn = 0;
195
Venkat Sudhir64f66302012-10-30 09:30:16 -0700196 pr_debug("%s:", __func__);
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800197 if (pdata == NULL) {
198 pr_err("%s: pdata is NULL\n", __func__);
199 rtn = -EINVAL;
200 goto err;
201 }
Prashanth Reddyf9536572013-02-13 12:17:08 -0800202 if (intf == MDM_MI2S_AUXPCM_PRIM_INTF) {
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800203 i2s_ctrl = pdata->pri_ctrl;
Prashanth Reddyf9536572013-02-13 12:17:08 -0800204 }
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800205 else {
206 pr_debug("%s: Wrong Interface\n", __func__);
207 rtn = -EINVAL;
208 goto err;
209 }
210 if (i2s_ctrl == NULL || i2s_ctrl->pin_data == NULL) {
211 pr_err("%s: Intf ptr NULL\n", __func__);
212 rtn = -EINVAL;
213 goto err;
214 }
215 pin_data = i2s_ctrl->pin_data;
216 for (i = 0; i < i2s_ctrl->cnt; i++, pin_data++) {
217 gpio_free(pin_data->gpio_no);
218 pr_debug("%s: gpio = %d, gpio name = %s\n",
219 __func__, pin_data->gpio_no,
220 pin_data->gpio_name);
221 }
222err:
223 return rtn;
224
Venkat Sudhir64f66302012-10-30 09:30:16 -0700225}
226static int mdm9625_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd, bool enable)
227{
Venkat Sudhir64f66302012-10-30 09:30:16 -0700228 struct snd_soc_card *card = rtd->card;
229 struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
Venkat Sudhir56959f12013-01-05 15:45:46 -0800230 struct afe_clk_cfg *lpass_clk = NULL;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700231 int ret = 0;
232
233 if (pdata == NULL) {
234 pr_err("%s:platform data is null\n", __func__);
Venkat Sudhir56959f12013-01-05 15:45:46 -0800235 return -ENOMEM;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700236 }
Venkat Sudhir56959f12013-01-05 15:45:46 -0800237 lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
238 if (lpass_clk == NULL) {
239 pr_err("%s:Failed to allocate memory\n", __func__);
240 return -ENOMEM;
241 }
242 memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
243 pr_debug("%s:enable = %x\n", __func__, enable);
Venkat Sudhir64f66302012-10-30 09:30:16 -0700244 if (enable) {
Venkat Sudhir56959f12013-01-05 15:45:46 -0800245 if (pdata->prim_clk_usrs == 0) {
246 lpass_clk->clk_val2 = pdata->mclk_freq;
247 lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_BOTH_VALID;
248 } else
249 lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
250 ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
251 if (ret < 0)
252 pr_err("%s:afe_set_lpass_clock failed\n", __func__);
253 else
254 pdata->prim_clk_usrs++;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700255 } else {
Venkat Sudhir56959f12013-01-05 15:45:46 -0800256 if (pdata->prim_clk_usrs > 0)
257 pdata->prim_clk_usrs--;
258 if (pdata->prim_clk_usrs == 0) {
259 lpass_clk->clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
260 lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_BOTH_VALID;
261 } else
262 lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID;
263 lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
264 ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
265 if (ret < 0)
266 pr_err("%s:afe_set_lpass_clock failed\n", __func__);
Venkat Sudhir64f66302012-10-30 09:30:16 -0700267 }
Venkat Sudhir56959f12013-01-05 15:45:46 -0800268 pr_debug("%s: clk 1 = %x clk2 = %x mode = %x\n",
269 __func__, lpass_clk->clk_val1,
270 lpass_clk->clk_val2,
271 lpass_clk->clk_set_mode);
272 kfree(lpass_clk);
Venkat Sudhir64f66302012-10-30 09:30:16 -0700273 return ret;
274}
275
276static void mdm9625_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
277{
278 struct snd_soc_pcm_runtime *rtd = substream->private_data;
279 int ret;
280 if (atomic_dec_return(&mi2s_ref_count) == 0) {
Prashanth Reddyf9536572013-02-13 12:17:08 -0800281 mdm9625_mi2s_free_gpios(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
Venkat Sudhir64f66302012-10-30 09:30:16 -0700282 ret = mdm9625_mi2s_clk_ctl(rtd, false);
283 if (ret < 0)
284 pr_err("%s:clock disable failed\n", __func__);
285 }
286}
287
288static int mdm9625_mi2s_startup(struct snd_pcm_substream *substream)
289{
290 struct snd_soc_pcm_runtime *rtd = substream->private_data;
291 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
292 struct snd_soc_dai *codec_dai = rtd->codec_dai;
293 int ret = 0;
294
295 if (atomic_inc_return(&mi2s_ref_count) == 1) {
Prashanth Reddyf9536572013-02-13 12:17:08 -0800296 if (lpaif_pri_muxsel_virt_addr != NULL)
297 iowrite32(I2S_SEL << I2S_PCM_SEL_OFFSET,
298 lpaif_pri_muxsel_virt_addr);
299 else
300 pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
301 __func__);
302 ret = mdm9625_set_gpio(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
303 if (ret < 0) {
304 pr_err("%s, GPIO setup failed\n", __func__);
305 return ret;
306 }
Venkat Sudhir64f66302012-10-30 09:30:16 -0700307 ret = mdm9625_mi2s_clk_ctl(rtd, true);
308 if (ret < 0) {
309 pr_err("set format for codec dai failed\n");
310 return ret;
311 }
312 }
313 /* This sets the CONFIG PARAMETER WS_SRC.
314 * 1 means internal clock master mode.
315 * 0 means external clock slave mode.
316 */
317 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
318 if (ret < 0)
319 pr_err("set fmt cpu dai failed\n");
320
321 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
322 if (ret < 0)
323 pr_err("set fmt for codec dai failed\n");
324
325 return ret;
326}
327
Venkat Sudhir64f66302012-10-30 09:30:16 -0700328static int mdm9625_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
329 struct snd_pcm_hw_params *params)
330{
331 struct snd_interval *rate = hw_param_interval(params,
332 SNDRV_PCM_HW_PARAM_RATE);
333 struct snd_interval *channels = hw_param_interval(params,
334 SNDRV_PCM_HW_PARAM_CHANNELS);
335 rate->min = rate->max = 48000;
336 channels->min = channels->max = mdm9625_mi2s_rx_ch;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700337 return 0;
338}
339
340static int mdm9625_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
341 struct snd_pcm_hw_params *params)
342{
343 struct snd_interval *rate = hw_param_interval(params,
344 SNDRV_PCM_HW_PARAM_RATE);
345 struct snd_interval *channels = hw_param_interval(params,
346 SNDRV_PCM_HW_PARAM_CHANNELS);
347 rate->min = rate->max = 48000;
348 channels->min = channels->max = mdm9625_mi2s_tx_ch;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700349 return 0;
350}
351
352
353static int mdm9625_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
354 struct snd_ctl_elem_value *ucontrol)
355{
356 pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
357 mdm9625_mi2s_rx_ch);
358 ucontrol->value.integer.value[0] = mdm9625_mi2s_rx_ch - 1;
359 return 0;
360}
361
362static int mdm9625_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
363 struct snd_ctl_elem_value *ucontrol)
364{
365 mdm9625_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
366 pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
367 mdm9625_mi2s_rx_ch);
368 return 1;
369}
370
371static int mdm9625_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_value *ucontrol)
373{
374 pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
375 mdm9625_mi2s_tx_ch);
376 ucontrol->value.integer.value[0] = mdm9625_mi2s_tx_ch - 1;
377 return 0;
378}
379
380static int mdm9625_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
381 struct snd_ctl_elem_value *ucontrol)
382{
383 mdm9625_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
384 pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
385 mdm9625_mi2s_tx_ch);
386 return 1;
387}
388
389
390static int mdm9625_mi2s_get_spk(struct snd_kcontrol *kcontrol,
391 struct snd_ctl_elem_value *ucontrol)
392{
393 pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
394 ucontrol->value.integer.value[0] = msm_spk_control;
395 return 0;
396}
397
398static void mdm_ext_control(struct snd_soc_codec *codec)
399{
400 struct snd_soc_dapm_context *dapm = &codec->dapm;
401 pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
402 mutex_lock(&dapm->codec->mutex);
403 if (msm_spk_control == MDM9625_SPK_ON) {
404 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
405 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
406 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
407 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
408 } else {
409 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
410 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
411 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
412 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
413 }
414 snd_soc_dapm_sync(dapm);
415 mutex_unlock(&dapm->codec->mutex);
416}
417
418static int mdm9625_mi2s_set_spk(struct snd_kcontrol *kcontrol,
419 struct snd_ctl_elem_value *ucontrol)
420{
421 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
422 pr_debug("%s()\n", __func__);
423 if (msm_spk_control == ucontrol->value.integer.value[0])
424 return 0;
425 msm_spk_control = ucontrol->value.integer.value[0];
426 mdm_ext_control(codec);
427 return 1;
428}
429
430static int mdm9625_enable_codec_ext_clk(struct snd_soc_codec *codec,
431 int enable, bool dapm)
432{
433 int ret = 0;
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800434 struct mdm9625_machine_data *pdata =
435 snd_soc_card_get_drvdata(codec->card);
Venkat Sudhir56959f12013-01-05 15:45:46 -0800436 struct afe_clk_cfg *lpass_clk = NULL;
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800437
Venkat Sudhir56959f12013-01-05 15:45:46 -0800438 pr_debug("%s: enable = %d codec name %s enable %x\n",
439 __func__, enable, codec->name, enable);
440 lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL);
441 if (lpass_clk == NULL) {
442 pr_err("%s:Failed to allocate memory\n", __func__);
443 return -ENOMEM;
444 }
Venkat Sudhir64f66302012-10-30 09:30:16 -0700445 mutex_lock(&cdc_mclk_mutex);
Venkat Sudhir56959f12013-01-05 15:45:46 -0800446 memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg));
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800447 if (enable) {
Venkat Sudhir56959f12013-01-05 15:45:46 -0800448 if (pdata->prim_clk_usrs == 0) {
449 lpass_clk->clk_val2 = pdata->mclk_freq;
450 lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
451 ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
452 if (ret < 0) {
453 pr_err("%s:afe_set_lpass_clock failed\n",
454 __func__);
455 goto err;
456 }
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800457 }
Venkat Sudhir56959f12013-01-05 15:45:46 -0800458 pdata->prim_clk_usrs++;
Venkat Sudhir64f66302012-10-30 09:30:16 -0700459 taiko_mclk_enable(codec, 1, dapm);
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800460 } else {
Venkat Sudhir56959f12013-01-05 15:45:46 -0800461 if (pdata->prim_clk_usrs > 0)
462 pdata->prim_clk_usrs--;
463 if (pdata->prim_clk_usrs == 0) {
464 lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID;
465 lpass_clk->clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
466 ret = afe_set_lpass_clock(MI2S_RX, lpass_clk);
467 if (ret < 0) {
468 pr_err("%s:afe_set_lpass_clock failed\n",
469 __func__);
470 goto err;
471 }
472 }
Venkat Sudhir64f66302012-10-30 09:30:16 -0700473 taiko_mclk_enable(codec, 0, dapm);
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800474 }
Venkat Sudhir56959f12013-01-05 15:45:46 -0800475 pr_debug("%s: clk2 = %x mode = %x\n",
476 __func__, lpass_clk->clk_val2,
477 lpass_clk->clk_set_mode);
478err:
Venkat Sudhir64f66302012-10-30 09:30:16 -0700479 mutex_unlock(&cdc_mclk_mutex);
Venkat Sudhir56959f12013-01-05 15:45:46 -0800480 kfree(lpass_clk);
Venkat Sudhir64f66302012-10-30 09:30:16 -0700481 return ret;
482}
483
484static int mdm9625_mclk_event(struct snd_soc_dapm_widget *w,
485 struct snd_kcontrol *kcontrol, int event)
486{
487 pr_debug("%s: event = %d\n", __func__, event);
488 switch (event) {
489 case SND_SOC_DAPM_PRE_PMU:
490 return mdm9625_enable_codec_ext_clk(w->codec, 1, true);
491 case SND_SOC_DAPM_POST_PMD:
492 return mdm9625_enable_codec_ext_clk(w->codec, 0, true);
493 }
494 return 0;
495}
496
Prashanth Reddyf9536572013-02-13 12:17:08 -0800497static int mdm9625_auxpcm_startup(struct snd_pcm_substream *substream)
498{
499 struct snd_soc_pcm_runtime *rtd = substream->private_data;
500 int ret = 0;
501
502 if (atomic_inc_return(&aux_ref_count) == 1) {
503 if (lpaif_pri_muxsel_virt_addr != NULL)
504 iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
505 lpaif_pri_muxsel_virt_addr);
506 else
507 pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
508 __func__);
509 ret = mdm9625_set_gpio(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
510 if (ret < 0) {
511 pr_err("%s, GPIO setup failed\n", __func__);
512 return ret;
513 }
514 ret = mdm9625_mi2s_clk_ctl(rtd, true);
515 if (ret < 0) {
516 pr_err("set format for codec dai failed\n");
517 return ret;
518 }
519 }
520 return ret;
521}
522
523static void mdm9625_auxpcm_snd_shutdown(struct snd_pcm_substream *substream)
524{
525 struct snd_soc_pcm_runtime *rtd = substream->private_data;
526 int ret;
527
528 if (atomic_dec_return(&aux_ref_count) == 0) {
529 mdm9625_mi2s_free_gpios(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
530 ret = mdm9625_mi2s_clk_ctl(rtd, false);
531 if (ret < 0)
532 pr_err("%s:clock disable failed\n", __func__);
533 }
534}
535
536static int mdm9625_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_value *ucontrol)
538{
539 ucontrol->value.integer.value[0] = mdm9625_auxpcm_rate;
540 return 0;
541}
542
543static int mdm9625_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
545{
546 switch (ucontrol->value.integer.value[0]) {
547 case 0:
548 mdm9625_auxpcm_rate = 8000;
549 break;
550 case 1:
551 mdm9625_auxpcm_rate = 16000;
552 break;
553 default:
554 mdm9625_auxpcm_rate = 8000;
555 break;
556 }
557 return 0;
558}
559
560static int mdm9625_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
561 struct snd_pcm_hw_params *params)
562{
563 struct snd_interval *rate =
564 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
565
566 struct snd_interval *channels =
567 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
568
569 rate->min = rate->max = mdm9625_auxpcm_rate;
570 channels->min = channels->max = 1;
571
572 return 0;
573}
Venkat Sudhir64f66302012-10-30 09:30:16 -0700574
575static const struct snd_soc_dapm_widget mdm9625_dapm_widgets[] = {
576
577 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
578 mdm9625_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
579 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", NULL),
580 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", NULL),
581 SND_SOC_DAPM_SPK("Ext Spk Top Pos", NULL),
582 SND_SOC_DAPM_SPK("Ext Spk Top Neg", NULL),
583 SND_SOC_DAPM_MIC("Handset Mic", NULL),
584 SND_SOC_DAPM_MIC("Headset Mic", NULL),
585 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
586 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
587 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
588 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
589 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
590 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
591 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
592 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
593};
594
595static const char *const spk_function[] = {"Off", "On"};
596static const char *const mi2s_rx_ch_text[] = {"One", "Two"};
597static const char *const mi2s_tx_ch_text[] = {"One", "Two"};
Prashanth Reddyf9536572013-02-13 12:17:08 -0800598static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
Venkat Sudhir64f66302012-10-30 09:30:16 -0700599
600static const struct soc_enum mdm9625_enum[] = {
601 SOC_ENUM_SINGLE_EXT(2, spk_function),
602 SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text),
603 SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text),
Prashanth Reddyf9536572013-02-13 12:17:08 -0800604 SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
Venkat Sudhir64f66302012-10-30 09:30:16 -0700605};
606
607static const struct snd_kcontrol_new mdm_snd_controls[] = {
Prashanth Reddyf9536572013-02-13 12:17:08 -0800608 SOC_ENUM_EXT("Speaker Function", mdm9625_enum[0],
Venkat Sudhir64f66302012-10-30 09:30:16 -0700609 mdm9625_mi2s_get_spk,
610 mdm9625_mi2s_set_spk),
Prashanth Reddyf9536572013-02-13 12:17:08 -0800611 SOC_ENUM_EXT("MI2S_RX Channels", mdm9625_enum[1],
Venkat Sudhir64f66302012-10-30 09:30:16 -0700612 mdm9625_mi2s_rx_ch_get,
613 mdm9625_mi2s_rx_ch_put),
Prashanth Reddyf9536572013-02-13 12:17:08 -0800614 SOC_ENUM_EXT("MI2S_TX Channels", mdm9625_enum[2],
Venkat Sudhir64f66302012-10-30 09:30:16 -0700615 mdm9625_mi2s_tx_ch_get,
616 mdm9625_mi2s_tx_ch_put),
Prashanth Reddyf9536572013-02-13 12:17:08 -0800617 SOC_ENUM_EXT("AUX PCM SampleRate", mdm9625_enum[3],
618 mdm9625_auxpcm_rate_get,
619 mdm9625_auxpcm_rate_put),
Venkat Sudhir64f66302012-10-30 09:30:16 -0700620};
621
622static int mdm9625_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
623{
624 int err;
625 struct snd_soc_codec *codec = rtd->codec;
626 struct snd_soc_dapm_context *dapm = &codec->dapm;
627 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800628 pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
Venkat Sudhir64f66302012-10-30 09:30:16 -0700629
630 rtd->pmdown_time = 0;
631 err = snd_soc_add_codec_controls(codec, mdm_snd_controls,
632 ARRAY_SIZE(mdm_snd_controls));
633 if (err < 0)
634 return err;
635
636 snd_soc_dapm_new_controls(dapm, mdm9625_dapm_widgets,
637 ARRAY_SIZE(mdm9625_dapm_widgets));
638
639 /* After DAPM Enable pins alawys
640 * DAPM SYNC needs to be called.
641 */
642 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
643 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
644 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
645 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
646 snd_soc_dapm_sync(dapm);
647
Venkat Sudhir64f66302012-10-30 09:30:16 -0700648 mbhc_cfg.calibration = def_taiko_mbhc_cal();
649 if (mbhc_cfg.calibration)
650 err = taiko_hs_detect(codec, &mbhc_cfg);
651 else
652 err = -ENOMEM;
653 return err;
654}
655
656void *def_taiko_mbhc_cal(void)
657{
658 void *taiko_cal;
659 struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
660 u16 *btn_low, *btn_high;
661 u8 *n_ready, *n_cic, *gain;
662
663 taiko_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(WCD9XXX_MBHC_DEF_BUTTONS,
664 WCD9XXX_MBHC_DEF_RLOADS),
665 GFP_KERNEL);
666 if (!taiko_cal) {
667 pr_err("%s: out of memory\n", __func__);
668 return NULL;
669 }
670
671#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(taiko_cal)->X) = (Y))
672 S(t_ldoh, 100);
673 S(t_bg_fast_settle, 100);
674 S(t_shutdown_plug_rem, 255);
675 S(mbhc_nsa, 4);
676 S(mbhc_navg, 4);
677#undef S
678#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(taiko_cal)->X) = (Y))
679 S(mic_current, TAIKO_PID_MIC_5_UA);
680 S(hph_current, TAIKO_PID_MIC_5_UA);
681 S(t_mic_pid, 100);
682 S(t_ins_complete, 250);
683 S(t_ins_retry, 200);
684#undef S
685#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(taiko_cal)->X) = (Y))
686 S(v_no_mic, 30);
687 S(v_hs_max, 2400);
688#undef S
689#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal)->X) = (Y))
690 S(c[0], 62);
691 S(c[1], 124);
692 S(nc, 1);
693 S(n_meas, 3);
694 S(mbhc_nsc, 11);
695 S(n_btn_meas, 1);
696 S(n_btn_con, 2);
697 S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
698 S(v_btn_press_delta_sta, 100);
699 S(v_btn_press_delta_cic, 50);
700#undef S
701 btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal);
702 btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
703 btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
704 MBHC_BTN_DET_V_BTN_HIGH);
705 btn_low[0] = -50;
706 btn_high[0] = 10;
707 btn_low[1] = 11;
708 btn_high[1] = 52;
709 btn_low[2] = 53;
710 btn_high[2] = 94;
711 btn_low[3] = 95;
712 btn_high[3] = 133;
713 btn_low[4] = 134;
714 btn_high[4] = 171;
715 btn_low[5] = 172;
716 btn_high[5] = 208;
717 btn_low[6] = 209;
718 btn_high[6] = 244;
719 btn_low[7] = 245;
720 btn_high[7] = 330;
721 n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
722 n_ready[0] = 80;
723 n_ready[1] = 68;
724 n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
725 n_cic[0] = 60;
726 n_cic[1] = 47;
727 gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
728 gain[0] = 11;
729 gain[1] = 9;
730
731 return taiko_cal;
732}
733
734
735static struct snd_soc_ops mdm9625_mi2s_be_ops = {
736 .startup = mdm9625_mi2s_startup,
737 .shutdown = mdm9625_mi2s_snd_shutdown,
738};
739
Prashanth Reddyf9536572013-02-13 12:17:08 -0800740static struct snd_soc_ops mdm9625_auxpcm_be_ops = {
741 .startup = mdm9625_auxpcm_startup,
742 .shutdown = mdm9625_auxpcm_snd_shutdown,
743};
744
Venkat Sudhir64f66302012-10-30 09:30:16 -0700745/* Digital audio interface connects codec <---> CPU */
746static struct snd_soc_dai_link mdm9625_dai[] = {
747 /* FrontEnd DAI Links */
748 {
749 .name = "MDM9625 Media1",
750 .stream_name = "MultiMedia1",
751 .cpu_dai_name = "MultiMedia1",
Venkat Sudhirbd2d0372013-02-28 16:08:04 -0800752 .platform_name = "msm-pcm-dsp.0",
Venkat Sudhir64f66302012-10-30 09:30:16 -0700753 .dynamic = 1,
754 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
755 SND_SOC_DPCM_TRIGGER_POST},
756 .codec_dai_name = "snd-soc-dummy-dai",
757 .codec_name = "snd-soc-dummy",
758 .ignore_suspend = 1,
759 /* This dainlink has playback support */
760 .ignore_pmdown_time = 1,
761 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
762 },
763 {
Venkat Sudhir352b58b2013-03-24 23:47:06 -0700764 .name = "MDM9625 Media2",
765 .stream_name = "MultiMedia2",
766 .cpu_dai_name = "MultiMedia2",
767 .platform_name = "msm-pcm-dsp.0",
768 .dynamic = 1,
769 .codec_dai_name = "snd-soc-dummy-dai",
770 .codec_name = "snd-soc-dummy",
771 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
772 SND_SOC_DPCM_TRIGGER_POST},
773 .ignore_suspend = 1,
774 /* this dainlink has playback support */
775 .ignore_pmdown_time = 1,
776 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
777 },
778 {
Venkat Sudhir64f66302012-10-30 09:30:16 -0700779 .name = "MSM VoIP",
780 .stream_name = "VoIP",
781 .cpu_dai_name = "VoIP",
782 .platform_name = "msm-voip-dsp",
783 .dynamic = 1,
784 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
785 SND_SOC_DPCM_TRIGGER_POST},
786 .codec_dai_name = "snd-soc-dummy-dai",
787 .codec_name = "snd-soc-dummy",
788 .ignore_suspend = 1,
789 /* This dainlink has VOIP support */
790 .ignore_pmdown_time = 1,
791 .be_id = MSM_FRONTEND_DAI_VOIP,
792 },
793 {
794 .name = "Circuit-Switch Voice",
795 .stream_name = "CS-Voice",
796 .cpu_dai_name = "CS-VOICE",
797 .platform_name = "msm-pcm-voice",
798 .dynamic = 1,
799 .codec_dai_name = "snd-soc-dummy-dai",
800 .codec_name = "snd-soc-dummy",
801 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
802 SND_SOC_DPCM_TRIGGER_POST},
803 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
804 .ignore_suspend = 1,
805 /* This dainlink has Voice support */
806 .ignore_pmdown_time = 1,
807 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
808 },
809 {
810 .name = "MI2S Hostless",
811 .stream_name = "MI2S Hostless",
812 .cpu_dai_name = "MI2S_TX_HOSTLESS",
813 .platform_name = "msm-pcm-hostless",
814 .dynamic = 1,
815 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
816 SND_SOC_DPCM_TRIGGER_POST},
817 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
818 .ignore_suspend = 1,
819 .ignore_pmdown_time = 1,
820 /* This dainlink has MI2S support */
821 .codec_dai_name = "snd-soc-dummy-dai",
822 .codec_name = "snd-soc-dummy",
823 },
Venkat Sudhir1d7d84e2013-01-14 17:35:39 -0800824 {
825 .name = "VoLTE",
826 .stream_name = "VoLTE",
827 .cpu_dai_name = "VoLTE",
828 .platform_name = "msm-pcm-voice",
829 .dynamic = 1,
830 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
831 SND_SOC_DPCM_TRIGGER_POST},
832 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
833 .ignore_suspend = 1,
834 /* this dainlink has playback support */
835 .ignore_pmdown_time = 1,
836 .codec_dai_name = "snd-soc-dummy-dai",
837 .codec_name = "snd-soc-dummy",
838 .be_id = MSM_FRONTEND_DAI_VOLTE,
839 },
Venkat Sudhir5a9c2de2013-01-15 10:07:32 -0800840 { .name = "MSM AFE-PCM RX",
841 .stream_name = "AFE-PROXY RX",
842 .cpu_dai_name = "msm-dai-q6-dev.241",
843 .codec_name = "msm-stub-codec.1",
844 .codec_dai_name = "msm-stub-rx",
845 .platform_name = "msm-pcm-afe",
846 .ignore_suspend = 1,
847 /* this dainlink has playback support */
848 .ignore_pmdown_time = 1,
849 },
850 {
851 .name = "MSM AFE-PCM TX",
852 .stream_name = "AFE-PROXY TX",
853 .cpu_dai_name = "msm-dai-q6-dev.240",
854 .codec_name = "msm-stub-codec.1",
855 .codec_dai_name = "msm-stub-tx",
856 .platform_name = "msm-pcm-afe",
857 .ignore_suspend = 1,
858 },
Venkat Sudhir6f1a5302013-01-17 12:28:15 -0800859 {
860 .name = "DTMF RX Hostless",
861 .stream_name = "DTMF RX Hostless",
862 .cpu_dai_name = "DTMF_RX_HOSTLESS",
863 .platform_name = "msm-pcm-dtmf",
864 .dynamic = 1,
865 .codec_dai_name = "snd-soc-dummy-dai",
866 .codec_name = "snd-soc-dummy",
867 .trigger = {SND_SOC_DPCM_TRIGGER_POST,
868 SND_SOC_DPCM_TRIGGER_POST},
869 .ignore_suspend = 1,
870 .be_id = MSM_FRONTEND_DAI_DTMF_RX,
871 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
872 },
873 {
874 .name = "DTMF TX",
875 .stream_name = "DTMF TX",
876 .cpu_dai_name = "msm-dai-stub",
877 .platform_name = "msm-pcm-dtmf",
878 .codec_name = "msm-stub-codec.1",
879 .codec_dai_name = "msm-stub-tx",
880 .ignore_suspend = 1,
881 },
Venkat Sudhir64f66302012-10-30 09:30:16 -0700882 /* Backend DAI Links */
883 {
884 .name = LPASS_BE_MI2S_RX,
885 .stream_name = "MI2S Playback",
886 .cpu_dai_name = "msm-dai-q6-mi2s.0",
887 .platform_name = "msm-pcm-routing",
888 .codec_name = "taiko_codec",
889 .codec_dai_name = "taiko_i2s_rx1",
890 .no_pcm = 1,
891 .be_id = MSM_BACKEND_DAI_MI2S_RX,
892 .init = &mdm9625_mi2s_audrx_init,
893 .be_hw_params_fixup = &mdm9625_mi2s_rx_be_hw_params_fixup,
894 .ops = &mdm9625_mi2s_be_ops,
895 },
896 {
897 .name = LPASS_BE_MI2S_TX,
898 .stream_name = "MI2S Capture",
899 .cpu_dai_name = "msm-dai-q6-mi2s.0",
900 .platform_name = "msm-pcm-routing",
901 .codec_name = "taiko_codec",
902 .codec_dai_name = "taiko_i2s_tx1",
903 .no_pcm = 1,
904 .be_id = MSM_BACKEND_DAI_MI2S_TX,
905 .be_hw_params_fixup = &mdm9625_mi2s_tx_be_hw_params_fixup,
906 .ops = &mdm9625_mi2s_be_ops,
907 },
Venkat Sudhir5a9c2de2013-01-15 10:07:32 -0800908 {
909 .name = LPASS_BE_AFE_PCM_RX,
910 .stream_name = "AFE Playback",
911 .cpu_dai_name = "msm-dai-q6-dev.224",
912 .platform_name = "msm-pcm-routing",
913 .codec_name = "msm-stub-codec.1",
914 .codec_dai_name = "msm-stub-rx",
915 .no_pcm = 1,
916 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
917 },
918 {
919 .name = LPASS_BE_AFE_PCM_TX,
920 .stream_name = "AFE Capture",
921 .cpu_dai_name = "msm-dai-q6-dev.225",
922 .platform_name = "msm-pcm-routing",
923 .codec_name = "msm-stub-codec.1",
924 .codec_dai_name = "msm-stub-tx",
925 .no_pcm = 1,
926 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
927 },
Prashanth Reddyf9536572013-02-13 12:17:08 -0800928 {
929 .name = LPASS_BE_AUXPCM_RX,
930 .stream_name = "AUX PCM Playback",
931 .cpu_dai_name = "msm-dai-q6.4106",
932 .platform_name = "msm-pcm-routing",
933 .codec_name = "msm-stub-codec.1",
934 .codec_dai_name = "msm-stub-rx",
935 .no_pcm = 1,
936 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
937 .be_hw_params_fixup = mdm9625_auxpcm_be_params_fixup,
938 .ops = &mdm9625_auxpcm_be_ops,
939 .ignore_pmdown_time = 1,
940 /* this dainlink has playback support */
941 },
942 {
943 .name = LPASS_BE_AUXPCM_TX,
944 .stream_name = "AUX PCM Capture",
945 .cpu_dai_name = "msm-dai-q6.4107",
946 .platform_name = "msm-pcm-routing",
947 .codec_name = "msm-stub-codec.1",
948 .codec_dai_name = "msm-stub-tx",
949 .no_pcm = 1,
950 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
951 .be_hw_params_fixup = mdm9625_auxpcm_be_params_fixup,
952 .ops = &mdm9625_auxpcm_be_ops,
953 },
Venkat Sudhir64f66302012-10-30 09:30:16 -0700954};
955
956static struct snd_soc_card snd_soc_card_mdm9625 = {
957 .name = "mdm9625-taiko-i2s-snd-card",
958 .dai_link = mdm9625_dai,
959 .num_links = ARRAY_SIZE(mdm9625_dai),
960};
961
Prashanth Reddyf9536572013-02-13 12:17:08 -0800962static int mdm9625_dtparse(struct platform_device *pdev,
Venkat Sudhir459d6f52012-12-04 12:00:13 -0800963 struct mdm9625_machine_data **pdata)
964{
965 int ret = 0, i = 0;
966 struct msm_i2s_gpio *pin_data = NULL;
967 struct msm_i2s_ctrl *ctrl;
968 struct msm_i2s_gpio *mclk_pin = NULL;
969 unsigned int gpio_no[4];
970 unsigned int dt_mclk = 0;
971 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
972 int prim_cnt = 0;
973 pin_data = devm_kzalloc(&pdev->dev, (4 *
974 sizeof(struct msm_i2s_gpio)),
975 GFP_KERNEL);
976 mclk_pin = devm_kzalloc(&pdev->dev,
977 sizeof(struct msm_i2s_gpio),
978 GFP_KERNEL);
979
980 if (!pin_data || !mclk_pin) {
981 dev_err(&pdev->dev, "No memory for gpio\n");
982 ret = -ENOMEM;
983 goto err;
984 }
985 for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
986 gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
987 mdm_i2s_gpio_name[i][DT_PARSE_INDEX],
988 0, &flags);
989 if (gpio_no[i] > 0) {
990 pin_data[i].gpio_name =
991 mdm_i2s_gpio_name[prim_cnt][GPIO_NAME_INDEX];
992 pin_data[i].gpio_no = gpio_no[i];
993 dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
994 "0x%x\n", __func__,
995 pin_data[i].gpio_name,
996 pin_data[i].gpio_no);
997 prim_cnt++;
998 } else {
999 dev_err(&pdev->dev, "%s:Invalid I2S GPIO[%s] = %x\n",
1000 __func__,
1001 mdm_i2s_gpio_name[i][GPIO_NAME_INDEX],
1002 gpio_no[i]);
1003 ret = -ENODEV;
1004 goto err;
1005 }
1006 }
1007 for (i = 0; i < ARRAY_SIZE(mdm_mclk_gpio); i++) {
1008 dt_mclk = of_get_named_gpio_flags(pdev->dev.of_node,
1009 mdm_mclk_gpio[i][DT_PARSE_INDEX], 0,
1010 &flags);
1011 if (dt_mclk > 0) {
1012 mclk_pin->gpio_name =
1013 mdm_mclk_gpio[i][GPIO_NAME_INDEX];
1014 mclk_pin->gpio_no = dt_mclk;
1015 ret = gpio_request(mclk_pin->gpio_no,
1016 mclk_pin->gpio_name);
1017 dev_dbg(&pdev->dev, "%s:Request MCLK Gpio\n"
1018 "gpio[%s] = 0x%x\n", __func__,
1019 mclk_pin->gpio_name,
1020 dt_mclk);
1021 } else {
1022 dev_err(&pdev->dev, "%s:MCLK gpio is incorrect\n",
1023 __func__);
1024 ret = -ENODEV;
1025 goto err;
1026 }
1027 }
1028
1029 ctrl = devm_kzalloc(&pdev->dev,
1030 sizeof(struct msm_i2s_ctrl), GFP_KERNEL);
1031 if (!ctrl) {
1032 dev_err(&pdev->dev, "No memory for gpio\n");
1033 ret = -ENOMEM;
1034 goto err;
1035 }
1036 ctrl->pin_data = pin_data;
1037 ctrl->cnt = prim_cnt;
1038 (*pdata)->pri_ctrl = ctrl;
1039 (*pdata)->mclk_pin = mclk_pin;
1040 return ret;
1041
1042err:
1043 if (mclk_pin)
1044 devm_kfree(&pdev->dev, mclk_pin);
1045 if (pin_data)
1046 devm_kfree(&pdev->dev, pin_data);
1047 return ret;
1048}
1049
Venkat Sudhir64f66302012-10-30 09:30:16 -07001050static __devinit int mdm9625_asoc_machine_probe(struct platform_device *pdev)
1051{
1052 int ret;
1053 struct snd_soc_card *card = &snd_soc_card_mdm9625;
1054 struct mdm9625_machine_data *pdata;
Venkat Sudhir56959f12013-01-05 15:45:46 -08001055 enum apr_subsys_state q6_state;
Venkat Sudhir64f66302012-10-30 09:30:16 -07001056
Venkat Sudhir56959f12013-01-05 15:45:46 -08001057 q6_state = apr_get_q6_state();
1058 if (q6_state != APR_SUBSYS_LOADED) {
1059 dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n",
1060 __func__, q6_state);
1061 return -EPROBE_DEFER;
1062 }
Venkat Sudhir64f66302012-10-30 09:30:16 -07001063 mutex_init(&cdc_mclk_mutex);
Venkat Sudhir64f66302012-10-30 09:30:16 -07001064 if (!pdev->dev.of_node) {
1065 dev_err(&pdev->dev, "No platform supplied from device tree\n");
1066 return -EINVAL;
1067 }
1068 pdata = devm_kzalloc(&pdev->dev, sizeof(struct mdm9625_machine_data),
1069 GFP_KERNEL);
1070 if (!pdata) {
Venkat Sudhir459d6f52012-12-04 12:00:13 -08001071 dev_err(&pdev->dev, "Can't allocate mdm9625_asoc_mach_data\n");
Venkat Sudhir64f66302012-10-30 09:30:16 -07001072 ret = -ENOMEM;
1073 goto err;
1074 }
Prashanth Reddyf9536572013-02-13 12:17:08 -08001075 ret = mdm9625_dtparse(pdev, &pdata);
Venkat Sudhir459d6f52012-12-04 12:00:13 -08001076 if (ret) {
1077 dev_err(&pdev->dev,
Prashanth Reddyf9536572013-02-13 12:17:08 -08001078 "%s: mi2s-aux Pin data parse failed",
Venkat Sudhir459d6f52012-12-04 12:00:13 -08001079 __func__);
Venkat Sudhir64f66302012-10-30 09:30:16 -07001080 goto err;
Venkat Sudhir459d6f52012-12-04 12:00:13 -08001081 }
Venkat Sudhir64f66302012-10-30 09:30:16 -07001082 ret = of_property_read_u32(pdev->dev.of_node,
1083 "qcom,taiko-mclk-clk-freq",
1084 &pdata->mclk_freq);
1085 if (ret) {
1086 dev_err(&pdev->dev,
1087 "Looking up %s property in node %s failed",
1088 "qcom,taiko-mclk-clk-freq",
1089 pdev->dev.of_node->full_name);
1090 goto err;
1091 }
1092 /* At present only 12.288MHz is supported on MDM. */
Venkat Sudhir56959f12013-01-05 15:45:46 -08001093 if (q6afe_check_osr_clk_freq(pdata->mclk_freq)) {
Venkat Sudhir64f66302012-10-30 09:30:16 -07001094 dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
1095 pdata->mclk_freq);
1096 ret = -EINVAL;
1097 goto err;
1098 }
Venkat Sudhir56959f12013-01-05 15:45:46 -08001099 pdata->prim_clk_usrs = 0;
Venkat Sudhir459d6f52012-12-04 12:00:13 -08001100 card->dev = &pdev->dev;
1101 platform_set_drvdata(pdev, card);
1102 snd_soc_card_set_drvdata(card, pdata);
1103 ret = snd_soc_of_parse_card_name(card, "qcom,model");
1104 if (ret)
1105 goto err;
1106 ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
1107 if (ret)
1108 goto err;
Venkat Sudhir64f66302012-10-30 09:30:16 -07001109 ret = snd_soc_register_card(card);
1110 if (ret) {
1111 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
1112 ret);
1113 goto err;
1114 }
Prashanth Reddyf9536572013-02-13 12:17:08 -08001115
1116 lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
1117 if (lpaif_pri_muxsel_virt_addr == NULL) {
1118 pr_err("%s Pri muxsel virt addr is null\n", __func__);
1119 ret = -EINVAL;
1120 goto err;
1121 }
1122
Venkat Sudhir64f66302012-10-30 09:30:16 -07001123 return 0;
1124err:
1125 devm_kfree(&pdev->dev, pdata);
1126 return ret;
1127}
1128
1129static int __devexit mdm9625_asoc_machine_remove(struct platform_device *pdev)
1130{
1131 struct snd_soc_card *card = platform_get_drvdata(pdev);
1132 struct mdm9625_machine_data *pdata = snd_soc_card_get_drvdata(card);
1133 pdata->mclk_freq = 0;
1134 snd_soc_unregister_card(card);
1135 return 0;
1136}
1137
1138static const struct of_device_id msm9625_asoc_machine_of_match[] = {
1139 { .compatible = "qcom,mdm9625-audio-taiko", },
1140 {},
1141};
1142
1143static struct platform_driver msm9625_asoc_machine_driver = {
1144 .driver = {
1145 .name = MDM9625_MACHINE_DRV_NAME,
1146 .owner = THIS_MODULE,
1147 .pm = &snd_soc_pm_ops,
1148 .of_match_table = msm9625_asoc_machine_of_match,
1149 },
1150 .probe = mdm9625_asoc_machine_probe,
1151 .remove = __devexit_p(mdm9625_asoc_machine_remove),
1152};
1153
1154
1155module_platform_driver(msm9625_asoc_machine_driver);
1156
1157MODULE_DESCRIPTION("ALSA SoC msm");
1158MODULE_LICENSE("GPL v2");
1159MODULE_ALIAS("platform:" MDM9625_MACHINE_DRV_NAME);
1160MODULE_DEVICE_TABLE(of, msm9625_asoc_machine_of_match);
1161