xref: /OK3568_Linux_fs/kernel/sound/soc/ti/omap-dmic.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * omap-dmic.c  --  OMAP ASoC DMIC DAI driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010 - 2011 Texas Instruments
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: David Lambert <dlambert@ti.com>
8*4882a593Smuzhiyun  *	   Misael Lopez Cruz <misael.lopez@ti.com>
9*4882a593Smuzhiyun  *	   Liam Girdwood <lrg@ti.com>
10*4882a593Smuzhiyun  *	   Peter Ujfalusi <peter.ujfalusi@ti.com>
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/err.h>
17*4882a593Smuzhiyun #include <linux/clk.h>
18*4882a593Smuzhiyun #include <linux/io.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/pm_runtime.h>
21*4882a593Smuzhiyun #include <linux/of_device.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include <sound/core.h>
24*4882a593Smuzhiyun #include <sound/pcm.h>
25*4882a593Smuzhiyun #include <sound/pcm_params.h>
26*4882a593Smuzhiyun #include <sound/initval.h>
27*4882a593Smuzhiyun #include <sound/soc.h>
28*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include "omap-dmic.h"
31*4882a593Smuzhiyun #include "sdma-pcm.h"
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun struct omap_dmic {
34*4882a593Smuzhiyun 	struct device *dev;
35*4882a593Smuzhiyun 	void __iomem *io_base;
36*4882a593Smuzhiyun 	struct clk *fclk;
37*4882a593Smuzhiyun 	struct pm_qos_request pm_qos_req;
38*4882a593Smuzhiyun 	int latency;
39*4882a593Smuzhiyun 	int fclk_freq;
40*4882a593Smuzhiyun 	int out_freq;
41*4882a593Smuzhiyun 	int clk_div;
42*4882a593Smuzhiyun 	int sysclk;
43*4882a593Smuzhiyun 	int threshold;
44*4882a593Smuzhiyun 	u32 ch_enabled;
45*4882a593Smuzhiyun 	bool active;
46*4882a593Smuzhiyun 	struct mutex mutex;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data dma_data;
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
omap_dmic_write(struct omap_dmic * dmic,u16 reg,u32 val)51*4882a593Smuzhiyun static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	writel_relaxed(val, dmic->io_base + reg);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
omap_dmic_read(struct omap_dmic * dmic,u16 reg)56*4882a593Smuzhiyun static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	return readl_relaxed(dmic->io_base + reg);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
omap_dmic_start(struct omap_dmic * dmic)61*4882a593Smuzhiyun static inline void omap_dmic_start(struct omap_dmic *dmic)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	/* Configure DMA controller */
66*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG,
67*4882a593Smuzhiyun 			OMAP_DMIC_DMA_ENABLE);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
omap_dmic_stop(struct omap_dmic * dmic)72*4882a593Smuzhiyun static inline void omap_dmic_stop(struct omap_dmic *dmic)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
75*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
76*4882a593Smuzhiyun 			ctrl & ~OMAP_DMIC_UP_ENABLE_MASK);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* Disable DMA request generation */
79*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG,
80*4882a593Smuzhiyun 			OMAP_DMIC_DMA_ENABLE);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
dmic_is_enabled(struct omap_dmic * dmic)84*4882a593Smuzhiyun static inline int dmic_is_enabled(struct omap_dmic *dmic)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) &
87*4882a593Smuzhiyun 						OMAP_DMIC_UP_ENABLE_MASK;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
omap_dmic_dai_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)90*4882a593Smuzhiyun static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
91*4882a593Smuzhiyun 				  struct snd_soc_dai *dai)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
94*4882a593Smuzhiyun 	int ret = 0;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	mutex_lock(&dmic->mutex);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (!snd_soc_dai_active(dai))
99*4882a593Smuzhiyun 		dmic->active = 1;
100*4882a593Smuzhiyun 	else
101*4882a593Smuzhiyun 		ret = -EBUSY;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	mutex_unlock(&dmic->mutex);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	return ret;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
omap_dmic_dai_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)108*4882a593Smuzhiyun static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream,
109*4882a593Smuzhiyun 				    struct snd_soc_dai *dai)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	mutex_lock(&dmic->mutex);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	cpu_latency_qos_remove_request(&dmic->pm_qos_req);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (!snd_soc_dai_active(dai))
118*4882a593Smuzhiyun 		dmic->active = 0;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	mutex_unlock(&dmic->mutex);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
omap_dmic_select_divider(struct omap_dmic * dmic,int sample_rate)123*4882a593Smuzhiyun static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	int divider = -EINVAL;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/*
128*4882a593Smuzhiyun 	 * 192KHz rate is only supported with 19.2MHz/3.84MHz clock
129*4882a593Smuzhiyun 	 * configuration.
130*4882a593Smuzhiyun 	 */
131*4882a593Smuzhiyun 	if (sample_rate == 192000) {
132*4882a593Smuzhiyun 		if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000)
133*4882a593Smuzhiyun 			divider = 0x6; /* Divider: 5 (192KHz sampling rate) */
134*4882a593Smuzhiyun 		else
135*4882a593Smuzhiyun 			dev_err(dmic->dev,
136*4882a593Smuzhiyun 				"invalid clock configuration for 192KHz\n");
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		return divider;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	switch (dmic->out_freq) {
142*4882a593Smuzhiyun 	case 1536000:
143*4882a593Smuzhiyun 		if (dmic->fclk_freq != 24576000)
144*4882a593Smuzhiyun 			goto div_err;
145*4882a593Smuzhiyun 		divider = 0x4; /* Divider: 16 */
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 	case 2400000:
148*4882a593Smuzhiyun 		switch (dmic->fclk_freq) {
149*4882a593Smuzhiyun 		case 12000000:
150*4882a593Smuzhiyun 			divider = 0x5; /* Divider: 5 */
151*4882a593Smuzhiyun 			break;
152*4882a593Smuzhiyun 		case 19200000:
153*4882a593Smuzhiyun 			divider = 0x0; /* Divider: 8 */
154*4882a593Smuzhiyun 			break;
155*4882a593Smuzhiyun 		case 24000000:
156*4882a593Smuzhiyun 			divider = 0x2; /* Divider: 10 */
157*4882a593Smuzhiyun 			break;
158*4882a593Smuzhiyun 		default:
159*4882a593Smuzhiyun 			goto div_err;
160*4882a593Smuzhiyun 		}
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	case 3072000:
163*4882a593Smuzhiyun 		if (dmic->fclk_freq != 24576000)
164*4882a593Smuzhiyun 			goto div_err;
165*4882a593Smuzhiyun 		divider = 0x3; /* Divider: 8 */
166*4882a593Smuzhiyun 		break;
167*4882a593Smuzhiyun 	case 3840000:
168*4882a593Smuzhiyun 		if (dmic->fclk_freq != 19200000)
169*4882a593Smuzhiyun 			goto div_err;
170*4882a593Smuzhiyun 		divider = 0x1; /* Divider: 5 (96KHz sampling rate) */
171*4882a593Smuzhiyun 		break;
172*4882a593Smuzhiyun 	default:
173*4882a593Smuzhiyun 		dev_err(dmic->dev, "invalid out frequency: %dHz\n",
174*4882a593Smuzhiyun 			dmic->out_freq);
175*4882a593Smuzhiyun 		break;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	return divider;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun div_err:
181*4882a593Smuzhiyun 	dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n",
182*4882a593Smuzhiyun 		dmic->out_freq, dmic->fclk_freq);
183*4882a593Smuzhiyun 	return -EINVAL;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
omap_dmic_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)186*4882a593Smuzhiyun static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
187*4882a593Smuzhiyun 				    struct snd_pcm_hw_params *params,
188*4882a593Smuzhiyun 				    struct snd_soc_dai *dai)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
191*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data *dma_data;
192*4882a593Smuzhiyun 	int channels;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
195*4882a593Smuzhiyun 	if (dmic->clk_div < 0) {
196*4882a593Smuzhiyun 		dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n",
197*4882a593Smuzhiyun 			dmic->out_freq, dmic->fclk_freq);
198*4882a593Smuzhiyun 		return -EINVAL;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	dmic->ch_enabled = 0;
202*4882a593Smuzhiyun 	channels = params_channels(params);
203*4882a593Smuzhiyun 	switch (channels) {
204*4882a593Smuzhiyun 	case 6:
205*4882a593Smuzhiyun 		dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
206*4882a593Smuzhiyun 		fallthrough;
207*4882a593Smuzhiyun 	case 4:
208*4882a593Smuzhiyun 		dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
209*4882a593Smuzhiyun 		fallthrough;
210*4882a593Smuzhiyun 	case 2:
211*4882a593Smuzhiyun 		dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
212*4882a593Smuzhiyun 		break;
213*4882a593Smuzhiyun 	default:
214*4882a593Smuzhiyun 		dev_err(dmic->dev, "invalid number of legacy channels\n");
215*4882a593Smuzhiyun 		return -EINVAL;
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* packet size is threshold * channels */
219*4882a593Smuzhiyun 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
220*4882a593Smuzhiyun 	dma_data->maxburst = dmic->threshold * channels;
221*4882a593Smuzhiyun 	dmic->latency = (OMAP_DMIC_THRES_MAX - dmic->threshold) * USEC_PER_SEC /
222*4882a593Smuzhiyun 			params_rate(params);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
omap_dmic_dai_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)227*4882a593Smuzhiyun static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream,
228*4882a593Smuzhiyun 				  struct snd_soc_dai *dai)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
231*4882a593Smuzhiyun 	u32 ctrl;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	if (cpu_latency_qos_request_active(&dmic->pm_qos_req))
234*4882a593Smuzhiyun 		cpu_latency_qos_update_request(&dmic->pm_qos_req,
235*4882a593Smuzhiyun 					       dmic->latency);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* Configure uplink threshold */
238*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	/* Set dmic out format */
243*4882a593Smuzhiyun 	ctrl &= ~(OMAP_DMIC_FORMAT | OMAP_DMIC_POLAR_MASK);
244*4882a593Smuzhiyun 	ctrl |= (OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
245*4882a593Smuzhiyun 		 OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* Configure dmic clock divider */
248*4882a593Smuzhiyun 	ctrl &= ~OMAP_DMIC_CLK_DIV_MASK;
249*4882a593Smuzhiyun 	ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
254*4882a593Smuzhiyun 			ctrl | OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
255*4882a593Smuzhiyun 			OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
omap_dmic_dai_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)260*4882a593Smuzhiyun static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream,
261*4882a593Smuzhiyun 				  int cmd, struct snd_soc_dai *dai)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	switch (cmd) {
266*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
267*4882a593Smuzhiyun 		omap_dmic_start(dmic);
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
270*4882a593Smuzhiyun 		omap_dmic_stop(dmic);
271*4882a593Smuzhiyun 		break;
272*4882a593Smuzhiyun 	default:
273*4882a593Smuzhiyun 		break;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return 0;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
omap_dmic_select_fclk(struct omap_dmic * dmic,int clk_id,unsigned int freq)279*4882a593Smuzhiyun static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id,
280*4882a593Smuzhiyun 				 unsigned int freq)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	struct clk *parent_clk, *mux;
283*4882a593Smuzhiyun 	char *parent_clk_name;
284*4882a593Smuzhiyun 	int ret = 0;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	switch (freq) {
287*4882a593Smuzhiyun 	case 12000000:
288*4882a593Smuzhiyun 	case 19200000:
289*4882a593Smuzhiyun 	case 24000000:
290*4882a593Smuzhiyun 	case 24576000:
291*4882a593Smuzhiyun 		break;
292*4882a593Smuzhiyun 	default:
293*4882a593Smuzhiyun 		dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq);
294*4882a593Smuzhiyun 		dmic->fclk_freq = 0;
295*4882a593Smuzhiyun 		return -EINVAL;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (dmic->sysclk == clk_id) {
299*4882a593Smuzhiyun 		dmic->fclk_freq = freq;
300*4882a593Smuzhiyun 		return 0;
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	/* re-parent not allowed if a stream is ongoing */
304*4882a593Smuzhiyun 	if (dmic->active && dmic_is_enabled(dmic)) {
305*4882a593Smuzhiyun 		dev_err(dmic->dev, "can't re-parent when DMIC active\n");
306*4882a593Smuzhiyun 		return -EBUSY;
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	switch (clk_id) {
310*4882a593Smuzhiyun 	case OMAP_DMIC_SYSCLK_PAD_CLKS:
311*4882a593Smuzhiyun 		parent_clk_name = "pad_clks_ck";
312*4882a593Smuzhiyun 		break;
313*4882a593Smuzhiyun 	case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS:
314*4882a593Smuzhiyun 		parent_clk_name = "slimbus_clk";
315*4882a593Smuzhiyun 		break;
316*4882a593Smuzhiyun 	case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS:
317*4882a593Smuzhiyun 		parent_clk_name = "dmic_sync_mux_ck";
318*4882a593Smuzhiyun 		break;
319*4882a593Smuzhiyun 	default:
320*4882a593Smuzhiyun 		dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id);
321*4882a593Smuzhiyun 		return -EINVAL;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	parent_clk = clk_get(dmic->dev, parent_clk_name);
325*4882a593Smuzhiyun 	if (IS_ERR(parent_clk)) {
326*4882a593Smuzhiyun 		dev_err(dmic->dev, "can't get %s\n", parent_clk_name);
327*4882a593Smuzhiyun 		return -ENODEV;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	mux = clk_get_parent(dmic->fclk);
331*4882a593Smuzhiyun 	if (IS_ERR(mux)) {
332*4882a593Smuzhiyun 		dev_err(dmic->dev, "can't get fck mux parent\n");
333*4882a593Smuzhiyun 		clk_put(parent_clk);
334*4882a593Smuzhiyun 		return -ENODEV;
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	mutex_lock(&dmic->mutex);
338*4882a593Smuzhiyun 	if (dmic->active) {
339*4882a593Smuzhiyun 		/* disable clock while reparenting */
340*4882a593Smuzhiyun 		pm_runtime_put_sync(dmic->dev);
341*4882a593Smuzhiyun 		ret = clk_set_parent(mux, parent_clk);
342*4882a593Smuzhiyun 		pm_runtime_get_sync(dmic->dev);
343*4882a593Smuzhiyun 	} else {
344*4882a593Smuzhiyun 		ret = clk_set_parent(mux, parent_clk);
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 	mutex_unlock(&dmic->mutex);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (ret < 0) {
349*4882a593Smuzhiyun 		dev_err(dmic->dev, "re-parent failed\n");
350*4882a593Smuzhiyun 		goto err_busy;
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	dmic->sysclk = clk_id;
354*4882a593Smuzhiyun 	dmic->fclk_freq = freq;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun err_busy:
357*4882a593Smuzhiyun 	clk_put(mux);
358*4882a593Smuzhiyun 	clk_put(parent_clk);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	return ret;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
omap_dmic_select_outclk(struct omap_dmic * dmic,int clk_id,unsigned int freq)363*4882a593Smuzhiyun static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id,
364*4882a593Smuzhiyun 				    unsigned int freq)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	int ret = 0;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (clk_id != OMAP_DMIC_ABE_DMIC_CLK) {
369*4882a593Smuzhiyun 		dev_err(dmic->dev, "output clk_id (%d) not supported\n",
370*4882a593Smuzhiyun 			clk_id);
371*4882a593Smuzhiyun 		return -EINVAL;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	switch (freq) {
375*4882a593Smuzhiyun 	case 1536000:
376*4882a593Smuzhiyun 	case 2400000:
377*4882a593Smuzhiyun 	case 3072000:
378*4882a593Smuzhiyun 	case 3840000:
379*4882a593Smuzhiyun 		dmic->out_freq = freq;
380*4882a593Smuzhiyun 		break;
381*4882a593Smuzhiyun 	default:
382*4882a593Smuzhiyun 		dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq);
383*4882a593Smuzhiyun 		dmic->out_freq = 0;
384*4882a593Smuzhiyun 		ret = -EINVAL;
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	return ret;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
omap_dmic_set_dai_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)390*4882a593Smuzhiyun static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
391*4882a593Smuzhiyun 				    unsigned int freq, int dir)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (dir == SND_SOC_CLOCK_IN)
396*4882a593Smuzhiyun 		return omap_dmic_select_fclk(dmic, clk_id, freq);
397*4882a593Smuzhiyun 	else if (dir == SND_SOC_CLOCK_OUT)
398*4882a593Smuzhiyun 		return omap_dmic_select_outclk(dmic, clk_id, freq);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	dev_err(dmic->dev, "invalid clock direction (%d)\n", dir);
401*4882a593Smuzhiyun 	return -EINVAL;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
405*4882a593Smuzhiyun 	.startup	= omap_dmic_dai_startup,
406*4882a593Smuzhiyun 	.shutdown	= omap_dmic_dai_shutdown,
407*4882a593Smuzhiyun 	.hw_params	= omap_dmic_dai_hw_params,
408*4882a593Smuzhiyun 	.prepare	= omap_dmic_dai_prepare,
409*4882a593Smuzhiyun 	.trigger	= omap_dmic_dai_trigger,
410*4882a593Smuzhiyun 	.set_sysclk	= omap_dmic_set_dai_sysclk,
411*4882a593Smuzhiyun };
412*4882a593Smuzhiyun 
omap_dmic_probe(struct snd_soc_dai * dai)413*4882a593Smuzhiyun static int omap_dmic_probe(struct snd_soc_dai *dai)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	pm_runtime_enable(dmic->dev);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	/* Disable lines while request is ongoing */
420*4882a593Smuzhiyun 	pm_runtime_get_sync(dmic->dev);
421*4882a593Smuzhiyun 	omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00);
422*4882a593Smuzhiyun 	pm_runtime_put_sync(dmic->dev);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* Configure DMIC threshold value */
425*4882a593Smuzhiyun 	dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
omap_dmic_remove(struct snd_soc_dai * dai)432*4882a593Smuzhiyun static int omap_dmic_remove(struct snd_soc_dai *dai)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	pm_runtime_disable(dmic->dev);
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	return 0;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun static struct snd_soc_dai_driver omap_dmic_dai = {
442*4882a593Smuzhiyun 	.name = "omap-dmic",
443*4882a593Smuzhiyun 	.probe = omap_dmic_probe,
444*4882a593Smuzhiyun 	.remove = omap_dmic_remove,
445*4882a593Smuzhiyun 	.capture = {
446*4882a593Smuzhiyun 		.channels_min = 2,
447*4882a593Smuzhiyun 		.channels_max = 6,
448*4882a593Smuzhiyun 		.rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
449*4882a593Smuzhiyun 		.formats = SNDRV_PCM_FMTBIT_S32_LE,
450*4882a593Smuzhiyun 		.sig_bits = 24,
451*4882a593Smuzhiyun 	},
452*4882a593Smuzhiyun 	.ops = &omap_dmic_dai_ops,
453*4882a593Smuzhiyun };
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun static const struct snd_soc_component_driver omap_dmic_component = {
456*4882a593Smuzhiyun 	.name		= "omap-dmic",
457*4882a593Smuzhiyun };
458*4882a593Smuzhiyun 
asoc_dmic_probe(struct platform_device * pdev)459*4882a593Smuzhiyun static int asoc_dmic_probe(struct platform_device *pdev)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	struct omap_dmic *dmic;
462*4882a593Smuzhiyun 	struct resource *res;
463*4882a593Smuzhiyun 	int ret;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL);
466*4882a593Smuzhiyun 	if (!dmic)
467*4882a593Smuzhiyun 		return -ENOMEM;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	platform_set_drvdata(pdev, dmic);
470*4882a593Smuzhiyun 	dmic->dev = &pdev->dev;
471*4882a593Smuzhiyun 	dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	mutex_init(&dmic->mutex);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	dmic->fclk = devm_clk_get(dmic->dev, "fck");
476*4882a593Smuzhiyun 	if (IS_ERR(dmic->fclk)) {
477*4882a593Smuzhiyun 		dev_err(dmic->dev, "cant get fck\n");
478*4882a593Smuzhiyun 		return -ENODEV;
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
482*4882a593Smuzhiyun 	if (!res) {
483*4882a593Smuzhiyun 		dev_err(dmic->dev, "invalid dma memory resource\n");
484*4882a593Smuzhiyun 		return -ENODEV;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	dmic->dma_data.filter_data = "up_link";
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
491*4882a593Smuzhiyun 	dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
492*4882a593Smuzhiyun 	if (IS_ERR(dmic->io_base))
493*4882a593Smuzhiyun 		return PTR_ERR(dmic->io_base);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(&pdev->dev,
497*4882a593Smuzhiyun 					      &omap_dmic_component,
498*4882a593Smuzhiyun 					      &omap_dmic_dai, 1);
499*4882a593Smuzhiyun 	if (ret)
500*4882a593Smuzhiyun 		return ret;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link");
503*4882a593Smuzhiyun 	if (ret)
504*4882a593Smuzhiyun 		return ret;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	return 0;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun static const struct of_device_id omap_dmic_of_match[] = {
510*4882a593Smuzhiyun 	{ .compatible = "ti,omap4-dmic", },
511*4882a593Smuzhiyun 	{ }
512*4882a593Smuzhiyun };
513*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, omap_dmic_of_match);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun static struct platform_driver asoc_dmic_driver = {
516*4882a593Smuzhiyun 	.driver = {
517*4882a593Smuzhiyun 		.name = "omap-dmic",
518*4882a593Smuzhiyun 		.of_match_table = omap_dmic_of_match,
519*4882a593Smuzhiyun 	},
520*4882a593Smuzhiyun 	.probe = asoc_dmic_probe,
521*4882a593Smuzhiyun };
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun module_platform_driver(asoc_dmic_driver);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun MODULE_ALIAS("platform:omap-dmic");
526*4882a593Smuzhiyun MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
527*4882a593Smuzhiyun MODULE_DESCRIPTION("OMAP DMIC ASoC Interface");
528*4882a593Smuzhiyun MODULE_LICENSE("GPL");
529