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