• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) ST-Ericsson SA 2012
3  *
4  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
5  *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
6  *         for ST-Ericsson.
7  *
8  * License terms:
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as published
12  * by the Free Software Foundation.
13  */
14 
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/io.h>
18 #include <linux/clk.h>
19 
20 #include <sound/soc.h>
21 #include <sound/soc-dapm.h>
22 #include <sound/pcm.h>
23 #include <sound/pcm_params.h>
24 
25 #include "ux500_pcm.h"
26 #include "ux500_msp_dai.h"
27 #include "../codecs/ab8500-codec.h"
28 
29 #define TX_SLOT_MONO	0x0008
30 #define TX_SLOT_STEREO	0x000a
31 #define RX_SLOT_MONO	0x0001
32 #define RX_SLOT_STEREO	0x0003
33 #define TX_SLOT_8CH	0x00FF
34 #define RX_SLOT_8CH	0x00FF
35 
36 #define DEF_TX_SLOTS	TX_SLOT_STEREO
37 #define DEF_RX_SLOTS	RX_SLOT_MONO
38 
39 #define DRIVERMODE_NORMAL	0
40 #define DRIVERMODE_CODEC_ONLY	1
41 
42 /* Slot configuration */
43 static unsigned int tx_slots = DEF_TX_SLOTS;
44 static unsigned int rx_slots = DEF_RX_SLOTS;
45 
46 /* Clocks */
47 static const char * const enum_mclk[] = {
48 	"SYSCLK",
49 	"ULPCLK"
50 };
51 enum mclk {
52 	MCLK_SYSCLK,
53 	MCLK_ULPCLK,
54 };
55 
56 static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
57 
58 /* Private data for machine-part MOP500<->AB8500 */
59 struct mop500_ab8500_drvdata {
60 	/* Clocks */
61 	enum mclk mclk_sel;
62 	struct clk *clk_ptr_intclk;
63 	struct clk *clk_ptr_sysclk;
64 	struct clk *clk_ptr_ulpclk;
65 };
66 
get_mclk_str(enum mclk mclk_sel)67 static inline const char *get_mclk_str(enum mclk mclk_sel)
68 {
69 	switch (mclk_sel) {
70 	case MCLK_SYSCLK:
71 		return "SYSCLK";
72 	case MCLK_ULPCLK:
73 		return "ULPCLK";
74 	default:
75 		return "Unknown";
76 	}
77 }
78 
mop500_ab8500_set_mclk(struct device * dev,struct mop500_ab8500_drvdata * drvdata)79 static int mop500_ab8500_set_mclk(struct device *dev,
80 				struct mop500_ab8500_drvdata *drvdata)
81 {
82 	int status;
83 	struct clk *clk_ptr;
84 
85 	if (IS_ERR(drvdata->clk_ptr_intclk)) {
86 		dev_err(dev,
87 			"%s: ERROR: intclk not initialized!\n", __func__);
88 		return -EIO;
89 	}
90 
91 	switch (drvdata->mclk_sel) {
92 	case MCLK_SYSCLK:
93 		clk_ptr = drvdata->clk_ptr_sysclk;
94 		break;
95 	case MCLK_ULPCLK:
96 		clk_ptr = drvdata->clk_ptr_ulpclk;
97 		break;
98 	default:
99 		return -EINVAL;
100 	}
101 
102 	if (IS_ERR(clk_ptr)) {
103 		dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
104 			get_mclk_str(drvdata->mclk_sel));
105 		return -EIO;
106 	}
107 
108 	status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
109 	if (status)
110 		dev_err(dev,
111 			"%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
112 			__func__, get_mclk_str(drvdata->mclk_sel), status);
113 	else
114 		dev_dbg(dev,
115 			"%s: intclk parent changed to %s.\n",
116 			__func__, get_mclk_str(drvdata->mclk_sel));
117 
118 	return status;
119 }
120 
121 /*
122  * Control-events
123  */
124 
mclk_input_control_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)125 static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
126 				struct snd_ctl_elem_value *ucontrol)
127 {
128 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
129 	struct mop500_ab8500_drvdata *drvdata =
130 				snd_soc_card_get_drvdata(codec->card);
131 
132 	ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
133 
134 	return 0;
135 }
136 
mclk_input_control_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)137 static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
138 				struct snd_ctl_elem_value *ucontrol)
139 {
140 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
141 	struct mop500_ab8500_drvdata *drvdata =
142 				snd_soc_card_get_drvdata(codec->card);
143 	unsigned int val = ucontrol->value.enumerated.item[0];
144 
145 	if (val > (unsigned int)MCLK_ULPCLK)
146 		return -EINVAL;
147 	if (drvdata->mclk_sel == val)
148 		return 0;
149 
150 	drvdata->mclk_sel = val;
151 
152 	return 1;
153 }
154 
155 /*
156  * Controls
157  */
158 
159 static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
160 	SOC_ENUM_EXT("Master Clock Select",
161 		soc_enum_mclk,
162 		mclk_input_control_get, mclk_input_control_put),
163 	/* Digital interface - Clocks */
164 	SOC_SINGLE("Digital Interface Master Generator Switch",
165 		AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENMASTGEN,
166 		1, 0),
167 	SOC_SINGLE("Digital Interface 0 Bit-clock Switch",
168 		AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK0,
169 		1, 0),
170 	SOC_SINGLE("Digital Interface 1 Bit-clock Switch",
171 		AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK1,
172 		1, 0),
173 	SOC_DAPM_PIN_SWITCH("Headset Left"),
174 	SOC_DAPM_PIN_SWITCH("Headset Right"),
175 	SOC_DAPM_PIN_SWITCH("Earpiece"),
176 	SOC_DAPM_PIN_SWITCH("Speaker Left"),
177 	SOC_DAPM_PIN_SWITCH("Speaker Right"),
178 	SOC_DAPM_PIN_SWITCH("LineOut Left"),
179 	SOC_DAPM_PIN_SWITCH("LineOut Right"),
180 	SOC_DAPM_PIN_SWITCH("Vibra 1"),
181 	SOC_DAPM_PIN_SWITCH("Vibra 2"),
182 	SOC_DAPM_PIN_SWITCH("Mic 1"),
183 	SOC_DAPM_PIN_SWITCH("Mic 2"),
184 	SOC_DAPM_PIN_SWITCH("LineIn Left"),
185 	SOC_DAPM_PIN_SWITCH("LineIn Right"),
186 	SOC_DAPM_PIN_SWITCH("DMic 1"),
187 	SOC_DAPM_PIN_SWITCH("DMic 2"),
188 	SOC_DAPM_PIN_SWITCH("DMic 3"),
189 	SOC_DAPM_PIN_SWITCH("DMic 4"),
190 	SOC_DAPM_PIN_SWITCH("DMic 5"),
191 	SOC_DAPM_PIN_SWITCH("DMic 6"),
192 };
193 
194 /* ASoC */
195 
mop500_ab8500_startup(struct snd_pcm_substream * substream)196 int mop500_ab8500_startup(struct snd_pcm_substream *substream)
197 {
198 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
199 
200 	/* Set audio-clock source */
201 	return mop500_ab8500_set_mclk(rtd->card->dev,
202 				snd_soc_card_get_drvdata(rtd->card));
203 }
204 
mop500_ab8500_shutdown(struct snd_pcm_substream * substream)205 void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
206 {
207 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
208 	struct device *dev = rtd->card->dev;
209 
210 	dev_dbg(dev, "%s: Enter\n", __func__);
211 
212 	/* Reset slots configuration to default(s) */
213 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
214 		tx_slots = DEF_TX_SLOTS;
215 	else
216 		rx_slots = DEF_RX_SLOTS;
217 }
218 
mop500_ab8500_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)219 int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
220 			struct snd_pcm_hw_params *params)
221 {
222 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
223 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
224 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
225 	struct device *dev = rtd->card->dev;
226 	unsigned int fmt;
227 	int channels, ret = 0, driver_mode, slots;
228 	unsigned int sw_codec, sw_cpu;
229 	bool is_playback;
230 
231 	dev_dbg(dev, "%s: Enter\n", __func__);
232 
233 	dev_dbg(dev, "%s: substream->pcm->name = %s\n"
234 		"substream->pcm->id = %s.\n"
235 		"substream->name = %s.\n"
236 		"substream->number = %d.\n",
237 		__func__,
238 		substream->pcm->name,
239 		substream->pcm->id,
240 		substream->name,
241 		substream->number);
242 
243 	channels = params_channels(params);
244 
245 	switch (params_format(params)) {
246 	case SNDRV_PCM_FORMAT_S32_LE:
247 		sw_cpu = 32;
248 		break;
249 
250 	case SNDRV_PCM_FORMAT_S16_LE:
251 		sw_cpu = 16;
252 		break;
253 
254 	default:
255 		return -EINVAL;
256 	}
257 
258 	/* Setup codec depending on driver-mode */
259 	if (channels == 8)
260 		driver_mode = DRIVERMODE_CODEC_ONLY;
261 	else
262 		driver_mode = DRIVERMODE_NORMAL;
263 	dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
264 		(driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
265 
266 	/* Setup format */
267 
268 	if (driver_mode == DRIVERMODE_NORMAL) {
269 		fmt = SND_SOC_DAIFMT_DSP_A |
270 			SND_SOC_DAIFMT_CBM_CFM |
271 			SND_SOC_DAIFMT_NB_NF |
272 			SND_SOC_DAIFMT_CONT;
273 	} else {
274 		fmt = SND_SOC_DAIFMT_DSP_A |
275 			SND_SOC_DAIFMT_CBM_CFM |
276 			SND_SOC_DAIFMT_NB_NF |
277 			SND_SOC_DAIFMT_GATED;
278 	}
279 
280 	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
281 	if (ret < 0) {
282 		dev_err(dev,
283 			"%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
284 			__func__, ret);
285 		return ret;
286 	}
287 
288 	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
289 	if (ret < 0) {
290 		dev_err(dev,
291 			"%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
292 			__func__, ret);
293 		return ret;
294 	}
295 
296 	/* Setup TDM-slots */
297 
298 	is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
299 	switch (channels) {
300 	case 1:
301 		slots = 16;
302 		tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
303 		rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
304 		break;
305 	case 2:
306 		slots = 16;
307 		tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
308 		rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
309 		break;
310 	case 8:
311 		slots = 16;
312 		tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
313 		rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
314 		break;
315 	default:
316 		return -EINVAL;
317 	}
318 
319 	if (driver_mode == DRIVERMODE_NORMAL)
320 		sw_codec = sw_cpu;
321 	else
322 		sw_codec = 20;
323 
324 	dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
325 		tx_slots, rx_slots);
326 	ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
327 				sw_cpu);
328 	if (ret)
329 		return ret;
330 
331 	dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
332 		tx_slots, rx_slots);
333 	ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
334 				sw_codec);
335 	if (ret)
336 		return ret;
337 
338 	return 0;
339 }
340 
341 struct snd_soc_ops mop500_ab8500_ops[] = {
342 	{
343 		.hw_params = mop500_ab8500_hw_params,
344 		.startup = mop500_ab8500_startup,
345 		.shutdown = mop500_ab8500_shutdown,
346 	}
347 };
348 
mop500_ab8500_machine_init(struct snd_soc_pcm_runtime * rtd)349 int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
350 {
351 	struct snd_soc_codec *codec = rtd->codec;
352 	struct device *dev = rtd->card->dev;
353 	struct mop500_ab8500_drvdata *drvdata;
354 	int ret;
355 
356 	dev_dbg(dev, "%s Enter.\n", __func__);
357 
358 	/* Create driver private-data struct */
359 	drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
360 			GFP_KERNEL);
361 	snd_soc_card_set_drvdata(rtd->card, drvdata);
362 
363 	/* Setup clocks */
364 
365 	drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
366 	if (IS_ERR(drvdata->clk_ptr_sysclk))
367 		dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
368 			__func__);
369 	drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
370 	if (IS_ERR(drvdata->clk_ptr_ulpclk))
371 		dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
372 			__func__);
373 	drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
374 	if (IS_ERR(drvdata->clk_ptr_intclk))
375 		dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
376 			__func__);
377 
378 	/* Set intclk default parent to ulpclk */
379 	drvdata->mclk_sel = MCLK_ULPCLK;
380 	ret = mop500_ab8500_set_mclk(dev, drvdata);
381 	if (ret < 0)
382 		dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
383 			__func__);
384 
385 	drvdata->mclk_sel = MCLK_ULPCLK;
386 
387 	/* Add controls */
388 	ret = snd_soc_add_codec_controls(codec, mop500_ab8500_ctrls,
389 			ARRAY_SIZE(mop500_ab8500_ctrls));
390 	if (ret < 0) {
391 		pr_err("%s: Failed to add machine-controls (%d)!\n",
392 				__func__, ret);
393 		return ret;
394 	}
395 
396 	ret = snd_soc_dapm_disable_pin(&codec->dapm, "Earpiece");
397 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Left");
398 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Right");
399 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Left");
400 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Right");
401 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 1");
402 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 2");
403 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 1");
404 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 2");
405 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Left");
406 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Right");
407 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 1");
408 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 2");
409 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 3");
410 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 4");
411 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 5");
412 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 6");
413 
414 	return ret;
415 }
416 
mop500_ab8500_remove(struct snd_soc_card * card)417 void mop500_ab8500_remove(struct snd_soc_card *card)
418 {
419 	struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
420 
421 	if (drvdata->clk_ptr_sysclk != NULL)
422 		clk_put(drvdata->clk_ptr_sysclk);
423 	if (drvdata->clk_ptr_ulpclk != NULL)
424 		clk_put(drvdata->clk_ptr_ulpclk);
425 	if (drvdata->clk_ptr_intclk != NULL)
426 		clk_put(drvdata->clk_ptr_intclk);
427 
428 	snd_soc_card_set_drvdata(card, drvdata);
429 }
430