825 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) ST-Ericsson SA 20124 *5 * Author: Ola Lilja <ola.o.lilja@stericsson.com>,6 * Roger Nilsson <roger.xr.nilsson@stericsson.com>7 * for ST-Ericsson.8 */9 10#include <linux/module.h>11#include <linux/slab.h>12#include <linux/bitops.h>13#include <linux/platform_device.h>14#include <linux/clk.h>15#include <linux/of.h>16#include <linux/regulator/consumer.h>17#include <linux/mfd/dbx500-prcmu.h>18 19#include <sound/soc.h>20#include <sound/soc-dai.h>21#include <sound/dmaengine_pcm.h>22 23#include "ux500_msp_i2s.h"24#include "ux500_msp_dai.h"25#include "ux500_pcm.h"26 27static int setup_pcm_multichan(struct snd_soc_dai *dai,28 struct ux500_msp_config *msp_config)29{30 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);31 struct msp_multichannel_config *multi =32 &msp_config->multichannel_config;33 34 if (drvdata->slots > 1) {35 msp_config->multichannel_configured = 1;36 37 multi->tx_multichannel_enable = true;38 multi->rx_multichannel_enable = true;39 multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;40 41 multi->tx_channel_0_enable = drvdata->tx_mask;42 multi->tx_channel_1_enable = 0;43 multi->tx_channel_2_enable = 0;44 multi->tx_channel_3_enable = 0;45 46 multi->rx_channel_0_enable = drvdata->rx_mask;47 multi->rx_channel_1_enable = 0;48 multi->rx_channel_2_enable = 0;49 multi->rx_channel_3_enable = 0;50 51 dev_dbg(dai->dev,52 "%s: Multichannel enabled. Slots: %d, TX: %u, RX: %u\n",53 __func__, drvdata->slots, multi->tx_channel_0_enable,54 multi->rx_channel_0_enable);55 }56 57 return 0;58}59 60static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,61 struct msp_protdesc *prot_desc)62{63 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);64 65 switch (drvdata->slots) {66 case 1:67 switch (rate) {68 case 8000:69 prot_desc->frame_period =70 FRAME_PER_SINGLE_SLOT_8_KHZ;71 break;72 73 case 16000:74 prot_desc->frame_period =75 FRAME_PER_SINGLE_SLOT_16_KHZ;76 break;77 78 case 44100:79 prot_desc->frame_period =80 FRAME_PER_SINGLE_SLOT_44_1_KHZ;81 break;82 83 case 48000:84 prot_desc->frame_period =85 FRAME_PER_SINGLE_SLOT_48_KHZ;86 break;87 88 default:89 dev_err(dai->dev,90 "%s: Error: Unsupported sample-rate (freq = %d)!\n",91 __func__, rate);92 return -EINVAL;93 }94 break;95 96 case 2:97 prot_desc->frame_period = FRAME_PER_2_SLOTS;98 break;99 100 case 8:101 prot_desc->frame_period = FRAME_PER_8_SLOTS;102 break;103 104 case 16:105 prot_desc->frame_period = FRAME_PER_16_SLOTS;106 break;107 default:108 dev_err(dai->dev,109 "%s: Error: Unsupported slot-count (slots = %d)!\n",110 __func__, drvdata->slots);111 return -EINVAL;112 }113 114 prot_desc->clocks_per_frame =115 prot_desc->frame_period+1;116 117 dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",118 __func__,119 prot_desc->clocks_per_frame);120 121 return 0;122}123 124static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,125 struct msp_protdesc *prot_desc)126{127 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);128 129 u32 frame_length = MSP_FRAME_LEN_1;130 131 prot_desc->frame_width = 0;132 133 switch (drvdata->slots) {134 case 1:135 frame_length = MSP_FRAME_LEN_1;136 break;137 138 case 2:139 frame_length = MSP_FRAME_LEN_2;140 break;141 142 case 8:143 frame_length = MSP_FRAME_LEN_8;144 break;145 146 case 16:147 frame_length = MSP_FRAME_LEN_16;148 break;149 default:150 dev_err(dai->dev,151 "%s: Error: Unsupported slot-count (slots = %d)!\n",152 __func__, drvdata->slots);153 return -EINVAL;154 }155 156 prot_desc->tx_frame_len_1 = frame_length;157 prot_desc->rx_frame_len_1 = frame_length;158 prot_desc->tx_frame_len_2 = frame_length;159 prot_desc->rx_frame_len_2 = frame_length;160 161 prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;162 prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;163 prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;164 prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;165 166 return setup_frameper(dai, rate, prot_desc);167}168 169static int setup_clocking(struct snd_soc_dai *dai,170 unsigned int fmt,171 struct ux500_msp_config *msp_config)172{173 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {174 case SND_SOC_DAIFMT_NB_NF:175 break;176 177 case SND_SOC_DAIFMT_NB_IF:178 msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;179 msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;180 181 break;182 183 default:184 dev_err(dai->dev,185 "%s: Error: Unsupported inversion (fmt = 0x%x)!\n",186 __func__, fmt);187 188 return -EINVAL;189 }190 191 switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {192 case SND_SOC_DAIFMT_BC_FC:193 dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);194 195 msp_config->iodelay = 0x20;196 msp_config->rx_fsync_sel = 0;197 msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;198 msp_config->tx_clk_sel = 0;199 msp_config->rx_clk_sel = 0;200 msp_config->srg_clk_sel = 0x2 << SCKSEL_SHIFT;201 202 break;203 204 case SND_SOC_DAIFMT_BP_FP:205 dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);206 207 msp_config->tx_clk_sel = TX_CLK_SEL_SRG;208 msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;209 msp_config->rx_clk_sel = RX_CLK_SEL_SRG;210 msp_config->rx_fsync_sel = RX_SYNC_SRG;211 msp_config->srg_clk_sel = 1 << SCKSEL_SHIFT;212 213 break;214 215 default:216 dev_err(dai->dev, "%s: Error: Unsupported master (fmt = 0x%x)!\n",217 __func__, fmt);218 219 return -EINVAL;220 }221 222 return 0;223}224 225static int setup_pcm_protdesc(struct snd_soc_dai *dai,226 unsigned int fmt,227 struct msp_protdesc *prot_desc)228{229 prot_desc->rx_phase_mode = MSP_SINGLE_PHASE;230 prot_desc->tx_phase_mode = MSP_SINGLE_PHASE;231 prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;232 prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;233 prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;234 prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;235 prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_HI);236 prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_HI << RFSPOL_SHIFT;237 238 if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) {239 dev_dbg(dai->dev, "%s: DSP_A.\n", __func__);240 prot_desc->rx_clk_pol = MSP_RISING_EDGE;241 prot_desc->tx_clk_pol = MSP_FALLING_EDGE;242 243 prot_desc->rx_data_delay = MSP_DELAY_1;244 prot_desc->tx_data_delay = MSP_DELAY_1;245 } else {246 dev_dbg(dai->dev, "%s: DSP_B.\n", __func__);247 prot_desc->rx_clk_pol = MSP_FALLING_EDGE;248 prot_desc->tx_clk_pol = MSP_RISING_EDGE;249 250 prot_desc->rx_data_delay = MSP_DELAY_0;251 prot_desc->tx_data_delay = MSP_DELAY_0;252 }253 254 prot_desc->rx_half_word_swap = MSP_SWAP_NONE;255 prot_desc->tx_half_word_swap = MSP_SWAP_NONE;256 prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;257 prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;258 prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;259 260 return 0;261}262 263static int setup_i2s_protdesc(struct msp_protdesc *prot_desc)264{265 prot_desc->rx_phase_mode = MSP_DUAL_PHASE;266 prot_desc->tx_phase_mode = MSP_DUAL_PHASE;267 prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;268 prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;269 prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;270 prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;271 prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_LO);272 prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_LO << RFSPOL_SHIFT;273 274 prot_desc->rx_frame_len_1 = MSP_FRAME_LEN_1;275 prot_desc->rx_frame_len_2 = MSP_FRAME_LEN_1;276 prot_desc->tx_frame_len_1 = MSP_FRAME_LEN_1;277 prot_desc->tx_frame_len_2 = MSP_FRAME_LEN_1;278 prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;279 prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;280 prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;281 prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;282 283 prot_desc->rx_clk_pol = MSP_RISING_EDGE;284 prot_desc->tx_clk_pol = MSP_FALLING_EDGE;285 286 prot_desc->rx_data_delay = MSP_DELAY_0;287 prot_desc->tx_data_delay = MSP_DELAY_0;288 289 prot_desc->tx_half_word_swap = MSP_SWAP_NONE;290 prot_desc->rx_half_word_swap = MSP_SWAP_NONE;291 prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;292 prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;293 prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;294 295 return 0;296}297 298static int setup_msp_config(struct snd_pcm_substream *substream,299 struct snd_soc_dai *dai,300 struct ux500_msp_config *msp_config)301{302 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);303 struct msp_protdesc *prot_desc = &msp_config->protdesc;304 struct snd_pcm_runtime *runtime = substream->runtime;305 unsigned int fmt = drvdata->fmt;306 int ret;307 308 memset(msp_config, 0, sizeof(*msp_config));309 310 msp_config->f_inputclk = drvdata->master_clk;311 312 msp_config->tx_fifo_config = TX_FIFO_ENABLE;313 msp_config->rx_fifo_config = RX_FIFO_ENABLE;314 msp_config->def_elem_len = 1;315 msp_config->direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?316 MSP_DIR_TX : MSP_DIR_RX;317 msp_config->data_size = MSP_DATA_BITS_32;318 msp_config->frame_freq = runtime->rate;319 320 dev_dbg(dai->dev, "%s: f_inputclk = %u, frame_freq = %u.\n",321 __func__, msp_config->f_inputclk, msp_config->frame_freq);322 /* To avoid division by zero */323 prot_desc->clocks_per_frame = 1;324 325 dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,326 runtime->rate, runtime->channels);327 switch (fmt &328 (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) {329 case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP:330 dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);331 332 msp_config->default_protdesc = 1;333 msp_config->protocol = MSP_I2S_PROTOCOL;334 break;335 336 case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC:337 dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);338 339 msp_config->data_size = MSP_DATA_BITS_16;340 msp_config->protocol = MSP_I2S_PROTOCOL;341 342 ret = setup_i2s_protdesc(prot_desc);343 if (ret < 0)344 return ret;345 346 break;347 348 case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP:349 case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC:350 case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP:351 case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC:352 dev_dbg(dai->dev, "%s: PCM format.\n", __func__);353 354 msp_config->data_size = MSP_DATA_BITS_16;355 msp_config->protocol = MSP_PCM_PROTOCOL;356 357 ret = setup_pcm_protdesc(dai, fmt, prot_desc);358 if (ret < 0)359 return ret;360 361 ret = setup_pcm_multichan(dai, msp_config);362 if (ret < 0)363 return ret;364 365 ret = setup_pcm_framing(dai, runtime->rate, prot_desc);366 if (ret < 0)367 return ret;368 369 break;370 371 default:372 dev_err(dai->dev, "%s: Error: Unsupported format (%d)!\n",373 __func__, fmt);374 return -EINVAL;375 }376 377 return setup_clocking(dai, fmt, msp_config);378}379 380static int ux500_msp_dai_startup(struct snd_pcm_substream *substream,381 struct snd_soc_dai *dai)382{383 int ret = 0;384 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);385 386 dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,387 snd_pcm_stream_str(substream));388 389 /* Enable regulator */390 ret = regulator_enable(drvdata->reg_vape);391 if (ret != 0) {392 dev_err(drvdata->msp->dev,393 "%s: Failed to enable regulator!\n", __func__);394 return ret;395 }396 397 /* Prepare and enable clocks */398 dev_dbg(dai->dev, "%s: Enabling MSP-clocks.\n", __func__);399 ret = clk_prepare_enable(drvdata->pclk);400 if (ret) {401 dev_err(drvdata->msp->dev,402 "%s: Failed to prepare/enable pclk!\n", __func__);403 goto err_pclk;404 }405 406 ret = clk_prepare_enable(drvdata->clk);407 if (ret) {408 dev_err(drvdata->msp->dev,409 "%s: Failed to prepare/enable clk!\n", __func__);410 goto err_clk;411 }412 413 return ret;414err_clk:415 clk_disable_unprepare(drvdata->pclk);416err_pclk:417 regulator_disable(drvdata->reg_vape);418 return ret;419}420 421static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,422 struct snd_soc_dai *dai)423{424 int ret;425 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);426 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);427 428 dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,429 snd_pcm_stream_str(substream));430 431 if (drvdata->vape_opp_constraint == 1) {432 prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,433 "ux500_msp_i2s", 50);434 drvdata->vape_opp_constraint = 0;435 }436 437 if (ux500_msp_i2s_close(drvdata->msp,438 is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {439 dev_err(dai->dev,440 "%s: Error: MSP %d (%s): Unable to close i2s.\n",441 __func__, dai->id, snd_pcm_stream_str(substream));442 }443 444 /* Disable and unprepare clocks */445 clk_disable_unprepare(drvdata->clk);446 clk_disable_unprepare(drvdata->pclk);447 448 /* Disable regulator */449 ret = regulator_disable(drvdata->reg_vape);450 if (ret < 0)451 dev_err(dai->dev,452 "%s: ERROR: Failed to disable regulator (%d)!\n",453 __func__, ret);454}455 456static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,457 struct snd_soc_dai *dai)458{459 int ret = 0;460 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);461 struct snd_pcm_runtime *runtime = substream->runtime;462 struct ux500_msp_config msp_config;463 464 dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,465 dai->id, snd_pcm_stream_str(substream), runtime->rate);466 467 setup_msp_config(substream, dai, &msp_config);468 469 ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);470 if (ret < 0) {471 dev_err(dai->dev, "%s: Error: msp_setup failed (ret = %d)!\n",472 __func__, ret);473 return ret;474 }475 476 /* Set OPP-level */477 if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) &&478 (drvdata->msp->f_bitclk > 19200000)) {479 /* If the bit-clock is higher than 19.2MHz, Vape should be480 * run in 100% OPP. Only when bit-clock is used (MSP master)481 */482 prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,483 "ux500-msp-i2s", 100);484 drvdata->vape_opp_constraint = 1;485 } else {486 prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,487 "ux500-msp-i2s", 50);488 drvdata->vape_opp_constraint = 0;489 }490 491 return ret;492}493 494static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,495 struct snd_pcm_hw_params *params,496 struct snd_soc_dai *dai)497{498 unsigned int mask, slots_active;499 struct snd_pcm_runtime *runtime = substream->runtime;500 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);501 502 dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",503 __func__, dai->id, snd_pcm_stream_str(substream));504 505 switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {506 case SND_SOC_DAIFMT_I2S:507 snd_pcm_hw_constraint_minmax(runtime,508 SNDRV_PCM_HW_PARAM_CHANNELS,509 1, 2);510 break;511 512 case SND_SOC_DAIFMT_DSP_B:513 case SND_SOC_DAIFMT_DSP_A:514 mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?515 drvdata->tx_mask :516 drvdata->rx_mask;517 518 slots_active = hweight32(mask);519 dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);520 521 snd_pcm_hw_constraint_single(runtime,522 SNDRV_PCM_HW_PARAM_CHANNELS,523 slots_active);524 break;525 526 default:527 dev_err(dai->dev,528 "%s: Error: Unsupported protocol (fmt = 0x%x)!\n",529 __func__, drvdata->fmt);530 return -EINVAL;531 }532 533 return 0;534}535 536static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,537 unsigned int fmt)538{539 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);540 541 dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);542 543 switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |544 SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) {545 case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP:546 case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC:547 case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP:548 case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC:549 case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP:550 case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC:551 break;552 553 default:554 dev_err(dai->dev,555 "%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",556 __func__, drvdata->fmt);557 return -EINVAL;558 }559 560 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {561 case SND_SOC_DAIFMT_NB_NF:562 case SND_SOC_DAIFMT_NB_IF:563 case SND_SOC_DAIFMT_IB_IF:564 break;565 566 default:567 dev_err(dai->dev,568 "%s: Error: Unsupported inversion (fmt = 0x%x)!\n",569 __func__, drvdata->fmt);570 return -EINVAL;571 }572 573 drvdata->fmt = fmt;574 return 0;575}576 577static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,578 unsigned int tx_mask,579 unsigned int rx_mask,580 int slots, int slot_width)581{582 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);583 unsigned int cap;584 585 switch (slots) {586 case 1:587 cap = 0x01;588 break;589 case 2:590 cap = 0x03;591 break;592 case 8:593 cap = 0xFF;594 break;595 case 16:596 cap = 0xFFFF;597 break;598 default:599 dev_err(dai->dev, "%s: Error: Unsupported slot-count (%d)!\n",600 __func__, slots);601 return -EINVAL;602 }603 drvdata->slots = slots;604 605 if (!(slot_width == 16)) {606 dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",607 __func__, slot_width);608 return -EINVAL;609 }610 drvdata->slot_width = slot_width;611 612 drvdata->tx_mask = tx_mask & cap;613 drvdata->rx_mask = rx_mask & cap;614 615 return 0;616}617 618static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai,619 int clk_id, unsigned int freq, int dir)620{621 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);622 623 dev_dbg(dai->dev, "%s: MSP %d: Enter. clk-id: %d, freq: %u.\n",624 __func__, dai->id, clk_id, freq);625 626 switch (clk_id) {627 case UX500_MSP_MASTER_CLOCK:628 drvdata->master_clk = freq;629 break;630 631 default:632 dev_err(dai->dev, "%s: MSP %d: Invalid clk-id (%d)!\n",633 __func__, dai->id, clk_id);634 return -EINVAL;635 }636 637 return 0;638}639 640static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,641 int cmd, struct snd_soc_dai *dai)642{643 int ret = 0;644 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);645 646 dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n",647 __func__, dai->id, snd_pcm_stream_str(substream),648 (int)drvdata->msp->id, cmd);649 650 ret = ux500_msp_i2s_trigger(drvdata->msp, cmd, substream->stream);651 652 return ret;653}654 655static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)656{657 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);658 struct snd_dmaengine_dai_dma_data *playback_dma_data;659 struct snd_dmaengine_dai_dma_data *capture_dma_data;660 661 playback_dma_data = devm_kzalloc(dai->dev,662 sizeof(*playback_dma_data),663 GFP_KERNEL);664 if (!playback_dma_data)665 return -ENOMEM;666 667 capture_dma_data = devm_kzalloc(dai->dev,668 sizeof(*capture_dma_data),669 GFP_KERNEL);670 if (!capture_dma_data)671 return -ENOMEM;672 673 playback_dma_data->addr = drvdata->msp->tx_rx_addr;674 capture_dma_data->addr = drvdata->msp->tx_rx_addr;675 676 playback_dma_data->maxburst = 4;677 capture_dma_data->maxburst = 4;678 679 snd_soc_dai_init_dma_data(dai, playback_dma_data, capture_dma_data);680 681 return 0;682}683 684static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {685 {686 .probe = ux500_msp_dai_of_probe,687 .set_sysclk = ux500_msp_dai_set_dai_sysclk,688 .set_fmt = ux500_msp_dai_set_dai_fmt,689 .set_tdm_slot = ux500_msp_dai_set_tdm_slot,690 .startup = ux500_msp_dai_startup,691 .shutdown = ux500_msp_dai_shutdown,692 .prepare = ux500_msp_dai_prepare,693 .trigger = ux500_msp_dai_trigger,694 .hw_params = ux500_msp_dai_hw_params,695 }696};697 698static struct snd_soc_dai_driver ux500_msp_dai_drv = {699 .playback.channels_min = UX500_MSP_MIN_CHANNELS,700 .playback.channels_max = UX500_MSP_MAX_CHANNELS,701 .playback.rates = UX500_I2S_RATES,702 .playback.formats = UX500_I2S_FORMATS,703 .capture.channels_min = UX500_MSP_MIN_CHANNELS,704 .capture.channels_max = UX500_MSP_MAX_CHANNELS,705 .capture.rates = UX500_I2S_RATES,706 .capture.formats = UX500_I2S_FORMATS,707 .ops = ux500_msp_dai_ops,708};709 710static const struct snd_soc_component_driver ux500_msp_component = {711 .name = "ux500-msp",712 .legacy_dai_naming = 1,713};714 715 716static int ux500_msp_drv_probe(struct platform_device *pdev)717{718 struct ux500_msp_i2s_drvdata *drvdata;719 int ret = 0;720 721 drvdata = devm_kzalloc(&pdev->dev,722 sizeof(struct ux500_msp_i2s_drvdata),723 GFP_KERNEL);724 if (!drvdata)725 return -ENOMEM;726 727 drvdata->fmt = 0;728 drvdata->slots = 1;729 drvdata->tx_mask = 0x01;730 drvdata->rx_mask = 0x01;731 drvdata->slot_width = 16;732 drvdata->master_clk = MSP_INPUT_FREQ_APB;733 734 drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");735 if (IS_ERR(drvdata->reg_vape)) {736 ret = (int)PTR_ERR(drvdata->reg_vape);737 dev_err(&pdev->dev,738 "%s: ERROR: Failed to get Vape supply (%d)!\n",739 __func__, ret);740 return ret;741 }742 prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);743 744 drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk");745 if (IS_ERR(drvdata->pclk)) {746 ret = (int)PTR_ERR(drvdata->pclk);747 dev_err(&pdev->dev,748 "%s: ERROR: devm_clk_get of pclk failed (%d)!\n",749 __func__, ret);750 return ret;751 }752 753 drvdata->clk = devm_clk_get(&pdev->dev, NULL);754 if (IS_ERR(drvdata->clk)) {755 ret = (int)PTR_ERR(drvdata->clk);756 dev_err(&pdev->dev,757 "%s: ERROR: devm_clk_get failed (%d)!\n",758 __func__, ret);759 return ret;760 }761 762 ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp);763 if (!drvdata->msp) {764 dev_err(&pdev->dev,765 "%s: ERROR: Failed to init MSP-struct (%d)!",766 __func__, ret);767 return ret;768 }769 dev_set_drvdata(&pdev->dev, drvdata);770 771 ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,772 &ux500_msp_dai_drv, 1);773 if (ret < 0) {774 dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",775 __func__, drvdata->msp->id);776 return ret;777 }778 779 ret = ux500_pcm_register_platform(pdev);780 if (ret < 0) {781 dev_err(&pdev->dev,782 "Error: %s: Failed to register PCM platform device!\n",783 __func__);784 goto err_reg_plat;785 }786 787 return 0;788 789err_reg_plat:790 snd_soc_unregister_component(&pdev->dev);791 return ret;792}793 794static void ux500_msp_drv_remove(struct platform_device *pdev)795{796 struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev);797 798 ux500_pcm_unregister_platform(pdev);799 800 snd_soc_unregister_component(&pdev->dev);801 802 prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");803 804 ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);805}806 807static const struct of_device_id ux500_msp_i2s_match[] = {808 { .compatible = "stericsson,ux500-msp-i2s", },809 {},810};811MODULE_DEVICE_TABLE(of, ux500_msp_i2s_match);812 813static struct platform_driver msp_i2s_driver = {814 .driver = {815 .name = "ux500-msp-i2s",816 .of_match_table = ux500_msp_i2s_match,817 },818 .probe = ux500_msp_drv_probe,819 .remove = ux500_msp_drv_remove,820};821module_platform_driver(msp_i2s_driver);822 823MODULE_DESCRIPTION("ASoC Ux500 I2S driver");824MODULE_LICENSE("GPL v2");825