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