xref: /OK3568_Linux_fs/kernel/sound/soc/sti/sti_uniperif.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) STMicroelectronics SA 2015
4*4882a593Smuzhiyun  * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
5*4882a593Smuzhiyun  *          for STMicroelectronics.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "uniperif.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun  * User frame size shall be 2, 4, 6 or 8 32-bits words length
16*4882a593Smuzhiyun  * (i.e. 8, 16, 24 or 32 bytes)
17*4882a593Smuzhiyun  * This constraint comes from allowed values for
18*4882a593Smuzhiyun  * UNIPERIF_I2S_FMT_NUM_CH register
19*4882a593Smuzhiyun  */
20*4882a593Smuzhiyun #define UNIPERIF_MAX_FRAME_SZ 0x20
21*4882a593Smuzhiyun #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ)
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun struct sti_uniperiph_dev_data {
24*4882a593Smuzhiyun 	unsigned int id; /* Nb available player instances */
25*4882a593Smuzhiyun 	unsigned int version; /* player IP version */
26*4882a593Smuzhiyun 	unsigned int stream;
27*4882a593Smuzhiyun 	const char *dai_names;
28*4882a593Smuzhiyun 	enum uniperif_type type;
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static const struct sti_uniperiph_dev_data sti_uniplayer_hdmi = {
32*4882a593Smuzhiyun 	.id = 0,
33*4882a593Smuzhiyun 	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
34*4882a593Smuzhiyun 	.stream = SNDRV_PCM_STREAM_PLAYBACK,
35*4882a593Smuzhiyun 	.dai_names = "Uni Player #0 (HDMI)",
36*4882a593Smuzhiyun 	.type = SND_ST_UNIPERIF_TYPE_HDMI
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun static const struct sti_uniperiph_dev_data sti_uniplayer_pcm_out = {
40*4882a593Smuzhiyun 	.id = 1,
41*4882a593Smuzhiyun 	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
42*4882a593Smuzhiyun 	.stream = SNDRV_PCM_STREAM_PLAYBACK,
43*4882a593Smuzhiyun 	.dai_names = "Uni Player #1 (PCM OUT)",
44*4882a593Smuzhiyun 	.type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM,
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static const struct sti_uniperiph_dev_data sti_uniplayer_dac = {
48*4882a593Smuzhiyun 	.id = 2,
49*4882a593Smuzhiyun 	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
50*4882a593Smuzhiyun 	.stream = SNDRV_PCM_STREAM_PLAYBACK,
51*4882a593Smuzhiyun 	.dai_names = "Uni Player #2 (DAC)",
52*4882a593Smuzhiyun 	.type = SND_ST_UNIPERIF_TYPE_PCM,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static const struct sti_uniperiph_dev_data sti_uniplayer_spdif = {
56*4882a593Smuzhiyun 	.id = 3,
57*4882a593Smuzhiyun 	.version = SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0,
58*4882a593Smuzhiyun 	.stream = SNDRV_PCM_STREAM_PLAYBACK,
59*4882a593Smuzhiyun 	.dai_names = "Uni Player #3 (SPDIF)",
60*4882a593Smuzhiyun 	.type = SND_ST_UNIPERIF_TYPE_SPDIF
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun static const struct sti_uniperiph_dev_data sti_unireader_pcm_in = {
64*4882a593Smuzhiyun 	.id = 0,
65*4882a593Smuzhiyun 	.version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0,
66*4882a593Smuzhiyun 	.stream = SNDRV_PCM_STREAM_CAPTURE,
67*4882a593Smuzhiyun 	.dai_names = "Uni Reader #0 (PCM IN)",
68*4882a593Smuzhiyun 	.type = SND_ST_UNIPERIF_TYPE_PCM | SND_ST_UNIPERIF_TYPE_TDM,
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static const struct sti_uniperiph_dev_data sti_unireader_hdmi_in = {
72*4882a593Smuzhiyun 	.id = 1,
73*4882a593Smuzhiyun 	.version = SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0,
74*4882a593Smuzhiyun 	.stream = SNDRV_PCM_STREAM_CAPTURE,
75*4882a593Smuzhiyun 	.dai_names = "Uni Reader #1 (HDMI IN)",
76*4882a593Smuzhiyun 	.type = SND_ST_UNIPERIF_TYPE_PCM,
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static const struct of_device_id snd_soc_sti_match[] = {
80*4882a593Smuzhiyun 	{ .compatible = "st,stih407-uni-player-hdmi",
81*4882a593Smuzhiyun 	  .data = &sti_uniplayer_hdmi
82*4882a593Smuzhiyun 	},
83*4882a593Smuzhiyun 	{ .compatible = "st,stih407-uni-player-pcm-out",
84*4882a593Smuzhiyun 	  .data = &sti_uniplayer_pcm_out
85*4882a593Smuzhiyun 	},
86*4882a593Smuzhiyun 	{ .compatible = "st,stih407-uni-player-dac",
87*4882a593Smuzhiyun 	  .data = &sti_uniplayer_dac
88*4882a593Smuzhiyun 	},
89*4882a593Smuzhiyun 	{ .compatible = "st,stih407-uni-player-spdif",
90*4882a593Smuzhiyun 	  .data = &sti_uniplayer_spdif
91*4882a593Smuzhiyun 	},
92*4882a593Smuzhiyun 	{ .compatible = "st,stih407-uni-reader-pcm_in",
93*4882a593Smuzhiyun 	  .data = &sti_unireader_pcm_in
94*4882a593Smuzhiyun 	},
95*4882a593Smuzhiyun 	{ .compatible = "st,stih407-uni-reader-hdmi",
96*4882a593Smuzhiyun 	  .data = &sti_unireader_hdmi_in
97*4882a593Smuzhiyun 	},
98*4882a593Smuzhiyun 	{},
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
sti_uniperiph_reset(struct uniperif * uni)101*4882a593Smuzhiyun int  sti_uniperiph_reset(struct uniperif *uni)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	int count = 10;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* Reset uniperipheral uni */
106*4882a593Smuzhiyun 	SET_UNIPERIF_SOFT_RST_SOFT_RST(uni);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	if (uni->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) {
109*4882a593Smuzhiyun 		while (GET_UNIPERIF_SOFT_RST_SOFT_RST(uni) && count) {
110*4882a593Smuzhiyun 			udelay(5);
111*4882a593Smuzhiyun 			count--;
112*4882a593Smuzhiyun 		}
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (!count) {
116*4882a593Smuzhiyun 		dev_err(uni->dev, "Failed to reset uniperif\n");
117*4882a593Smuzhiyun 		return -EIO;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	return 0;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
sti_uniperiph_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)123*4882a593Smuzhiyun int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
124*4882a593Smuzhiyun 			       unsigned int rx_mask, int slots,
125*4882a593Smuzhiyun 			       int slot_width)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
128*4882a593Smuzhiyun 	struct uniperif *uni = priv->dai_data.uni;
129*4882a593Smuzhiyun 	int i, frame_size, avail_slots;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (!UNIPERIF_TYPE_IS_TDM(uni)) {
132*4882a593Smuzhiyun 		dev_err(uni->dev, "cpu dai not in tdm mode\n");
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/* store info in unip context */
137*4882a593Smuzhiyun 	uni->tdm_slot.slots = slots;
138*4882a593Smuzhiyun 	uni->tdm_slot.slot_width = slot_width;
139*4882a593Smuzhiyun 	/* unip is unidirectionnal */
140*4882a593Smuzhiyun 	uni->tdm_slot.mask = (tx_mask != 0) ? tx_mask : rx_mask;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	/* number of available timeslots */
143*4882a593Smuzhiyun 	for (i = 0, avail_slots = 0; i < uni->tdm_slot.slots; i++) {
144*4882a593Smuzhiyun 		if ((uni->tdm_slot.mask >> i) & 0x01)
145*4882a593Smuzhiyun 			avail_slots++;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 	uni->tdm_slot.avail_slots = avail_slots;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	/* frame size in bytes */
150*4882a593Smuzhiyun 	frame_size = uni->tdm_slot.avail_slots * uni->tdm_slot.slot_width / 8;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* check frame size is allowed */
153*4882a593Smuzhiyun 	if ((frame_size > UNIPERIF_MAX_FRAME_SZ) ||
154*4882a593Smuzhiyun 	    (frame_size & ~(int)UNIPERIF_ALLOWED_FRAME_SZ)) {
155*4882a593Smuzhiyun 		dev_err(uni->dev, "frame size not allowed: %d bytes\n",
156*4882a593Smuzhiyun 			frame_size);
157*4882a593Smuzhiyun 		return -EINVAL;
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)163*4882a593Smuzhiyun int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params,
164*4882a593Smuzhiyun 			       struct snd_pcm_hw_rule *rule)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	struct uniperif *uni = rule->private;
167*4882a593Smuzhiyun 	struct snd_interval t;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	t.min = uni->tdm_slot.avail_slots;
170*4882a593Smuzhiyun 	t.max = uni->tdm_slot.avail_slots;
171*4882a593Smuzhiyun 	t.openmin = 0;
172*4882a593Smuzhiyun 	t.openmax = 0;
173*4882a593Smuzhiyun 	t.integer = 0;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun 
sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)178*4882a593Smuzhiyun int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params,
179*4882a593Smuzhiyun 				 struct snd_pcm_hw_rule *rule)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	struct uniperif *uni = rule->private;
182*4882a593Smuzhiyun 	struct snd_mask *maskp = hw_param_mask(params, rule->var);
183*4882a593Smuzhiyun 	u64 format;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	switch (uni->tdm_slot.slot_width) {
186*4882a593Smuzhiyun 	case 16:
187*4882a593Smuzhiyun 		format = SNDRV_PCM_FMTBIT_S16_LE;
188*4882a593Smuzhiyun 		break;
189*4882a593Smuzhiyun 	case 32:
190*4882a593Smuzhiyun 		format = SNDRV_PCM_FMTBIT_S32_LE;
191*4882a593Smuzhiyun 		break;
192*4882a593Smuzhiyun 	default:
193*4882a593Smuzhiyun 		dev_err(uni->dev, "format not supported: %d bits\n",
194*4882a593Smuzhiyun 			uni->tdm_slot.slot_width);
195*4882a593Smuzhiyun 		return -EINVAL;
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	maskp->bits[0] &= (u_int32_t)format;
199*4882a593Smuzhiyun 	maskp->bits[1] &= (u_int32_t)(format >> 32);
200*4882a593Smuzhiyun 	/* clear remaining indexes */
201*4882a593Smuzhiyun 	memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX - 64) / 8);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (!maskp->bits[0] && !maskp->bits[1])
204*4882a593Smuzhiyun 		return -EINVAL;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
sti_uniperiph_get_tdm_word_pos(struct uniperif * uni,unsigned int * word_pos)209*4882a593Smuzhiyun int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni,
210*4882a593Smuzhiyun 				   unsigned int *word_pos)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	int slot_width = uni->tdm_slot.slot_width / 8;
213*4882a593Smuzhiyun 	int slots_num = uni->tdm_slot.slots;
214*4882a593Smuzhiyun 	unsigned int slots_mask = uni->tdm_slot.mask;
215*4882a593Smuzhiyun 	int i, j, k;
216*4882a593Smuzhiyun 	unsigned int word16_pos[4];
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* word16_pos:
219*4882a593Smuzhiyun 	 * word16_pos[0] = WORDX_LSB
220*4882a593Smuzhiyun 	 * word16_pos[1] = WORDX_MSB,
221*4882a593Smuzhiyun 	 * word16_pos[2] = WORDX+1_LSB
222*4882a593Smuzhiyun 	 * word16_pos[3] = WORDX+1_MSB
223*4882a593Smuzhiyun 	 */
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* set unip word position */
226*4882a593Smuzhiyun 	for (i = 0, j = 0, k = 0; (i < slots_num) && (k < WORD_MAX); i++) {
227*4882a593Smuzhiyun 		if ((slots_mask >> i) & 0x01) {
228*4882a593Smuzhiyun 			word16_pos[j] = i * slot_width;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 			if (slot_width == 4) {
231*4882a593Smuzhiyun 				word16_pos[j + 1] = word16_pos[j] + 2;
232*4882a593Smuzhiyun 				j++;
233*4882a593Smuzhiyun 			}
234*4882a593Smuzhiyun 			j++;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 			if (j > 3) {
237*4882a593Smuzhiyun 				word_pos[k] = word16_pos[1] |
238*4882a593Smuzhiyun 					      (word16_pos[0] << 8) |
239*4882a593Smuzhiyun 					      (word16_pos[3] << 16) |
240*4882a593Smuzhiyun 					      (word16_pos[2] << 24);
241*4882a593Smuzhiyun 				j = 0;
242*4882a593Smuzhiyun 				k++;
243*4882a593Smuzhiyun 			}
244*4882a593Smuzhiyun 		}
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	return 0;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun /*
251*4882a593Smuzhiyun  * sti_uniperiph_dai_create_ctrl
252*4882a593Smuzhiyun  * This function is used to create Ctrl associated to DAI but also pcm device.
253*4882a593Smuzhiyun  * Request is done by front end to associate ctrl with pcm device id
254*4882a593Smuzhiyun  */
sti_uniperiph_dai_create_ctrl(struct snd_soc_dai * dai)255*4882a593Smuzhiyun static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
258*4882a593Smuzhiyun 	struct uniperif *uni = priv->dai_data.uni;
259*4882a593Smuzhiyun 	struct snd_kcontrol_new *ctrl;
260*4882a593Smuzhiyun 	int i;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (!uni->num_ctrls)
263*4882a593Smuzhiyun 		return 0;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	for (i = 0; i < uni->num_ctrls; i++) {
266*4882a593Smuzhiyun 		/*
267*4882a593Smuzhiyun 		 * Several Control can have same name. Controls are indexed on
268*4882a593Smuzhiyun 		 * Uniperipheral instance ID
269*4882a593Smuzhiyun 		 */
270*4882a593Smuzhiyun 		ctrl = &uni->snd_ctrls[i];
271*4882a593Smuzhiyun 		ctrl->index = uni->id;
272*4882a593Smuzhiyun 		ctrl->device = uni->id;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun  * DAI
280*4882a593Smuzhiyun  */
sti_uniperiph_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)281*4882a593Smuzhiyun int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream,
282*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
283*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
286*4882a593Smuzhiyun 	struct uniperif *uni = priv->dai_data.uni;
287*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data *dma_data;
288*4882a593Smuzhiyun 	int transfer_size;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (uni->type == SND_ST_UNIPERIF_TYPE_TDM)
291*4882a593Smuzhiyun 		/* transfer size = user frame size (in 32-bits FIFO cell) */
292*4882a593Smuzhiyun 		transfer_size = snd_soc_params_to_frame_size(params) / 32;
293*4882a593Smuzhiyun 	else
294*4882a593Smuzhiyun 		transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
297*4882a593Smuzhiyun 	dma_data->maxburst = transfer_size;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
sti_uniperiph_dai_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)302*4882a593Smuzhiyun int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	priv->dai_data.uni->daifmt = fmt;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return 0;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
sti_uniperiph_suspend(struct snd_soc_component * component)311*4882a593Smuzhiyun static int sti_uniperiph_suspend(struct snd_soc_component *component)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_component_get_drvdata(component);
314*4882a593Smuzhiyun 	struct uniperif *uni = priv->dai_data.uni;
315*4882a593Smuzhiyun 	int ret;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	/* The uniperipheral should be in stopped state */
318*4882a593Smuzhiyun 	if (uni->state != UNIPERIF_STATE_STOPPED) {
319*4882a593Smuzhiyun 		dev_err(uni->dev, "%s: invalid uni state( %d)\n",
320*4882a593Smuzhiyun 			__func__, (int)uni->state);
321*4882a593Smuzhiyun 		return -EBUSY;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/* Pinctrl: switch pinstate to sleep */
325*4882a593Smuzhiyun 	ret = pinctrl_pm_select_sleep_state(uni->dev);
326*4882a593Smuzhiyun 	if (ret)
327*4882a593Smuzhiyun 		dev_err(uni->dev, "%s: failed to select pinctrl state\n",
328*4882a593Smuzhiyun 			__func__);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	return ret;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
sti_uniperiph_resume(struct snd_soc_component * component)333*4882a593Smuzhiyun static int sti_uniperiph_resume(struct snd_soc_component *component)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_component_get_drvdata(component);
336*4882a593Smuzhiyun 	struct uniperif *uni = priv->dai_data.uni;
337*4882a593Smuzhiyun 	int ret;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) {
340*4882a593Smuzhiyun 		ret = uni_player_resume(uni);
341*4882a593Smuzhiyun 		if (ret)
342*4882a593Smuzhiyun 			return ret;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	/* pinctrl: switch pinstate to default */
346*4882a593Smuzhiyun 	ret = pinctrl_pm_select_default_state(uni->dev);
347*4882a593Smuzhiyun 	if (ret)
348*4882a593Smuzhiyun 		dev_err(uni->dev, "%s: failed to select pinctrl state\n",
349*4882a593Smuzhiyun 			__func__);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	return ret;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
sti_uniperiph_dai_probe(struct snd_soc_dai * dai)354*4882a593Smuzhiyun static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
357*4882a593Smuzhiyun 	struct sti_uniperiph_dai *dai_data = &priv->dai_data;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/* DMA settings*/
360*4882a593Smuzhiyun 	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK)
361*4882a593Smuzhiyun 		snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL);
362*4882a593Smuzhiyun 	else
363*4882a593Smuzhiyun 		snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	dai_data->dma_data.addr = dai_data->uni->fifo_phys_address;
366*4882a593Smuzhiyun 	dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	return sti_uniperiph_dai_create_ctrl(dai);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
372*4882a593Smuzhiyun 	.probe = sti_uniperiph_dai_probe,
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
376*4882a593Smuzhiyun 	.name = "sti_cpu_dai",
377*4882a593Smuzhiyun 	.suspend = sti_uniperiph_suspend,
378*4882a593Smuzhiyun 	.resume = sti_uniperiph_resume
379*4882a593Smuzhiyun };
380*4882a593Smuzhiyun 
sti_uniperiph_cpu_dai_of(struct device_node * node,struct sti_uniperiph_data * priv)381*4882a593Smuzhiyun static int sti_uniperiph_cpu_dai_of(struct device_node *node,
382*4882a593Smuzhiyun 				    struct sti_uniperiph_data *priv)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	struct device *dev = &priv->pdev->dev;
385*4882a593Smuzhiyun 	struct sti_uniperiph_dai *dai_data = &priv->dai_data;
386*4882a593Smuzhiyun 	struct snd_soc_dai_driver *dai = priv->dai;
387*4882a593Smuzhiyun 	struct snd_soc_pcm_stream *stream;
388*4882a593Smuzhiyun 	struct uniperif *uni;
389*4882a593Smuzhiyun 	const struct of_device_id *of_id;
390*4882a593Smuzhiyun 	const struct sti_uniperiph_dev_data *dev_data;
391*4882a593Smuzhiyun 	const char *mode;
392*4882a593Smuzhiyun 	int ret;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/* Populate data structure depending on compatibility */
395*4882a593Smuzhiyun 	of_id = of_match_node(snd_soc_sti_match, node);
396*4882a593Smuzhiyun 	if (!of_id->data) {
397*4882a593Smuzhiyun 		dev_err(dev, "data associated to device is missing\n");
398*4882a593Smuzhiyun 		return -EINVAL;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 	dev_data = (struct sti_uniperiph_dev_data *)of_id->data;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL);
403*4882a593Smuzhiyun 	if (!uni)
404*4882a593Smuzhiyun 		return -ENOMEM;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	uni->id = dev_data->id;
407*4882a593Smuzhiyun 	uni->ver = dev_data->version;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	*dai = sti_uniperiph_dai_template;
410*4882a593Smuzhiyun 	dai->name = dev_data->dai_names;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	/* Get resources */
413*4882a593Smuzhiyun 	uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (!uni->mem_region) {
416*4882a593Smuzhiyun 		dev_err(dev, "Failed to get memory resource\n");
417*4882a593Smuzhiyun 		return -ENODEV;
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	uni->base = devm_ioremap_resource(dev, uni->mem_region);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (IS_ERR(uni->base))
423*4882a593Smuzhiyun 		return PTR_ERR(uni->base);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	uni->fifo_phys_address = uni->mem_region->start +
426*4882a593Smuzhiyun 				     UNIPERIF_FIFO_DATA_OFFSET(uni);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	uni->irq = platform_get_irq(priv->pdev, 0);
429*4882a593Smuzhiyun 	if (uni->irq < 0)
430*4882a593Smuzhiyun 		return -ENXIO;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	uni->type = dev_data->type;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	/* check if player should be configured for tdm */
435*4882a593Smuzhiyun 	if (dev_data->type & SND_ST_UNIPERIF_TYPE_TDM) {
436*4882a593Smuzhiyun 		if (!of_property_read_string(node, "st,tdm-mode", &mode))
437*4882a593Smuzhiyun 			uni->type = SND_ST_UNIPERIF_TYPE_TDM;
438*4882a593Smuzhiyun 		else
439*4882a593Smuzhiyun 			uni->type = SND_ST_UNIPERIF_TYPE_PCM;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	dai_data->uni = uni;
443*4882a593Smuzhiyun 	dai_data->stream = dev_data->stream;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) {
446*4882a593Smuzhiyun 		ret = uni_player_init(priv->pdev, uni);
447*4882a593Smuzhiyun 		stream = &dai->playback;
448*4882a593Smuzhiyun 	} else {
449*4882a593Smuzhiyun 		ret = uni_reader_init(priv->pdev, uni);
450*4882a593Smuzhiyun 		stream = &dai->capture;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 	if (ret < 0)
453*4882a593Smuzhiyun 		return ret;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	dai->ops = uni->dai_ops;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	stream->stream_name = dai->name;
458*4882a593Smuzhiyun 	stream->channels_min = uni->hw->channels_min;
459*4882a593Smuzhiyun 	stream->channels_max = uni->hw->channels_max;
460*4882a593Smuzhiyun 	stream->rates = uni->hw->rates;
461*4882a593Smuzhiyun 	stream->formats = uni->hw->formats;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return 0;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = {
467*4882a593Smuzhiyun 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
468*4882a593Smuzhiyun };
469*4882a593Smuzhiyun 
sti_uniperiph_probe(struct platform_device * pdev)470*4882a593Smuzhiyun static int sti_uniperiph_probe(struct platform_device *pdev)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	struct sti_uniperiph_data *priv;
473*4882a593Smuzhiyun 	struct device_node *node = pdev->dev.of_node;
474*4882a593Smuzhiyun 	int ret;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	/* Allocate the private data and the CPU_DAI array */
477*4882a593Smuzhiyun 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
478*4882a593Smuzhiyun 	if (!priv)
479*4882a593Smuzhiyun 		return -ENOMEM;
480*4882a593Smuzhiyun 	priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL);
481*4882a593Smuzhiyun 	if (!priv->dai)
482*4882a593Smuzhiyun 		return -ENOMEM;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	priv->pdev = pdev;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	ret = sti_uniperiph_cpu_dai_of(node, priv);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	dev_set_drvdata(&pdev->dev, priv);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(&pdev->dev,
491*4882a593Smuzhiyun 					      &sti_uniperiph_dai_component,
492*4882a593Smuzhiyun 					      priv->dai, 1);
493*4882a593Smuzhiyun 	if (ret < 0)
494*4882a593Smuzhiyun 		return ret;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	return devm_snd_dmaengine_pcm_register(&pdev->dev,
497*4882a593Smuzhiyun 					       &dmaengine_pcm_config, 0);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun static struct platform_driver sti_uniperiph_driver = {
501*4882a593Smuzhiyun 	.driver = {
502*4882a593Smuzhiyun 		.name = "sti-uniperiph-dai",
503*4882a593Smuzhiyun 		.of_match_table = snd_soc_sti_match,
504*4882a593Smuzhiyun 	},
505*4882a593Smuzhiyun 	.probe = sti_uniperiph_probe,
506*4882a593Smuzhiyun };
507*4882a593Smuzhiyun module_platform_driver(sti_uniperiph_driver);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun MODULE_DESCRIPTION("uniperipheral DAI driver");
510*4882a593Smuzhiyun MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
511*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
512