Lines Matching +full:dmic +full:- +full:freq
1 // SPDX-License-Identifier: GPL-2.0-only
3 * omap-dmic.c -- OMAP ASoC DMIC DAI driver
5 * Copyright (C) 2010 - 2011 Texas Instruments
30 #include "omap-dmic.h"
31 #include "sdma-pcm.h"
51 static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val) in omap_dmic_write() argument
53 writel_relaxed(val, dmic->io_base + reg); in omap_dmic_write()
56 static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg) in omap_dmic_read() argument
58 return readl_relaxed(dmic->io_base + reg); in omap_dmic_read()
61 static inline void omap_dmic_start(struct omap_dmic *dmic) in omap_dmic_start() argument
63 u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); in omap_dmic_start()
66 omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG, in omap_dmic_start()
69 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled); in omap_dmic_start()
72 static inline void omap_dmic_stop(struct omap_dmic *dmic) in omap_dmic_stop() argument
74 u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); in omap_dmic_stop()
75 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, in omap_dmic_stop()
79 omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG, in omap_dmic_stop()
84 static inline int dmic_is_enabled(struct omap_dmic *dmic) in dmic_is_enabled() argument
86 return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) & in dmic_is_enabled()
93 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_dai_startup() local
96 mutex_lock(&dmic->mutex); in omap_dmic_dai_startup()
99 dmic->active = 1; in omap_dmic_dai_startup()
101 ret = -EBUSY; in omap_dmic_dai_startup()
103 mutex_unlock(&dmic->mutex); in omap_dmic_dai_startup()
111 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_dai_shutdown() local
113 mutex_lock(&dmic->mutex); in omap_dmic_dai_shutdown()
115 cpu_latency_qos_remove_request(&dmic->pm_qos_req); in omap_dmic_dai_shutdown()
118 dmic->active = 0; in omap_dmic_dai_shutdown()
120 mutex_unlock(&dmic->mutex); in omap_dmic_dai_shutdown()
123 static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate) in omap_dmic_select_divider() argument
125 int divider = -EINVAL; in omap_dmic_select_divider()
132 if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000) in omap_dmic_select_divider()
135 dev_err(dmic->dev, in omap_dmic_select_divider()
141 switch (dmic->out_freq) { in omap_dmic_select_divider()
143 if (dmic->fclk_freq != 24576000) in omap_dmic_select_divider()
148 switch (dmic->fclk_freq) { in omap_dmic_select_divider()
163 if (dmic->fclk_freq != 24576000) in omap_dmic_select_divider()
168 if (dmic->fclk_freq != 19200000) in omap_dmic_select_divider()
173 dev_err(dmic->dev, "invalid out frequency: %dHz\n", in omap_dmic_select_divider()
174 dmic->out_freq); in omap_dmic_select_divider()
181 dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n", in omap_dmic_select_divider()
182 dmic->out_freq, dmic->fclk_freq); in omap_dmic_select_divider()
183 return -EINVAL; in omap_dmic_select_divider()
190 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_dai_hw_params() local
194 dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params)); in omap_dmic_dai_hw_params()
195 if (dmic->clk_div < 0) { in omap_dmic_dai_hw_params()
196 dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n", in omap_dmic_dai_hw_params()
197 dmic->out_freq, dmic->fclk_freq); in omap_dmic_dai_hw_params()
198 return -EINVAL; in omap_dmic_dai_hw_params()
201 dmic->ch_enabled = 0; in omap_dmic_dai_hw_params()
205 dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE; in omap_dmic_dai_hw_params()
208 dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE; in omap_dmic_dai_hw_params()
211 dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE; in omap_dmic_dai_hw_params()
214 dev_err(dmic->dev, "invalid number of legacy channels\n"); in omap_dmic_dai_hw_params()
215 return -EINVAL; in omap_dmic_dai_hw_params()
220 dma_data->maxburst = dmic->threshold * channels; in omap_dmic_dai_hw_params()
221 dmic->latency = (OMAP_DMIC_THRES_MAX - dmic->threshold) * USEC_PER_SEC / in omap_dmic_dai_hw_params()
230 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_dai_prepare() local
233 if (cpu_latency_qos_request_active(&dmic->pm_qos_req)) in omap_dmic_dai_prepare()
234 cpu_latency_qos_update_request(&dmic->pm_qos_req, in omap_dmic_dai_prepare()
235 dmic->latency); in omap_dmic_dai_prepare()
238 omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold); in omap_dmic_dai_prepare()
240 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG); in omap_dmic_dai_prepare()
242 /* Set dmic out format */ in omap_dmic_dai_prepare()
247 /* Configure dmic clock divider */ in omap_dmic_dai_prepare()
249 ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div); in omap_dmic_dai_prepare()
251 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl); in omap_dmic_dai_prepare()
253 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, in omap_dmic_dai_prepare()
263 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_dai_trigger() local
267 omap_dmic_start(dmic); in omap_dmic_dai_trigger()
270 omap_dmic_stop(dmic); in omap_dmic_dai_trigger()
279 static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id, in omap_dmic_select_fclk() argument
280 unsigned int freq) in omap_dmic_select_fclk() argument
286 switch (freq) { in omap_dmic_select_fclk()
293 dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq); in omap_dmic_select_fclk()
294 dmic->fclk_freq = 0; in omap_dmic_select_fclk()
295 return -EINVAL; in omap_dmic_select_fclk()
298 if (dmic->sysclk == clk_id) { in omap_dmic_select_fclk()
299 dmic->fclk_freq = freq; in omap_dmic_select_fclk()
303 /* re-parent not allowed if a stream is ongoing */ in omap_dmic_select_fclk()
304 if (dmic->active && dmic_is_enabled(dmic)) { in omap_dmic_select_fclk()
305 dev_err(dmic->dev, "can't re-parent when DMIC active\n"); in omap_dmic_select_fclk()
306 return -EBUSY; in omap_dmic_select_fclk()
320 dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id); in omap_dmic_select_fclk()
321 return -EINVAL; in omap_dmic_select_fclk()
324 parent_clk = clk_get(dmic->dev, parent_clk_name); in omap_dmic_select_fclk()
326 dev_err(dmic->dev, "can't get %s\n", parent_clk_name); in omap_dmic_select_fclk()
327 return -ENODEV; in omap_dmic_select_fclk()
330 mux = clk_get_parent(dmic->fclk); in omap_dmic_select_fclk()
332 dev_err(dmic->dev, "can't get fck mux parent\n"); in omap_dmic_select_fclk()
334 return -ENODEV; in omap_dmic_select_fclk()
337 mutex_lock(&dmic->mutex); in omap_dmic_select_fclk()
338 if (dmic->active) { in omap_dmic_select_fclk()
340 pm_runtime_put_sync(dmic->dev); in omap_dmic_select_fclk()
342 pm_runtime_get_sync(dmic->dev); in omap_dmic_select_fclk()
346 mutex_unlock(&dmic->mutex); in omap_dmic_select_fclk()
349 dev_err(dmic->dev, "re-parent failed\n"); in omap_dmic_select_fclk()
353 dmic->sysclk = clk_id; in omap_dmic_select_fclk()
354 dmic->fclk_freq = freq; in omap_dmic_select_fclk()
363 static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id, in omap_dmic_select_outclk() argument
364 unsigned int freq) in omap_dmic_select_outclk() argument
369 dev_err(dmic->dev, "output clk_id (%d) not supported\n", in omap_dmic_select_outclk()
371 return -EINVAL; in omap_dmic_select_outclk()
374 switch (freq) { in omap_dmic_select_outclk()
379 dmic->out_freq = freq; in omap_dmic_select_outclk()
382 dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq); in omap_dmic_select_outclk()
383 dmic->out_freq = 0; in omap_dmic_select_outclk()
384 ret = -EINVAL; in omap_dmic_select_outclk()
391 unsigned int freq, int dir) in omap_dmic_set_dai_sysclk() argument
393 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_set_dai_sysclk() local
396 return omap_dmic_select_fclk(dmic, clk_id, freq); in omap_dmic_set_dai_sysclk()
398 return omap_dmic_select_outclk(dmic, clk_id, freq); in omap_dmic_set_dai_sysclk()
400 dev_err(dmic->dev, "invalid clock direction (%d)\n", dir); in omap_dmic_set_dai_sysclk()
401 return -EINVAL; in omap_dmic_set_dai_sysclk()
406 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_probe() local
408 pm_runtime_enable(dmic->dev); in omap_dmic_probe()
411 pm_runtime_get_sync(dmic->dev); in omap_dmic_probe()
412 omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00); in omap_dmic_probe()
413 pm_runtime_put_sync(dmic->dev); in omap_dmic_probe()
415 /* Configure DMIC threshold value */ in omap_dmic_probe()
416 dmic->threshold = OMAP_DMIC_THRES_MAX - 3; in omap_dmic_probe()
418 snd_soc_dai_init_dma_data(dai, NULL, &dmic->dma_data); in omap_dmic_probe()
425 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); in omap_dmic_remove() local
427 pm_runtime_disable(dmic->dev); in omap_dmic_remove()
444 .name = "omap-dmic",
456 .name = "omap-dmic",
462 struct omap_dmic *dmic; in asoc_dmic_probe() local
466 dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL); in asoc_dmic_probe()
467 if (!dmic) in asoc_dmic_probe()
468 return -ENOMEM; in asoc_dmic_probe()
470 platform_set_drvdata(pdev, dmic); in asoc_dmic_probe()
471 dmic->dev = &pdev->dev; in asoc_dmic_probe()
472 dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS; in asoc_dmic_probe()
474 mutex_init(&dmic->mutex); in asoc_dmic_probe()
476 dmic->fclk = devm_clk_get(dmic->dev, "fck"); in asoc_dmic_probe()
477 if (IS_ERR(dmic->fclk)) { in asoc_dmic_probe()
478 dev_err(dmic->dev, "can't get fck\n"); in asoc_dmic_probe()
479 return -ENODEV; in asoc_dmic_probe()
484 dev_err(dmic->dev, "invalid dma memory resource\n"); in asoc_dmic_probe()
485 return -ENODEV; in asoc_dmic_probe()
487 dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG; in asoc_dmic_probe()
489 dmic->dma_data.filter_data = "up_link"; in asoc_dmic_probe()
491 dmic->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); in asoc_dmic_probe()
492 if (IS_ERR(dmic->io_base)) in asoc_dmic_probe()
493 return PTR_ERR(dmic->io_base); in asoc_dmic_probe()
495 ret = devm_snd_soc_register_component(&pdev->dev, in asoc_dmic_probe()
501 ret = sdma_pcm_platform_register(&pdev->dev, NULL, "up_link"); in asoc_dmic_probe()
509 { .compatible = "ti,omap4-dmic", },
516 .name = "omap-dmic",
524 MODULE_ALIAS("platform:omap-dmic");
526 MODULE_DESCRIPTION("OMAP DMIC ASoC Interface");