xref: /openbmc/linux/sound/soc/ux500/mop500_ab8500.c (revision cdeecac4)
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 
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 
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 
125 static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
126 				struct snd_ctl_elem_value *ucontrol)
127 {
128 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
129 	struct mop500_ab8500_drvdata *drvdata =
130 				snd_soc_card_get_drvdata(card);
131 
132 	ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
133 
134 	return 0;
135 }
136 
137 static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
138 				struct snd_ctl_elem_value *ucontrol)
139 {
140 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
141 	struct mop500_ab8500_drvdata *drvdata =
142 				snd_soc_card_get_drvdata(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 	SOC_DAPM_PIN_SWITCH("Headset Left"),
164 	SOC_DAPM_PIN_SWITCH("Headset Right"),
165 	SOC_DAPM_PIN_SWITCH("Earpiece"),
166 	SOC_DAPM_PIN_SWITCH("Speaker Left"),
167 	SOC_DAPM_PIN_SWITCH("Speaker Right"),
168 	SOC_DAPM_PIN_SWITCH("LineOut Left"),
169 	SOC_DAPM_PIN_SWITCH("LineOut Right"),
170 	SOC_DAPM_PIN_SWITCH("Vibra 1"),
171 	SOC_DAPM_PIN_SWITCH("Vibra 2"),
172 	SOC_DAPM_PIN_SWITCH("Mic 1"),
173 	SOC_DAPM_PIN_SWITCH("Mic 2"),
174 	SOC_DAPM_PIN_SWITCH("LineIn Left"),
175 	SOC_DAPM_PIN_SWITCH("LineIn Right"),
176 	SOC_DAPM_PIN_SWITCH("DMic 1"),
177 	SOC_DAPM_PIN_SWITCH("DMic 2"),
178 	SOC_DAPM_PIN_SWITCH("DMic 3"),
179 	SOC_DAPM_PIN_SWITCH("DMic 4"),
180 	SOC_DAPM_PIN_SWITCH("DMic 5"),
181 	SOC_DAPM_PIN_SWITCH("DMic 6"),
182 };
183 
184 /* ASoC */
185 
186 static int mop500_ab8500_startup(struct snd_pcm_substream *substream)
187 {
188 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
189 
190 	/* Set audio-clock source */
191 	return mop500_ab8500_set_mclk(rtd->card->dev,
192 				snd_soc_card_get_drvdata(rtd->card));
193 }
194 
195 static void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
196 {
197 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
198 	struct device *dev = rtd->card->dev;
199 
200 	dev_dbg(dev, "%s: Enter\n", __func__);
201 
202 	/* Reset slots configuration to default(s) */
203 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
204 		tx_slots = DEF_TX_SLOTS;
205 	else
206 		rx_slots = DEF_RX_SLOTS;
207 }
208 
209 static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
210 			struct snd_pcm_hw_params *params)
211 {
212 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
213 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
214 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
215 	struct device *dev = rtd->card->dev;
216 	unsigned int fmt;
217 	int channels, ret = 0, driver_mode, slots;
218 	unsigned int sw_codec, sw_cpu;
219 	bool is_playback;
220 
221 	dev_dbg(dev, "%s: Enter\n", __func__);
222 
223 	dev_dbg(dev, "%s: substream->pcm->name = %s\n"
224 		"substream->pcm->id = %s.\n"
225 		"substream->name = %s.\n"
226 		"substream->number = %d.\n",
227 		__func__,
228 		substream->pcm->name,
229 		substream->pcm->id,
230 		substream->name,
231 		substream->number);
232 
233 	channels = params_channels(params);
234 
235 	switch (params_format(params)) {
236 	case SNDRV_PCM_FORMAT_S32_LE:
237 		sw_cpu = 32;
238 		break;
239 
240 	case SNDRV_PCM_FORMAT_S16_LE:
241 		sw_cpu = 16;
242 		break;
243 
244 	default:
245 		return -EINVAL;
246 	}
247 
248 	/* Setup codec depending on driver-mode */
249 	if (channels == 8)
250 		driver_mode = DRIVERMODE_CODEC_ONLY;
251 	else
252 		driver_mode = DRIVERMODE_NORMAL;
253 	dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
254 		(driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
255 
256 	/* Setup format */
257 
258 	if (driver_mode == DRIVERMODE_NORMAL) {
259 		fmt = SND_SOC_DAIFMT_DSP_A |
260 			SND_SOC_DAIFMT_CBM_CFM |
261 			SND_SOC_DAIFMT_NB_NF |
262 			SND_SOC_DAIFMT_CONT;
263 	} else {
264 		fmt = SND_SOC_DAIFMT_DSP_A |
265 			SND_SOC_DAIFMT_CBM_CFM |
266 			SND_SOC_DAIFMT_NB_NF |
267 			SND_SOC_DAIFMT_GATED;
268 	}
269 
270 	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
271 	if (ret < 0) {
272 		dev_err(dev,
273 			"%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
274 			__func__, ret);
275 		return ret;
276 	}
277 
278 	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
279 	if (ret < 0) {
280 		dev_err(dev,
281 			"%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
282 			__func__, ret);
283 		return ret;
284 	}
285 
286 	/* Setup TDM-slots */
287 
288 	is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
289 	switch (channels) {
290 	case 1:
291 		slots = 16;
292 		tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
293 		rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
294 		break;
295 	case 2:
296 		slots = 16;
297 		tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
298 		rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
299 		break;
300 	case 8:
301 		slots = 16;
302 		tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
303 		rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
304 		break;
305 	default:
306 		return -EINVAL;
307 	}
308 
309 	if (driver_mode == DRIVERMODE_NORMAL)
310 		sw_codec = sw_cpu;
311 	else
312 		sw_codec = 20;
313 
314 	dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
315 		tx_slots, rx_slots);
316 	ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
317 				sw_cpu);
318 	if (ret)
319 		return ret;
320 
321 	dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
322 		tx_slots, rx_slots);
323 	ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
324 				sw_codec);
325 	if (ret)
326 		return ret;
327 
328 	return 0;
329 }
330 
331 struct snd_soc_ops mop500_ab8500_ops[] = {
332 	{
333 		.hw_params = mop500_ab8500_hw_params,
334 		.startup = mop500_ab8500_startup,
335 		.shutdown = mop500_ab8500_shutdown,
336 	}
337 };
338 
339 int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
340 {
341 	struct snd_soc_codec *codec = rtd->codec;
342 	struct device *dev = rtd->card->dev;
343 	struct mop500_ab8500_drvdata *drvdata;
344 	int ret;
345 
346 	dev_dbg(dev, "%s Enter.\n", __func__);
347 
348 	/* Create driver private-data struct */
349 	drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
350 			GFP_KERNEL);
351 	snd_soc_card_set_drvdata(rtd->card, drvdata);
352 
353 	/* Setup clocks */
354 
355 	drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
356 	if (IS_ERR(drvdata->clk_ptr_sysclk))
357 		dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
358 			__func__);
359 	drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
360 	if (IS_ERR(drvdata->clk_ptr_ulpclk))
361 		dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
362 			__func__);
363 	drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
364 	if (IS_ERR(drvdata->clk_ptr_intclk))
365 		dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
366 			__func__);
367 
368 	/* Set intclk default parent to ulpclk */
369 	drvdata->mclk_sel = MCLK_ULPCLK;
370 	ret = mop500_ab8500_set_mclk(dev, drvdata);
371 	if (ret < 0)
372 		dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
373 			__func__);
374 
375 	drvdata->mclk_sel = MCLK_ULPCLK;
376 
377 	/* Add controls */
378 	ret = snd_soc_add_card_controls(codec->card, mop500_ab8500_ctrls,
379 			ARRAY_SIZE(mop500_ab8500_ctrls));
380 	if (ret < 0) {
381 		pr_err("%s: Failed to add machine-controls (%d)!\n",
382 				__func__, ret);
383 		return ret;
384 	}
385 
386 	ret = snd_soc_dapm_disable_pin(&codec->dapm, "Earpiece");
387 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Left");
388 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Right");
389 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Left");
390 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Right");
391 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 1");
392 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 2");
393 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 1");
394 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 2");
395 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Left");
396 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Right");
397 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 1");
398 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 2");
399 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 3");
400 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 4");
401 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 5");
402 	ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 6");
403 
404 	return ret;
405 }
406 
407 void mop500_ab8500_remove(struct snd_soc_card *card)
408 {
409 	struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
410 
411 	if (drvdata->clk_ptr_sysclk != NULL)
412 		clk_put(drvdata->clk_ptr_sysclk);
413 	if (drvdata->clk_ptr_ulpclk != NULL)
414 		clk_put(drvdata->clk_ptr_ulpclk);
415 	if (drvdata->clk_ptr_intclk != NULL)
416 		clk_put(drvdata->clk_ptr_intclk);
417 
418 	snd_soc_card_set_drvdata(card, drvdata);
419 }
420