xref: /openbmc/linux/sound/soc/ux500/mop500_ab8500.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e0690385SOla Lilja /*
3e0690385SOla Lilja  * Copyright (C) ST-Ericsson SA 2012
4e0690385SOla Lilja  *
5e0690385SOla Lilja  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
6e0690385SOla Lilja  *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
7e0690385SOla Lilja  *         for ST-Ericsson.
8e0690385SOla Lilja  */
9e0690385SOla Lilja 
10e0690385SOla Lilja #include <linux/module.h>
11e0690385SOla Lilja #include <linux/device.h>
12e0690385SOla Lilja #include <linux/io.h>
13e0690385SOla Lilja #include <linux/clk.h>
14a130243bSFabio Baltieri #include <linux/mutex.h>
15e0690385SOla Lilja 
16e0690385SOla Lilja #include <sound/soc.h>
17e0690385SOla Lilja #include <sound/soc-dapm.h>
18e0690385SOla Lilja #include <sound/pcm.h>
19e0690385SOla Lilja #include <sound/pcm_params.h>
20e0690385SOla Lilja 
21e0690385SOla Lilja #include "ux500_pcm.h"
22e0690385SOla Lilja #include "ux500_msp_dai.h"
2306b9671eSFabio Baltieri #include "mop500_ab8500.h"
24e0690385SOla Lilja #include "../codecs/ab8500-codec.h"
25e0690385SOla Lilja 
26e0690385SOla Lilja #define TX_SLOT_MONO	0x0008
27e0690385SOla Lilja #define TX_SLOT_STEREO	0x000a
28e0690385SOla Lilja #define RX_SLOT_MONO	0x0001
29e0690385SOla Lilja #define RX_SLOT_STEREO	0x0003
30e0690385SOla Lilja #define TX_SLOT_8CH	0x00FF
31e0690385SOla Lilja #define RX_SLOT_8CH	0x00FF
32e0690385SOla Lilja 
33e0690385SOla Lilja #define DEF_TX_SLOTS	TX_SLOT_STEREO
34e0690385SOla Lilja #define DEF_RX_SLOTS	RX_SLOT_MONO
35e0690385SOla Lilja 
36e0690385SOla Lilja #define DRIVERMODE_NORMAL	0
37e0690385SOla Lilja #define DRIVERMODE_CODEC_ONLY	1
38e0690385SOla Lilja 
39e0690385SOla Lilja /* Slot configuration */
40e0690385SOla Lilja static unsigned int tx_slots = DEF_TX_SLOTS;
41e0690385SOla Lilja static unsigned int rx_slots = DEF_RX_SLOTS;
42e0690385SOla Lilja 
43a130243bSFabio Baltieri /* Configuration consistency parameters */
44a130243bSFabio Baltieri static DEFINE_MUTEX(mop500_ab8500_params_lock);
45a130243bSFabio Baltieri static unsigned long mop500_ab8500_usage;
46a130243bSFabio Baltieri static int mop500_ab8500_rate;
47a130243bSFabio Baltieri static int mop500_ab8500_channels;
48a130243bSFabio Baltieri 
49e0690385SOla Lilja /* Clocks */
50e0690385SOla Lilja static const char * const enum_mclk[] = {
51e0690385SOla Lilja 	"SYSCLK",
52e0690385SOla Lilja 	"ULPCLK"
53e0690385SOla Lilja };
54e0690385SOla Lilja enum mclk {
55e0690385SOla Lilja 	MCLK_SYSCLK,
56e0690385SOla Lilja 	MCLK_ULPCLK,
57e0690385SOla Lilja };
58e0690385SOla Lilja 
59e0690385SOla Lilja static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
60e0690385SOla Lilja 
61e0690385SOla Lilja /* Private data for machine-part MOP500<->AB8500 */
62e0690385SOla Lilja struct mop500_ab8500_drvdata {
63e0690385SOla Lilja 	/* Clocks */
64e0690385SOla Lilja 	enum mclk mclk_sel;
65e0690385SOla Lilja 	struct clk *clk_ptr_intclk;
66e0690385SOla Lilja 	struct clk *clk_ptr_sysclk;
67e0690385SOla Lilja 	struct clk *clk_ptr_ulpclk;
68e0690385SOla Lilja };
69e0690385SOla Lilja 
get_mclk_str(enum mclk mclk_sel)70e0690385SOla Lilja static inline const char *get_mclk_str(enum mclk mclk_sel)
71e0690385SOla Lilja {
72e0690385SOla Lilja 	switch (mclk_sel) {
73e0690385SOla Lilja 	case MCLK_SYSCLK:
74e0690385SOla Lilja 		return "SYSCLK";
75e0690385SOla Lilja 	case MCLK_ULPCLK:
76e0690385SOla Lilja 		return "ULPCLK";
77e0690385SOla Lilja 	default:
78e0690385SOla Lilja 		return "Unknown";
79e0690385SOla Lilja 	}
80e0690385SOla Lilja }
81e0690385SOla Lilja 
mop500_ab8500_set_mclk(struct device * dev,struct mop500_ab8500_drvdata * drvdata)82e0690385SOla Lilja static int mop500_ab8500_set_mclk(struct device *dev,
83e0690385SOla Lilja 				struct mop500_ab8500_drvdata *drvdata)
84e0690385SOla Lilja {
85e0690385SOla Lilja 	int status;
86e0690385SOla Lilja 	struct clk *clk_ptr;
87e0690385SOla Lilja 
88e0690385SOla Lilja 	if (IS_ERR(drvdata->clk_ptr_intclk)) {
89e0690385SOla Lilja 		dev_err(dev,
90e0690385SOla Lilja 			"%s: ERROR: intclk not initialized!\n", __func__);
91e0690385SOla Lilja 		return -EIO;
92e0690385SOla Lilja 	}
93e0690385SOla Lilja 
94e0690385SOla Lilja 	switch (drvdata->mclk_sel) {
95e0690385SOla Lilja 	case MCLK_SYSCLK:
96e0690385SOla Lilja 		clk_ptr = drvdata->clk_ptr_sysclk;
97e0690385SOla Lilja 		break;
98e0690385SOla Lilja 	case MCLK_ULPCLK:
99e0690385SOla Lilja 		clk_ptr = drvdata->clk_ptr_ulpclk;
100e0690385SOla Lilja 		break;
101e0690385SOla Lilja 	default:
102e0690385SOla Lilja 		return -EINVAL;
103e0690385SOla Lilja 	}
104e0690385SOla Lilja 
105e0690385SOla Lilja 	if (IS_ERR(clk_ptr)) {
106e0690385SOla Lilja 		dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
107e0690385SOla Lilja 			get_mclk_str(drvdata->mclk_sel));
108e0690385SOla Lilja 		return -EIO;
109e0690385SOla Lilja 	}
110e0690385SOla Lilja 
111e0690385SOla Lilja 	status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
112e0690385SOla Lilja 	if (status)
113e0690385SOla Lilja 		dev_err(dev,
114e0690385SOla Lilja 			"%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
115e0690385SOla Lilja 			__func__, get_mclk_str(drvdata->mclk_sel), status);
116e0690385SOla Lilja 	else
117e0690385SOla Lilja 		dev_dbg(dev,
118e0690385SOla Lilja 			"%s: intclk parent changed to %s.\n",
119e0690385SOla Lilja 			__func__, get_mclk_str(drvdata->mclk_sel));
120e0690385SOla Lilja 
121e0690385SOla Lilja 	return status;
122e0690385SOla Lilja }
123e0690385SOla Lilja 
124e0690385SOla Lilja /*
125e0690385SOla Lilja  * Control-events
126e0690385SOla Lilja  */
127e0690385SOla Lilja 
mclk_input_control_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)128e0690385SOla Lilja static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
129e0690385SOla Lilja 				struct snd_ctl_elem_value *ucontrol)
130e0690385SOla Lilja {
131f656df65SFabio Baltieri 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
132e0690385SOla Lilja 	struct mop500_ab8500_drvdata *drvdata =
133f656df65SFabio Baltieri 				snd_soc_card_get_drvdata(card);
134e0690385SOla Lilja 
135e0690385SOla Lilja 	ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
136e0690385SOla Lilja 
137e0690385SOla Lilja 	return 0;
138e0690385SOla Lilja }
139e0690385SOla Lilja 
mclk_input_control_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)140e0690385SOla Lilja static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
141e0690385SOla Lilja 				struct snd_ctl_elem_value *ucontrol)
142e0690385SOla Lilja {
143f656df65SFabio Baltieri 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
144e0690385SOla Lilja 	struct mop500_ab8500_drvdata *drvdata =
145f656df65SFabio Baltieri 				snd_soc_card_get_drvdata(card);
146e0690385SOla Lilja 	unsigned int val = ucontrol->value.enumerated.item[0];
147e0690385SOla Lilja 
148e0690385SOla Lilja 	if (val > (unsigned int)MCLK_ULPCLK)
149e0690385SOla Lilja 		return -EINVAL;
150e0690385SOla Lilja 	if (drvdata->mclk_sel == val)
151e0690385SOla Lilja 		return 0;
152e0690385SOla Lilja 
153e0690385SOla Lilja 	drvdata->mclk_sel = val;
154e0690385SOla Lilja 
155e0690385SOla Lilja 	return 1;
156e0690385SOla Lilja }
157e0690385SOla Lilja 
158e0690385SOla Lilja /*
159e0690385SOla Lilja  * Controls
160e0690385SOla Lilja  */
161e0690385SOla Lilja 
162e0690385SOla Lilja static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
163e0690385SOla Lilja 	SOC_ENUM_EXT("Master Clock Select",
164e0690385SOla Lilja 		soc_enum_mclk,
165e0690385SOla Lilja 		mclk_input_control_get, mclk_input_control_put),
166e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Headset Left"),
167e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Headset Right"),
168e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Earpiece"),
169e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Speaker Left"),
170e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Speaker Right"),
171e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("LineOut Left"),
172e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("LineOut Right"),
173e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Vibra 1"),
174e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Vibra 2"),
175e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Mic 1"),
176e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("Mic 2"),
177e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("LineIn Left"),
178e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("LineIn Right"),
179e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("DMic 1"),
180e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("DMic 2"),
181e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("DMic 3"),
182e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("DMic 4"),
183e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("DMic 5"),
184e0690385SOla Lilja 	SOC_DAPM_PIN_SWITCH("DMic 6"),
185e0690385SOla Lilja };
186e0690385SOla Lilja 
187e0690385SOla Lilja /* ASoC */
188e0690385SOla Lilja 
mop500_ab8500_startup(struct snd_pcm_substream * substream)189cdeecac4SLars-Peter Clausen static int mop500_ab8500_startup(struct snd_pcm_substream *substream)
190e0690385SOla Lilja {
1913e44c479SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
192e0690385SOla Lilja 
193e0690385SOla Lilja 	/* Set audio-clock source */
194e0690385SOla Lilja 	return mop500_ab8500_set_mclk(rtd->card->dev,
195e0690385SOla Lilja 				snd_soc_card_get_drvdata(rtd->card));
196e0690385SOla Lilja }
197e0690385SOla Lilja 
mop500_ab8500_shutdown(struct snd_pcm_substream * substream)198cdeecac4SLars-Peter Clausen static void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
199e0690385SOla Lilja {
2003e44c479SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
201e0690385SOla Lilja 	struct device *dev = rtd->card->dev;
202e0690385SOla Lilja 
203e0690385SOla Lilja 	dev_dbg(dev, "%s: Enter\n", __func__);
204e0690385SOla Lilja 
205e0690385SOla Lilja 	/* Reset slots configuration to default(s) */
206e0690385SOla Lilja 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
207e0690385SOla Lilja 		tx_slots = DEF_TX_SLOTS;
208e0690385SOla Lilja 	else
209e0690385SOla Lilja 		rx_slots = DEF_RX_SLOTS;
210e0690385SOla Lilja }
211e0690385SOla Lilja 
mop500_ab8500_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)212cdeecac4SLars-Peter Clausen static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
213e0690385SOla Lilja 			struct snd_pcm_hw_params *params)
214e0690385SOla Lilja {
2153e44c479SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
21699396e38SKuninori Morimoto 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
21799396e38SKuninori Morimoto 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
218e0690385SOla Lilja 	struct device *dev = rtd->card->dev;
219e0690385SOla Lilja 	unsigned int fmt;
220e0690385SOla Lilja 	int channels, ret = 0, driver_mode, slots;
221e0690385SOla Lilja 	unsigned int sw_codec, sw_cpu;
222e0690385SOla Lilja 	bool is_playback;
223e0690385SOla Lilja 
224e0690385SOla Lilja 	dev_dbg(dev, "%s: Enter\n", __func__);
225e0690385SOla Lilja 
226e0690385SOla Lilja 	dev_dbg(dev, "%s: substream->pcm->name = %s\n"
227e0690385SOla Lilja 		"substream->pcm->id = %s.\n"
228e0690385SOla Lilja 		"substream->name = %s.\n"
229e0690385SOla Lilja 		"substream->number = %d.\n",
230e0690385SOla Lilja 		__func__,
231e0690385SOla Lilja 		substream->pcm->name,
232e0690385SOla Lilja 		substream->pcm->id,
233e0690385SOla Lilja 		substream->name,
234e0690385SOla Lilja 		substream->number);
235e0690385SOla Lilja 
236a130243bSFabio Baltieri 	/* Ensure configuration consistency between DAIs */
237a130243bSFabio Baltieri 	mutex_lock(&mop500_ab8500_params_lock);
238a130243bSFabio Baltieri 	if (mop500_ab8500_usage) {
239a130243bSFabio Baltieri 		if (mop500_ab8500_rate != params_rate(params) ||
240a130243bSFabio Baltieri 		    mop500_ab8500_channels != params_channels(params)) {
241a130243bSFabio Baltieri 			mutex_unlock(&mop500_ab8500_params_lock);
242a130243bSFabio Baltieri 			return -EBUSY;
243a130243bSFabio Baltieri 		}
244a130243bSFabio Baltieri 	} else {
245a130243bSFabio Baltieri 		mop500_ab8500_rate = params_rate(params);
246a130243bSFabio Baltieri 		mop500_ab8500_channels = params_channels(params);
247a130243bSFabio Baltieri 	}
248a130243bSFabio Baltieri 	__set_bit(cpu_dai->id, &mop500_ab8500_usage);
249a130243bSFabio Baltieri 	mutex_unlock(&mop500_ab8500_params_lock);
250a130243bSFabio Baltieri 
251e0690385SOla Lilja 	channels = params_channels(params);
252e0690385SOla Lilja 
253e0690385SOla Lilja 	switch (params_format(params)) {
254e0690385SOla Lilja 	case SNDRV_PCM_FORMAT_S32_LE:
255e0690385SOla Lilja 		sw_cpu = 32;
256e0690385SOla Lilja 		break;
257e0690385SOla Lilja 
258e0690385SOla Lilja 	case SNDRV_PCM_FORMAT_S16_LE:
259e0690385SOla Lilja 		sw_cpu = 16;
260e0690385SOla Lilja 		break;
261e0690385SOla Lilja 
262e0690385SOla Lilja 	default:
263e0690385SOla Lilja 		return -EINVAL;
264e0690385SOla Lilja 	}
265e0690385SOla Lilja 
266e0690385SOla Lilja 	/* Setup codec depending on driver-mode */
267e0690385SOla Lilja 	if (channels == 8)
268e0690385SOla Lilja 		driver_mode = DRIVERMODE_CODEC_ONLY;
269e0690385SOla Lilja 	else
270e0690385SOla Lilja 		driver_mode = DRIVERMODE_NORMAL;
271e0690385SOla Lilja 	dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
272e0690385SOla Lilja 		(driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
273e0690385SOla Lilja 
274e0690385SOla Lilja 	/* Setup format */
275e0690385SOla Lilja 
276e0690385SOla Lilja 	if (driver_mode == DRIVERMODE_NORMAL) {
277e0690385SOla Lilja 		fmt = SND_SOC_DAIFMT_DSP_A |
278e0690385SOla Lilja 			SND_SOC_DAIFMT_CBM_CFM |
279e0690385SOla Lilja 			SND_SOC_DAIFMT_NB_NF |
280e0690385SOla Lilja 			SND_SOC_DAIFMT_CONT;
281e0690385SOla Lilja 	} else {
282e0690385SOla Lilja 		fmt = SND_SOC_DAIFMT_DSP_A |
283e0690385SOla Lilja 			SND_SOC_DAIFMT_CBM_CFM |
284e0690385SOla Lilja 			SND_SOC_DAIFMT_NB_NF |
285e0690385SOla Lilja 			SND_SOC_DAIFMT_GATED;
286e0690385SOla Lilja 	}
287e0690385SOla Lilja 
288c853679aSLars-Peter Clausen 	ret = snd_soc_runtime_set_dai_fmt(rtd, fmt);
289c853679aSLars-Peter Clausen 	if (ret)
290e0690385SOla Lilja 		return ret;
291e0690385SOla Lilja 
292e0690385SOla Lilja 	/* Setup TDM-slots */
293e0690385SOla Lilja 
294e0690385SOla Lilja 	is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
295e0690385SOla Lilja 	switch (channels) {
296e0690385SOla Lilja 	case 1:
297e0690385SOla Lilja 		slots = 16;
298e0690385SOla Lilja 		tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
299e0690385SOla Lilja 		rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
300e0690385SOla Lilja 		break;
301e0690385SOla Lilja 	case 2:
302e0690385SOla Lilja 		slots = 16;
303e0690385SOla Lilja 		tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
304e0690385SOla Lilja 		rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
305e0690385SOla Lilja 		break;
306e0690385SOla Lilja 	case 8:
307e0690385SOla Lilja 		slots = 16;
308e0690385SOla Lilja 		tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
309e0690385SOla Lilja 		rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
310e0690385SOla Lilja 		break;
311e0690385SOla Lilja 	default:
312e0690385SOla Lilja 		return -EINVAL;
313e0690385SOla Lilja 	}
314e0690385SOla Lilja 
315e0690385SOla Lilja 	if (driver_mode == DRIVERMODE_NORMAL)
316e0690385SOla Lilja 		sw_codec = sw_cpu;
317e0690385SOla Lilja 	else
318e0690385SOla Lilja 		sw_codec = 20;
319e0690385SOla Lilja 
320e0690385SOla Lilja 	dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
321e0690385SOla Lilja 		tx_slots, rx_slots);
322e0690385SOla Lilja 	ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
323e0690385SOla Lilja 				sw_cpu);
324e0690385SOla Lilja 	if (ret)
325e0690385SOla Lilja 		return ret;
326e0690385SOla Lilja 
327e0690385SOla Lilja 	dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
328e0690385SOla Lilja 		tx_slots, rx_slots);
329e0690385SOla Lilja 	ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
330e0690385SOla Lilja 				sw_codec);
331e0690385SOla Lilja 	if (ret)
332e0690385SOla Lilja 		return ret;
333e0690385SOla Lilja 
334e0690385SOla Lilja 	return 0;
335e0690385SOla Lilja }
336e0690385SOla Lilja 
mop500_ab8500_hw_free(struct snd_pcm_substream * substream)337a130243bSFabio Baltieri static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream)
338a130243bSFabio Baltieri {
3393e44c479SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
34099396e38SKuninori Morimoto 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
341a130243bSFabio Baltieri 
342a130243bSFabio Baltieri 	mutex_lock(&mop500_ab8500_params_lock);
343a130243bSFabio Baltieri 	__clear_bit(cpu_dai->id, &mop500_ab8500_usage);
344a130243bSFabio Baltieri 	mutex_unlock(&mop500_ab8500_params_lock);
345a130243bSFabio Baltieri 
346a130243bSFabio Baltieri 	return 0;
347a130243bSFabio Baltieri }
348a130243bSFabio Baltieri 
349*2831b719SRikard Falkeborn const struct snd_soc_ops mop500_ab8500_ops[] = {
350e0690385SOla Lilja 	{
351e0690385SOla Lilja 		.hw_params = mop500_ab8500_hw_params,
352a130243bSFabio Baltieri 		.hw_free = mop500_ab8500_hw_free,
353e0690385SOla Lilja 		.startup = mop500_ab8500_startup,
354e0690385SOla Lilja 		.shutdown = mop500_ab8500_shutdown,
355e0690385SOla Lilja 	}
356e0690385SOla Lilja };
357e0690385SOla Lilja 
mop500_ab8500_machine_init(struct snd_soc_pcm_runtime * rtd)358e0690385SOla Lilja int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
359e0690385SOla Lilja {
3605cf57f0fSLars-Peter Clausen 	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
361e0690385SOla Lilja 	struct device *dev = rtd->card->dev;
362e0690385SOla Lilja 	struct mop500_ab8500_drvdata *drvdata;
363e0690385SOla Lilja 	int ret;
364e0690385SOla Lilja 
365e0690385SOla Lilja 	dev_dbg(dev, "%s Enter.\n", __func__);
366e0690385SOla Lilja 
367e0690385SOla Lilja 	/* Create driver private-data struct */
368e0690385SOla Lilja 	drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
369e0690385SOla Lilja 			GFP_KERNEL);
37072f0095eSRajan Vaja 
37172f0095eSRajan Vaja 	if (!drvdata)
37272f0095eSRajan Vaja 		return -ENOMEM;
37372f0095eSRajan Vaja 
374e0690385SOla Lilja 	snd_soc_card_set_drvdata(rtd->card, drvdata);
375e0690385SOla Lilja 
376e0690385SOla Lilja 	/* Setup clocks */
377e0690385SOla Lilja 
378e0690385SOla Lilja 	drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
379e0690385SOla Lilja 	if (IS_ERR(drvdata->clk_ptr_sysclk))
380e0690385SOla Lilja 		dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
381e0690385SOla Lilja 			__func__);
382e0690385SOla Lilja 	drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
383e0690385SOla Lilja 	if (IS_ERR(drvdata->clk_ptr_ulpclk))
384e0690385SOla Lilja 		dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
385e0690385SOla Lilja 			__func__);
386e0690385SOla Lilja 	drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
387e0690385SOla Lilja 	if (IS_ERR(drvdata->clk_ptr_intclk))
388e0690385SOla Lilja 		dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
389e0690385SOla Lilja 			__func__);
390e0690385SOla Lilja 
391e0690385SOla Lilja 	/* Set intclk default parent to ulpclk */
392e0690385SOla Lilja 	drvdata->mclk_sel = MCLK_ULPCLK;
393e0690385SOla Lilja 	ret = mop500_ab8500_set_mclk(dev, drvdata);
394e0690385SOla Lilja 	if (ret < 0)
395e0690385SOla Lilja 		dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
396e0690385SOla Lilja 			__func__);
397e0690385SOla Lilja 
398e0690385SOla Lilja 	drvdata->mclk_sel = MCLK_ULPCLK;
399e0690385SOla Lilja 
400e0690385SOla Lilja 	/* Add controls */
40155bc8253SLars-Peter Clausen 	ret = snd_soc_add_card_controls(rtd->card, mop500_ab8500_ctrls,
402e0690385SOla Lilja 			ARRAY_SIZE(mop500_ab8500_ctrls));
403e0690385SOla Lilja 	if (ret < 0) {
404e0690385SOla Lilja 		pr_err("%s: Failed to add machine-controls (%d)!\n",
405e0690385SOla Lilja 				__func__, ret);
406e0690385SOla Lilja 		return ret;
407e0690385SOla Lilja 	}
408e0690385SOla Lilja 
4095cf57f0fSLars-Peter Clausen 	ret = snd_soc_dapm_disable_pin(dapm, "Earpiece");
4105cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "Speaker Left");
4115cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "Speaker Right");
4125cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "LineOut Left");
4135cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "LineOut Right");
4145cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "Vibra 1");
4155cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "Vibra 2");
4165cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "Mic 1");
4175cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "Mic 2");
4185cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "LineIn Left");
4195cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "LineIn Right");
4205cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "DMic 1");
4215cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "DMic 2");
4225cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "DMic 3");
4235cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "DMic 4");
4245cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "DMic 5");
4255cf57f0fSLars-Peter Clausen 	ret |= snd_soc_dapm_disable_pin(dapm, "DMic 6");
426e0690385SOla Lilja 
427e0690385SOla Lilja 	return ret;
428e0690385SOla Lilja }
429e0690385SOla Lilja 
mop500_ab8500_remove(struct snd_soc_card * card)430e0690385SOla Lilja void mop500_ab8500_remove(struct snd_soc_card *card)
431e0690385SOla Lilja {
432e0690385SOla Lilja 	struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
433e0690385SOla Lilja 
434e0690385SOla Lilja 	clk_put(drvdata->clk_ptr_sysclk);
435e0690385SOla Lilja 	clk_put(drvdata->clk_ptr_ulpclk);
436e0690385SOla Lilja 	clk_put(drvdata->clk_ptr_intclk);
437e0690385SOla Lilja 
438e0690385SOla Lilja 	snd_soc_card_set_drvdata(card, drvdata);
439e0690385SOla Lilja }
440