2 * Copyright (C) ST-Ericsson SA 2012
4 * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
5 * Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
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.
15 #include <linux/module.h>
16 #include <linux/device.h>
18 #include <linux/clk.h>
20 #include <mach/hardware.h>
22 #include <sound/soc.h>
23 #include <sound/soc-dapm.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
27 #include "ux500_pcm.h"
28 #include "ux500_msp_dai.h"
29 #include "../codecs/ab8500-codec.h"
31 #define TX_SLOT_MONO 0x0008
32 #define TX_SLOT_STEREO 0x000a
33 #define RX_SLOT_MONO 0x0001
34 #define RX_SLOT_STEREO 0x0003
35 #define TX_SLOT_8CH 0x00FF
36 #define RX_SLOT_8CH 0x00FF
38 #define DEF_TX_SLOTS TX_SLOT_STEREO
39 #define DEF_RX_SLOTS RX_SLOT_MONO
41 #define DRIVERMODE_NORMAL 0
42 #define DRIVERMODE_CODEC_ONLY 1
44 /* Slot configuration */
45 static unsigned int tx_slots
= DEF_TX_SLOTS
;
46 static unsigned int rx_slots
= DEF_RX_SLOTS
;
49 static const char * const enum_mclk
[] = {
58 static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk
, enum_mclk
);
60 /* Private data for machine-part MOP500<->AB8500 */
61 struct mop500_ab8500_drvdata
{
64 struct clk
*clk_ptr_intclk
;
65 struct clk
*clk_ptr_sysclk
;
66 struct clk
*clk_ptr_ulpclk
;
69 static inline const char *get_mclk_str(enum mclk mclk_sel
)
81 static int mop500_ab8500_set_mclk(struct device
*dev
,
82 struct mop500_ab8500_drvdata
*drvdata
)
87 if (IS_ERR(drvdata
->clk_ptr_intclk
)) {
89 "%s: ERROR: intclk not initialized!\n", __func__
);
93 switch (drvdata
->mclk_sel
) {
95 clk_ptr
= drvdata
->clk_ptr_sysclk
;
98 clk_ptr
= drvdata
->clk_ptr_ulpclk
;
104 if (IS_ERR(clk_ptr
)) {
105 dev_err(dev
, "%s: ERROR: %s not initialized!\n", __func__
,
106 get_mclk_str(drvdata
->mclk_sel
));
110 status
= clk_set_parent(drvdata
->clk_ptr_intclk
, clk_ptr
);
113 "%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
114 __func__
, get_mclk_str(drvdata
->mclk_sel
), status
);
117 "%s: intclk parent changed to %s.\n",
118 __func__
, get_mclk_str(drvdata
->mclk_sel
));
127 static int mclk_input_control_get(struct snd_kcontrol
*kcontrol
,
128 struct snd_ctl_elem_value
*ucontrol
)
130 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
131 struct mop500_ab8500_drvdata
*drvdata
=
132 snd_soc_card_get_drvdata(codec
->card
);
134 ucontrol
->value
.enumerated
.item
[0] = drvdata
->mclk_sel
;
139 static int mclk_input_control_put(struct snd_kcontrol
*kcontrol
,
140 struct snd_ctl_elem_value
*ucontrol
)
142 struct snd_soc_codec
*codec
= snd_kcontrol_chip(kcontrol
);
143 struct mop500_ab8500_drvdata
*drvdata
=
144 snd_soc_card_get_drvdata(codec
->card
);
145 unsigned int val
= ucontrol
->value
.enumerated
.item
[0];
147 if (val
> (unsigned int)MCLK_ULPCLK
)
149 if (drvdata
->mclk_sel
== val
)
152 drvdata
->mclk_sel
= val
;
161 static struct snd_kcontrol_new mop500_ab8500_ctrls
[] = {
162 SOC_ENUM_EXT("Master Clock Select",
164 mclk_input_control_get
, mclk_input_control_put
),
165 /* Digital interface - Clocks */
166 SOC_SINGLE("Digital Interface Master Generator Switch",
167 AB8500_DIGIFCONF1
, AB8500_DIGIFCONF1_ENMASTGEN
,
169 SOC_SINGLE("Digital Interface 0 Bit-clock Switch",
170 AB8500_DIGIFCONF1
, AB8500_DIGIFCONF1_ENFSBITCLK0
,
172 SOC_SINGLE("Digital Interface 1 Bit-clock Switch",
173 AB8500_DIGIFCONF1
, AB8500_DIGIFCONF1_ENFSBITCLK1
,
175 SOC_DAPM_PIN_SWITCH("Headset Left"),
176 SOC_DAPM_PIN_SWITCH("Headset Right"),
177 SOC_DAPM_PIN_SWITCH("Earpiece"),
178 SOC_DAPM_PIN_SWITCH("Speaker Left"),
179 SOC_DAPM_PIN_SWITCH("Speaker Right"),
180 SOC_DAPM_PIN_SWITCH("LineOut Left"),
181 SOC_DAPM_PIN_SWITCH("LineOut Right"),
182 SOC_DAPM_PIN_SWITCH("Vibra 1"),
183 SOC_DAPM_PIN_SWITCH("Vibra 2"),
184 SOC_DAPM_PIN_SWITCH("Mic 1"),
185 SOC_DAPM_PIN_SWITCH("Mic 2"),
186 SOC_DAPM_PIN_SWITCH("LineIn Left"),
187 SOC_DAPM_PIN_SWITCH("LineIn Right"),
188 SOC_DAPM_PIN_SWITCH("DMic 1"),
189 SOC_DAPM_PIN_SWITCH("DMic 2"),
190 SOC_DAPM_PIN_SWITCH("DMic 3"),
191 SOC_DAPM_PIN_SWITCH("DMic 4"),
192 SOC_DAPM_PIN_SWITCH("DMic 5"),
193 SOC_DAPM_PIN_SWITCH("DMic 6"),
198 int mop500_ab8500_startup(struct snd_pcm_substream
*substream
)
200 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
202 /* Set audio-clock source */
203 return mop500_ab8500_set_mclk(rtd
->card
->dev
,
204 snd_soc_card_get_drvdata(rtd
->card
));
207 void mop500_ab8500_shutdown(struct snd_pcm_substream
*substream
)
209 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
210 struct device
*dev
= rtd
->card
->dev
;
212 dev_dbg(dev
, "%s: Enter\n", __func__
);
214 /* Reset slots configuration to default(s) */
215 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
216 tx_slots
= DEF_TX_SLOTS
;
218 rx_slots
= DEF_RX_SLOTS
;
221 int mop500_ab8500_hw_params(struct snd_pcm_substream
*substream
,
222 struct snd_pcm_hw_params
*params
)
224 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
225 struct snd_soc_dai
*codec_dai
= rtd
->codec_dai
;
226 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
227 struct device
*dev
= rtd
->card
->dev
;
229 int channels
, ret
= 0, driver_mode
, slots
;
230 unsigned int sw_codec
, sw_cpu
;
233 dev_dbg(dev
, "%s: Enter\n", __func__
);
235 dev_dbg(dev
, "%s: substream->pcm->name = %s\n"
236 "substream->pcm->id = %s.\n"
237 "substream->name = %s.\n"
238 "substream->number = %d.\n",
240 substream
->pcm
->name
,
245 channels
= params_channels(params
);
247 switch (params_format(params
)) {
248 case SNDRV_PCM_FORMAT_S32_LE
:
252 case SNDRV_PCM_FORMAT_S16_LE
:
260 /* Setup codec depending on driver-mode */
262 driver_mode
= DRIVERMODE_CODEC_ONLY
;
264 driver_mode
= DRIVERMODE_NORMAL
;
265 dev_dbg(dev
, "%s: Driver-mode: %s.\n", __func__
,
266 (driver_mode
== DRIVERMODE_NORMAL
) ? "NORMAL" : "CODEC_ONLY");
270 if (driver_mode
== DRIVERMODE_NORMAL
) {
271 fmt
= SND_SOC_DAIFMT_DSP_A
|
272 SND_SOC_DAIFMT_CBM_CFM
|
273 SND_SOC_DAIFMT_NB_NF
|
276 fmt
= SND_SOC_DAIFMT_DSP_A
|
277 SND_SOC_DAIFMT_CBM_CFM
|
278 SND_SOC_DAIFMT_NB_NF
|
279 SND_SOC_DAIFMT_GATED
;
282 ret
= snd_soc_dai_set_fmt(codec_dai
, fmt
);
285 "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
290 ret
= snd_soc_dai_set_fmt(cpu_dai
, fmt
);
293 "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
298 /* Setup TDM-slots */
300 is_playback
= (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
);
304 tx_slots
= (is_playback
) ? TX_SLOT_MONO
: 0;
305 rx_slots
= (is_playback
) ? 0 : RX_SLOT_MONO
;
309 tx_slots
= (is_playback
) ? TX_SLOT_STEREO
: 0;
310 rx_slots
= (is_playback
) ? 0 : RX_SLOT_STEREO
;
314 tx_slots
= (is_playback
) ? TX_SLOT_8CH
: 0;
315 rx_slots
= (is_playback
) ? 0 : RX_SLOT_8CH
;
321 if (driver_mode
== DRIVERMODE_NORMAL
)
326 dev_dbg(dev
, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__
,
328 ret
= snd_soc_dai_set_tdm_slot(cpu_dai
, tx_slots
, rx_slots
, slots
,
333 dev_dbg(dev
, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__
,
335 ret
= snd_soc_dai_set_tdm_slot(codec_dai
, tx_slots
, rx_slots
, slots
,
343 struct snd_soc_ops mop500_ab8500_ops
[] = {
345 .hw_params
= mop500_ab8500_hw_params
,
346 .startup
= mop500_ab8500_startup
,
347 .shutdown
= mop500_ab8500_shutdown
,
351 int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime
*rtd
)
353 struct snd_soc_codec
*codec
= rtd
->codec
;
354 struct device
*dev
= rtd
->card
->dev
;
355 struct mop500_ab8500_drvdata
*drvdata
;
358 dev_dbg(dev
, "%s Enter.\n", __func__
);
360 /* Create driver private-data struct */
361 drvdata
= devm_kzalloc(dev
, sizeof(struct mop500_ab8500_drvdata
),
363 snd_soc_card_set_drvdata(rtd
->card
, drvdata
);
367 drvdata
->clk_ptr_sysclk
= clk_get(dev
, "sysclk");
368 if (IS_ERR(drvdata
->clk_ptr_sysclk
))
369 dev_warn(dev
, "%s: WARNING: clk_get failed for 'sysclk'!\n",
371 drvdata
->clk_ptr_ulpclk
= clk_get(dev
, "ulpclk");
372 if (IS_ERR(drvdata
->clk_ptr_ulpclk
))
373 dev_warn(dev
, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
375 drvdata
->clk_ptr_intclk
= clk_get(dev
, "intclk");
376 if (IS_ERR(drvdata
->clk_ptr_intclk
))
377 dev_warn(dev
, "%s: WARNING: clk_get failed for 'intclk'!\n",
380 /* Set intclk default parent to ulpclk */
381 drvdata
->mclk_sel
= MCLK_ULPCLK
;
382 ret
= mop500_ab8500_set_mclk(dev
, drvdata
);
384 dev_warn(dev
, "%s: WARNING: mop500_ab8500_set_mclk!\n",
387 drvdata
->mclk_sel
= MCLK_ULPCLK
;
390 ret
= snd_soc_add_codec_controls(codec
, mop500_ab8500_ctrls
,
391 ARRAY_SIZE(mop500_ab8500_ctrls
));
393 pr_err("%s: Failed to add machine-controls (%d)!\n",
398 ret
= snd_soc_dapm_disable_pin(&codec
->dapm
, "Earpiece");
399 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "Speaker Left");
400 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "Speaker Right");
401 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "LineOut Left");
402 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "LineOut Right");
403 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "Vibra 1");
404 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "Vibra 2");
405 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "Mic 1");
406 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "Mic 2");
407 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "LineIn Left");
408 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "LineIn Right");
409 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "DMic 1");
410 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "DMic 2");
411 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "DMic 3");
412 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "DMic 4");
413 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "DMic 5");
414 ret
|= snd_soc_dapm_disable_pin(&codec
->dapm
, "DMic 6");
419 void mop500_ab8500_remove(struct snd_soc_card
*card
)
421 struct mop500_ab8500_drvdata
*drvdata
= snd_soc_card_get_drvdata(card
);
423 if (drvdata
->clk_ptr_sysclk
!= NULL
)
424 clk_put(drvdata
->clk_ptr_sysclk
);
425 if (drvdata
->clk_ptr_ulpclk
!= NULL
)
426 clk_put(drvdata
->clk_ptr_ulpclk
);
427 if (drvdata
->clk_ptr_intclk
!= NULL
)
428 clk_put(drvdata
->clk_ptr_intclk
);
430 snd_soc_card_set_drvdata(card
, drvdata
);