Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mop500_ab8500.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) ST-Ericsson SA 2012
3  *
4  * Author: Ola Lilja <[email protected]>,
5  * Kristoffer Karlsson <[email protected]>
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 <mach/hardware.h>
21 
22 #include <sound/soc.h>
23 #include <sound/soc-dapm.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 
27 #include "ux500_pcm.h"
28 #include "ux500_msp_dai.h"
29 #include "../codecs/ab8500-codec.h"
30 
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
37 
38 #define DEF_TX_SLOTS TX_SLOT_STEREO
39 #define DEF_RX_SLOTS RX_SLOT_MONO
40 
41 #define DRIVERMODE_NORMAL 0
42 #define DRIVERMODE_CODEC_ONLY 1
43 
44 /* Slot configuration */
45 static unsigned int tx_slots = DEF_TX_SLOTS;
46 static unsigned int rx_slots = DEF_RX_SLOTS;
47 
48 /* Clocks */
49 static const char * const enum_mclk[] = {
50  "SYSCLK",
51  "ULPCLK"
52 };
53 enum mclk {
56 };
57 
58 static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
59 
60 /* Private data for machine-part MOP500<->AB8500 */
62  /* Clocks */
63  enum mclk mclk_sel;
67 };
68 
69 static inline const char *get_mclk_str(enum mclk mclk_sel)
70 {
71  switch (mclk_sel) {
72  case MCLK_SYSCLK:
73  return "SYSCLK";
74  case MCLK_ULPCLK:
75  return "ULPCLK";
76  default:
77  return "Unknown";
78  }
79 }
80 
81 static int mop500_ab8500_set_mclk(struct device *dev,
83 {
84  int status;
85  struct clk *clk_ptr;
86 
87  if (IS_ERR(drvdata->clk_ptr_intclk)) {
88  dev_err(dev,
89  "%s: ERROR: intclk not initialized!\n", __func__);
90  return -EIO;
91  }
92 
93  switch (drvdata->mclk_sel) {
94  case MCLK_SYSCLK:
95  clk_ptr = drvdata->clk_ptr_sysclk;
96  break;
97  case MCLK_ULPCLK:
98  clk_ptr = drvdata->clk_ptr_ulpclk;
99  break;
100  default:
101  return -EINVAL;
102  }
103 
104  if (IS_ERR(clk_ptr)) {
105  dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
106  get_mclk_str(drvdata->mclk_sel));
107  return -EIO;
108  }
109 
110  status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
111  if (status)
112  dev_err(dev,
113  "%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
114  __func__, get_mclk_str(drvdata->mclk_sel), status);
115  else
116  dev_dbg(dev,
117  "%s: intclk parent changed to %s.\n",
118  __func__, get_mclk_str(drvdata->mclk_sel));
119 
120  return status;
121 }
122 
123 /*
124  * Control-events
125  */
126 
127 static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
128  struct snd_ctl_elem_value *ucontrol)
129 {
130  struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
131  struct mop500_ab8500_drvdata *drvdata =
132  snd_soc_card_get_drvdata(codec->card);
133 
134  ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
135 
136  return 0;
137 }
138 
139 static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
140  struct snd_ctl_elem_value *ucontrol)
141 {
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];
146 
147  if (val > (unsigned int)MCLK_ULPCLK)
148  return -EINVAL;
149  if (drvdata->mclk_sel == val)
150  return 0;
151 
152  drvdata->mclk_sel = val;
153 
154  return 1;
155 }
156 
157 /*
158  * Controls
159  */
160 
161 static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
162  SOC_ENUM_EXT("Master Clock Select",
163  soc_enum_mclk,
164  mclk_input_control_get, mclk_input_control_put),
165  /* Digital interface - Clocks */
166  SOC_SINGLE("Digital Interface Master Generator Switch",
168  1, 0),
169  SOC_SINGLE("Digital Interface 0 Bit-clock Switch",
171  1, 0),
172  SOC_SINGLE("Digital Interface 1 Bit-clock Switch",
174  1, 0),
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"),
194 };
195 
196 /* ASoC */
197 
199 {
200  struct snd_soc_pcm_runtime *rtd = substream->private_data;
201 
202  /* Set audio-clock source */
203  return mop500_ab8500_set_mclk(rtd->card->dev,
204  snd_soc_card_get_drvdata(rtd->card));
205 }
206 
208 {
209  struct snd_soc_pcm_runtime *rtd = substream->private_data;
210  struct device *dev = rtd->card->dev;
211 
212  dev_dbg(dev, "%s: Enter\n", __func__);
213 
214  /* Reset slots configuration to default(s) */
215  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
216  tx_slots = DEF_TX_SLOTS;
217  else
218  rx_slots = DEF_RX_SLOTS;
219 }
220 
222  struct snd_pcm_hw_params *params)
223 {
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;
228  unsigned int fmt;
229  int channels, ret = 0, driver_mode, slots;
230  unsigned int sw_codec, sw_cpu;
231  bool is_playback;
232 
233  dev_dbg(dev, "%s: Enter\n", __func__);
234 
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",
239  __func__,
240  substream->pcm->name,
241  substream->pcm->id,
242  substream->name,
243  substream->number);
244 
245  channels = params_channels(params);
246 
247  switch (params_format(params)) {
249  sw_cpu = 32;
250  break;
251 
253  sw_cpu = 16;
254  break;
255 
256  default:
257  return -EINVAL;
258  }
259 
260  /* Setup codec depending on driver-mode */
261  if (channels == 8)
262  driver_mode = DRIVERMODE_CODEC_ONLY;
263  else
264  driver_mode = DRIVERMODE_NORMAL;
265  dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
266  (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
267 
268  /* Setup format */
269 
270  if (driver_mode == DRIVERMODE_NORMAL) {
271  fmt = SND_SOC_DAIFMT_DSP_A |
275  } else {
276  fmt = SND_SOC_DAIFMT_DSP_A |
280  }
281 
282  ret = snd_soc_dai_set_fmt(codec_dai, fmt);
283  if (ret < 0) {
284  dev_err(dev,
285  "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
286  __func__, ret);
287  return ret;
288  }
289 
290  ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
291  if (ret < 0) {
292  dev_err(dev,
293  "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
294  __func__, ret);
295  return ret;
296  }
297 
298  /* Setup TDM-slots */
299 
300  is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
301  switch (channels) {
302  case 1:
303  slots = 16;
304  tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
305  rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
306  break;
307  case 2:
308  slots = 16;
309  tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
310  rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
311  break;
312  case 8:
313  slots = 16;
314  tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
315  rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
316  break;
317  default:
318  return -EINVAL;
319  }
320 
321  if (driver_mode == DRIVERMODE_NORMAL)
322  sw_codec = sw_cpu;
323  else
324  sw_codec = 20;
325 
326  dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
327  tx_slots, rx_slots);
328  ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
329  sw_cpu);
330  if (ret)
331  return ret;
332 
333  dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
334  tx_slots, rx_slots);
335  ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
336  sw_codec);
337  if (ret)
338  return ret;
339 
340  return 0;
341 }
342 
344  {
345  .hw_params = mop500_ab8500_hw_params,
346  .startup = mop500_ab8500_startup,
347  .shutdown = mop500_ab8500_shutdown,
348  }
349 };
350 
352 {
353  struct snd_soc_codec *codec = rtd->codec;
354  struct device *dev = rtd->card->dev;
356  int ret;
357 
358  dev_dbg(dev, "%s Enter.\n", __func__);
359 
360  /* Create driver private-data struct */
361  drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
362  GFP_KERNEL);
363  snd_soc_card_set_drvdata(rtd->card, drvdata);
364 
365  /* Setup clocks */
366 
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",
370  __func__);
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",
374  __func__);
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",
378  __func__);
379 
380  /* Set intclk default parent to ulpclk */
381  drvdata->mclk_sel = MCLK_ULPCLK;
382  ret = mop500_ab8500_set_mclk(dev, drvdata);
383  if (ret < 0)
384  dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
385  __func__);
386 
387  drvdata->mclk_sel = MCLK_ULPCLK;
388 
389  /* Add controls */
390  ret = snd_soc_add_codec_controls(codec, mop500_ab8500_ctrls,
391  ARRAY_SIZE(mop500_ab8500_ctrls));
392  if (ret < 0) {
393  pr_err("%s: Failed to add machine-controls (%d)!\n",
394  __func__, ret);
395  return ret;
396  }
397 
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");
415 
416  return ret;
417 }
418 
420 {
421  struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
422 
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);
429 
430  snd_soc_card_set_drvdata(card, drvdata);
431 }