brintos

brintos / linux-shallow public Read only

0
0
Text · 21.2 KiB · a2dd739 Raw
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