.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* sound/soc/rockchip/rockchip_i2s.c |
---|
2 | 3 | * |
---|
3 | 4 | * ALSA SoC Audio Layer - Rockchip I2S Controller driver |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (c) 2014 Rockchip Electronics Co. Ltd. |
---|
6 | 7 | * Author: Jianqun <jay.xu@rock-chips.com> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/module.h> |
---|
.. | .. |
---|
19 | 16 | #include <linux/clk/rockchip.h> |
---|
20 | 17 | #include <linux/pm_runtime.h> |
---|
21 | 18 | #include <linux/regmap.h> |
---|
22 | | -#include <linux/reset.h> |
---|
23 | 19 | #include <linux/spinlock.h> |
---|
24 | 20 | #include <sound/pcm_params.h> |
---|
25 | 21 | #include <sound/dmaengine_pcm.h> |
---|
26 | 22 | |
---|
27 | 23 | #include "rockchip_i2s.h" |
---|
| 24 | +#include "rockchip_dlp_pcm.h" |
---|
| 25 | +#include "rockchip_utils.h" |
---|
28 | 26 | |
---|
29 | 27 | #define DRV_NAME "rockchip-i2s" |
---|
30 | 28 | |
---|
31 | 29 | #define CLK_PPM_MIN (-1000) |
---|
32 | 30 | #define CLK_PPM_MAX (1000) |
---|
| 31 | + |
---|
| 32 | +#define DEFAULT_MCLK_FS 256 |
---|
| 33 | +#define DEFAULT_FS 48000 |
---|
| 34 | + |
---|
| 35 | +#define WAIT_TIME_MS_MAX 10000 |
---|
| 36 | + |
---|
| 37 | +#define QUIRK_ALWAYS_ON BIT(0) |
---|
33 | 38 | |
---|
34 | 39 | struct rk_i2s_pins { |
---|
35 | 40 | u32 reg_offset; |
---|
.. | .. |
---|
48 | 53 | |
---|
49 | 54 | struct regmap *regmap; |
---|
50 | 55 | struct regmap *grf; |
---|
51 | | - struct reset_control *reset_m; |
---|
52 | | - struct reset_control *reset_h; |
---|
| 56 | + |
---|
| 57 | + struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1]; |
---|
| 58 | + unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1]; |
---|
| 59 | + |
---|
| 60 | + bool has_capture; |
---|
| 61 | + bool has_playback; |
---|
53 | 62 | |
---|
54 | 63 | /* |
---|
55 | 64 | * Used to indicate the tx/rx status. |
---|
.. | .. |
---|
60 | 69 | bool rx_start; |
---|
61 | 70 | bool is_master_mode; |
---|
62 | 71 | const struct rk_i2s_pins *pins; |
---|
63 | | - unsigned int bclk_fs; |
---|
| 72 | + unsigned int bclk_ratio; |
---|
| 73 | + spinlock_t lock; /* tx/rx lock */ |
---|
64 | 74 | unsigned int clk_trcm; |
---|
65 | 75 | |
---|
66 | 76 | unsigned int mclk_root_rate; |
---|
.. | .. |
---|
68 | 78 | int clk_ppm; |
---|
69 | 79 | bool mclk_calibrate; |
---|
70 | 80 | |
---|
| 81 | + unsigned int quirks; |
---|
71 | 82 | }; |
---|
72 | 83 | |
---|
73 | | -/* txctrl/rxctrl lock */ |
---|
74 | | -static DEFINE_SPINLOCK(lock); |
---|
| 84 | +static struct i2s_of_quirks { |
---|
| 85 | + char *quirk; |
---|
| 86 | + int id; |
---|
| 87 | +} of_quirks[] = { |
---|
| 88 | + { |
---|
| 89 | + .quirk = "rockchip,always-on", |
---|
| 90 | + .id = QUIRK_ALWAYS_ON, |
---|
| 91 | + }, |
---|
| 92 | +}; |
---|
75 | 93 | |
---|
76 | 94 | static int i2s_runtime_suspend(struct device *dev) |
---|
77 | 95 | { |
---|
.. | .. |
---|
109 | 127 | return snd_soc_dai_get_drvdata(dai); |
---|
110 | 128 | } |
---|
111 | 129 | |
---|
112 | | -static void rockchip_i2s_reset(struct rk_i2s_dev *i2s) |
---|
| 130 | +static int rockchip_i2s_clear(struct rk_i2s_dev *i2s) |
---|
113 | 131 | { |
---|
114 | | - if (!IS_ERR(i2s->reset_m)) |
---|
115 | | - reset_control_assert(i2s->reset_m); |
---|
116 | | - if (!IS_ERR(i2s->reset_h)) |
---|
117 | | - reset_control_assert(i2s->reset_h); |
---|
118 | | - udelay(1); |
---|
119 | | - if (!IS_ERR(i2s->reset_m)) |
---|
120 | | - reset_control_deassert(i2s->reset_m); |
---|
121 | | - if (!IS_ERR(i2s->reset_h)) |
---|
122 | | - reset_control_deassert(i2s->reset_h); |
---|
123 | | - regcache_mark_dirty(i2s->regmap); |
---|
124 | | - regcache_sync(i2s->regmap); |
---|
| 132 | + unsigned int clr = I2S_CLR_TXC | I2S_CLR_RXC; |
---|
| 133 | + unsigned int val = 0; |
---|
| 134 | + int ret; |
---|
| 135 | + |
---|
| 136 | + /* |
---|
| 137 | + * Workaround for FIFO clear on SLAVE mode: |
---|
| 138 | + * |
---|
| 139 | + * A Suggest to do reset hclk domain and then do mclk |
---|
| 140 | + * domain, especially for SLAVE mode without CLK in. |
---|
| 141 | + * at last, recovery regmap config. |
---|
| 142 | + * |
---|
| 143 | + * B Suggest to switch to MASTER, and then do FIFO clr, |
---|
| 144 | + * at last, bring back to SLAVE. |
---|
| 145 | + * |
---|
| 146 | + * Now we choose plan B here. |
---|
| 147 | + */ |
---|
| 148 | + if (!i2s->is_master_mode) |
---|
| 149 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
---|
| 150 | + I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER); |
---|
| 151 | + regmap_update_bits(i2s->regmap, I2S_CLR, clr, clr); |
---|
| 152 | + |
---|
| 153 | + ret = regmap_read_poll_timeout_atomic(i2s->regmap, I2S_CLR, val, |
---|
| 154 | + !(val & clr), 10, 100); |
---|
| 155 | + if (!i2s->is_master_mode) |
---|
| 156 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
---|
| 157 | + I2S_CKR_MSS_MASK, I2S_CKR_MSS_SLAVE); |
---|
| 158 | + if (ret < 0) |
---|
| 159 | + dev_warn(i2s->dev, "failed to clear fifo on %s mode\n", |
---|
| 160 | + i2s->is_master_mode ? "master" : "slave"); |
---|
| 161 | + |
---|
| 162 | + return ret; |
---|
125 | 163 | } |
---|
126 | 164 | |
---|
127 | 165 | static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) |
---|
128 | 166 | { |
---|
129 | | - unsigned int val = 0; |
---|
130 | | - int retry = 10; |
---|
131 | | - |
---|
132 | | - spin_lock(&lock); |
---|
| 167 | + spin_lock(&i2s->lock); |
---|
133 | 168 | if (on) { |
---|
134 | 169 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
---|
135 | 170 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); |
---|
.. | .. |
---|
145 | 180 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
---|
146 | 181 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); |
---|
147 | 182 | |
---|
148 | | - if (!i2s->rx_start) { |
---|
| 183 | + if (!i2s->rx_start && !(i2s->quirks & QUIRK_ALWAYS_ON)) { |
---|
149 | 184 | regmap_update_bits(i2s->regmap, I2S_XFER, |
---|
150 | 185 | I2S_XFER_TXS_START | |
---|
151 | 186 | I2S_XFER_RXS_START, |
---|
.. | .. |
---|
153 | 188 | I2S_XFER_RXS_STOP); |
---|
154 | 189 | |
---|
155 | 190 | udelay(150); |
---|
156 | | - regmap_update_bits(i2s->regmap, I2S_CLR, |
---|
157 | | - I2S_CLR_TXC | I2S_CLR_RXC, |
---|
158 | | - I2S_CLR_TXC | I2S_CLR_RXC); |
---|
159 | | - |
---|
160 | | - regmap_read(i2s->regmap, I2S_CLR, &val); |
---|
161 | | - |
---|
162 | | - /* Should wait for clear operation to finish */ |
---|
163 | | - while (val) { |
---|
164 | | - regmap_read(i2s->regmap, I2S_CLR, &val); |
---|
165 | | - retry--; |
---|
166 | | - if (!retry) { |
---|
167 | | - dev_warn(i2s->dev, "reset\n"); |
---|
168 | | - rockchip_i2s_reset(i2s); |
---|
169 | | - break; |
---|
170 | | - } |
---|
171 | | - } |
---|
| 191 | + rockchip_i2s_clear(i2s); |
---|
172 | 192 | } |
---|
173 | 193 | } |
---|
174 | | - spin_unlock(&lock); |
---|
| 194 | + spin_unlock(&i2s->lock); |
---|
175 | 195 | } |
---|
176 | 196 | |
---|
177 | 197 | static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) |
---|
178 | 198 | { |
---|
179 | | - unsigned int val = 0; |
---|
180 | | - int retry = 10; |
---|
181 | | - |
---|
182 | | - spin_lock(&lock); |
---|
| 199 | + spin_lock(&i2s->lock); |
---|
183 | 200 | if (on) { |
---|
184 | 201 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
---|
185 | 202 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); |
---|
.. | .. |
---|
195 | 212 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
---|
196 | 213 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); |
---|
197 | 214 | |
---|
198 | | - if (!i2s->tx_start) { |
---|
| 215 | + if (!i2s->tx_start && !(i2s->quirks & QUIRK_ALWAYS_ON)) { |
---|
199 | 216 | regmap_update_bits(i2s->regmap, I2S_XFER, |
---|
200 | 217 | I2S_XFER_TXS_START | |
---|
201 | 218 | I2S_XFER_RXS_START, |
---|
.. | .. |
---|
203 | 220 | I2S_XFER_RXS_STOP); |
---|
204 | 221 | |
---|
205 | 222 | udelay(150); |
---|
206 | | - regmap_update_bits(i2s->regmap, I2S_CLR, |
---|
207 | | - I2S_CLR_TXC | I2S_CLR_RXC, |
---|
208 | | - I2S_CLR_TXC | I2S_CLR_RXC); |
---|
209 | | - |
---|
210 | | - regmap_read(i2s->regmap, I2S_CLR, &val); |
---|
211 | | - |
---|
212 | | - /* Should wait for clear operation to finish */ |
---|
213 | | - while (val) { |
---|
214 | | - regmap_read(i2s->regmap, I2S_CLR, &val); |
---|
215 | | - retry--; |
---|
216 | | - if (!retry) { |
---|
217 | | - dev_warn(i2s->dev, "reset\n"); |
---|
218 | | - rockchip_i2s_reset(i2s); |
---|
219 | | - break; |
---|
220 | | - } |
---|
221 | | - } |
---|
| 223 | + rockchip_i2s_clear(i2s); |
---|
222 | 224 | } |
---|
223 | 225 | } |
---|
224 | | - spin_unlock(&lock); |
---|
| 226 | + spin_unlock(&i2s->lock); |
---|
225 | 227 | } |
---|
226 | 228 | |
---|
227 | 229 | static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
---|
.. | .. |
---|
333 | 335 | return ret; |
---|
334 | 336 | } |
---|
335 | 337 | |
---|
| 338 | +static void rockchip_i2s_get_performance(struct snd_pcm_substream *substream, |
---|
| 339 | + struct snd_pcm_hw_params *params, |
---|
| 340 | + struct snd_soc_dai *dai, |
---|
| 341 | + unsigned int csr) |
---|
| 342 | +{ |
---|
| 343 | + struct rk_i2s_dev *i2s = to_info(dai); |
---|
| 344 | + unsigned int tdl; |
---|
| 345 | + int fifo; |
---|
| 346 | + |
---|
| 347 | + regmap_read(i2s->regmap, I2S_DMACR, &tdl); |
---|
| 348 | + |
---|
| 349 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 350 | + fifo = I2S_DMACR_TDL_V(tdl) * I2S_TXCR_CSR_V(csr); |
---|
| 351 | + else |
---|
| 352 | + fifo = I2S_DMACR_RDL_V(tdl) * I2S_RXCR_CSR_V(csr); |
---|
| 353 | + |
---|
| 354 | + rockchip_utils_get_performance(substream, params, dai, fifo); |
---|
| 355 | +} |
---|
| 356 | + |
---|
336 | 357 | static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, |
---|
337 | 358 | struct snd_pcm_hw_params *params, |
---|
338 | 359 | struct snd_soc_dai *dai) |
---|
.. | .. |
---|
343 | 364 | |
---|
344 | 365 | if (i2s->is_master_mode) { |
---|
345 | 366 | mclk_rate = clk_get_rate(i2s->mclk); |
---|
346 | | - bclk_rate = i2s->bclk_fs * params_rate(params); |
---|
| 367 | + bclk_rate = i2s->bclk_ratio * params_rate(params); |
---|
347 | 368 | if (!bclk_rate) |
---|
348 | 369 | return -EINVAL; |
---|
349 | 370 | |
---|
.. | .. |
---|
374 | 395 | val |= I2S_TXCR_VDW(24); |
---|
375 | 396 | break; |
---|
376 | 397 | case SNDRV_PCM_FORMAT_S32_LE: |
---|
| 398 | + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: |
---|
377 | 399 | val |= I2S_TXCR_VDW(32); |
---|
378 | 400 | break; |
---|
379 | 401 | default: |
---|
.. | .. |
---|
398 | 420 | params_channels(params)); |
---|
399 | 421 | return -EINVAL; |
---|
400 | 422 | } |
---|
| 423 | + |
---|
| 424 | + rockchip_i2s_get_performance(substream, params, dai, val); |
---|
401 | 425 | |
---|
402 | 426 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
---|
403 | 427 | regmap_update_bits(i2s->regmap, I2S_RXCR, |
---|
.. | .. |
---|
440 | 464 | return 0; |
---|
441 | 465 | } |
---|
442 | 466 | |
---|
| 467 | +static int rockchip_i2s_hw_free(struct snd_pcm_substream *substream, |
---|
| 468 | + struct snd_soc_dai *dai) |
---|
| 469 | +{ |
---|
| 470 | + rockchip_utils_put_performance(substream, dai); |
---|
| 471 | + |
---|
| 472 | + return 0; |
---|
| 473 | +} |
---|
| 474 | + |
---|
443 | 475 | static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, |
---|
444 | 476 | int cmd, struct snd_soc_dai *dai) |
---|
445 | 477 | { |
---|
.. | .. |
---|
469 | 501 | } |
---|
470 | 502 | |
---|
471 | 503 | return ret; |
---|
| 504 | +} |
---|
| 505 | + |
---|
| 506 | +static int rockchip_i2s_set_bclk_ratio(struct snd_soc_dai *dai, |
---|
| 507 | + unsigned int ratio) |
---|
| 508 | +{ |
---|
| 509 | + struct rk_i2s_dev *i2s = to_info(dai); |
---|
| 510 | + |
---|
| 511 | + i2s->bclk_ratio = ratio; |
---|
| 512 | + |
---|
| 513 | + return 0; |
---|
472 | 514 | } |
---|
473 | 515 | |
---|
474 | 516 | static int rockchip_i2s_clk_set_rate(struct rk_i2s_dev *i2s, |
---|
.. | .. |
---|
510 | 552 | unsigned int root_rate, div, delta; |
---|
511 | 553 | uint64_t ppm; |
---|
512 | 554 | int ret; |
---|
| 555 | + |
---|
| 556 | + if (rate == 0) |
---|
| 557 | + return 0; |
---|
513 | 558 | |
---|
514 | 559 | if (i2s->mclk_calibrate) { |
---|
515 | 560 | ret = rockchip_i2s_clk_set_rate(i2s, i2s->mclk_root, |
---|
.. | .. |
---|
557 | 602 | static int rockchip_i2s_clk_compensation_get(struct snd_kcontrol *kcontrol, |
---|
558 | 603 | struct snd_ctl_elem_value *ucontrol) |
---|
559 | 604 | { |
---|
560 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
561 | | - struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 605 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
---|
| 606 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
---|
562 | 607 | |
---|
563 | 608 | ucontrol->value.integer.value[0] = i2s->clk_ppm; |
---|
564 | 609 | |
---|
.. | .. |
---|
568 | 613 | static int rockchip_i2s_clk_compensation_put(struct snd_kcontrol *kcontrol, |
---|
569 | 614 | struct snd_ctl_elem_value *ucontrol) |
---|
570 | 615 | { |
---|
571 | | - struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); |
---|
572 | | - struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 616 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
---|
| 617 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
---|
573 | 618 | int ppm = ucontrol->value.integer.value[0]; |
---|
574 | 619 | |
---|
575 | 620 | if ((ucontrol->value.integer.value[0] < CLK_PPM_MIN) || |
---|
.. | .. |
---|
591 | 636 | { |
---|
592 | 637 | struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
---|
593 | 638 | |
---|
594 | | - dai->capture_dma_data = &i2s->capture_dma_data; |
---|
595 | | - dai->playback_dma_data = &i2s->playback_dma_data; |
---|
| 639 | + snd_soc_dai_init_dma_data(dai, |
---|
| 640 | + i2s->has_playback ? &i2s->playback_dma_data : NULL, |
---|
| 641 | + i2s->has_capture ? &i2s->capture_dma_data : NULL); |
---|
596 | 642 | |
---|
597 | 643 | if (i2s->mclk_calibrate) |
---|
598 | | - snd_soc_add_dai_controls(dai, &rockchip_i2s_compensation_control, 1); |
---|
| 644 | + snd_soc_add_component_controls(dai->component, |
---|
| 645 | + &rockchip_i2s_compensation_control, |
---|
| 646 | + 1); |
---|
599 | 647 | |
---|
600 | 648 | return 0; |
---|
601 | 649 | } |
---|
602 | 650 | |
---|
| 651 | +static int rockchip_i2s_startup(struct snd_pcm_substream *substream, |
---|
| 652 | + struct snd_soc_dai *dai) |
---|
| 653 | +{ |
---|
| 654 | + struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 655 | + int stream = substream->stream; |
---|
| 656 | + |
---|
| 657 | + if (i2s->substreams[stream]) |
---|
| 658 | + return -EBUSY; |
---|
| 659 | + |
---|
| 660 | + if (i2s->wait_time[stream]) |
---|
| 661 | + substream->wait_time = msecs_to_jiffies(i2s->wait_time[stream]); |
---|
| 662 | + |
---|
| 663 | + i2s->substreams[stream] = substream; |
---|
| 664 | + |
---|
| 665 | + return 0; |
---|
| 666 | +} |
---|
| 667 | + |
---|
| 668 | +static void rockchip_i2s_shutdown(struct snd_pcm_substream *substream, |
---|
| 669 | + struct snd_soc_dai *dai) |
---|
| 670 | +{ |
---|
| 671 | + struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
---|
| 672 | + |
---|
| 673 | + i2s->substreams[substream->stream] = NULL; |
---|
| 674 | +} |
---|
| 675 | + |
---|
603 | 676 | static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { |
---|
| 677 | + .startup = rockchip_i2s_startup, |
---|
| 678 | + .shutdown = rockchip_i2s_shutdown, |
---|
604 | 679 | .hw_params = rockchip_i2s_hw_params, |
---|
| 680 | + .hw_free = rockchip_i2s_hw_free, |
---|
| 681 | + .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, |
---|
605 | 682 | .set_sysclk = rockchip_i2s_set_sysclk, |
---|
606 | 683 | .set_fmt = rockchip_i2s_set_fmt, |
---|
607 | 684 | .trigger = rockchip_i2s_trigger, |
---|
.. | .. |
---|
609 | 686 | |
---|
610 | 687 | static struct snd_soc_dai_driver rockchip_i2s_dai = { |
---|
611 | 688 | .probe = rockchip_i2s_dai_probe, |
---|
612 | | - .playback = { |
---|
613 | | - .stream_name = "Playback", |
---|
614 | | - .channels_min = 2, |
---|
615 | | - .channels_max = 8, |
---|
616 | | - .rates = SNDRV_PCM_RATE_8000_192000, |
---|
617 | | - .formats = (SNDRV_PCM_FMTBIT_S8 | |
---|
618 | | - SNDRV_PCM_FMTBIT_S16_LE | |
---|
619 | | - SNDRV_PCM_FMTBIT_S20_3LE | |
---|
620 | | - SNDRV_PCM_FMTBIT_S24_LE | |
---|
621 | | - SNDRV_PCM_FMTBIT_S32_LE), |
---|
622 | | - }, |
---|
623 | | - .capture = { |
---|
624 | | - .stream_name = "Capture", |
---|
625 | | - .channels_min = 2, |
---|
626 | | - .channels_max = 2, |
---|
627 | | - .rates = SNDRV_PCM_RATE_8000_192000, |
---|
628 | | - .formats = (SNDRV_PCM_FMTBIT_S8 | |
---|
629 | | - SNDRV_PCM_FMTBIT_S16_LE | |
---|
630 | | - SNDRV_PCM_FMTBIT_S20_3LE | |
---|
631 | | - SNDRV_PCM_FMTBIT_S24_LE | |
---|
632 | | - SNDRV_PCM_FMTBIT_S32_LE), |
---|
633 | | - }, |
---|
634 | 689 | .ops = &rockchip_i2s_dai_ops, |
---|
| 690 | +}; |
---|
| 691 | + |
---|
| 692 | +static int rockchip_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol, |
---|
| 693 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 694 | +{ |
---|
| 695 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
---|
| 696 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
---|
| 697 | + |
---|
| 698 | + ucontrol->value.integer.value[0] = i2s->bclk_ratio; |
---|
| 699 | + |
---|
| 700 | + return 0; |
---|
| 701 | +} |
---|
| 702 | + |
---|
| 703 | +static int rockchip_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol, |
---|
| 704 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 705 | +{ |
---|
| 706 | + struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); |
---|
| 707 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt); |
---|
| 708 | + int value = ucontrol->value.integer.value[0]; |
---|
| 709 | + |
---|
| 710 | + if (value == i2s->bclk_ratio) |
---|
| 711 | + return 0; |
---|
| 712 | + |
---|
| 713 | + i2s->bclk_ratio = value; |
---|
| 714 | + |
---|
| 715 | + return 1; |
---|
| 716 | +} |
---|
| 717 | + |
---|
| 718 | +static int rockchip_i2s_wait_time_info(struct snd_kcontrol *kcontrol, |
---|
| 719 | + struct snd_ctl_elem_info *uinfo) |
---|
| 720 | +{ |
---|
| 721 | + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
---|
| 722 | + uinfo->count = 1; |
---|
| 723 | + uinfo->value.integer.min = 0; |
---|
| 724 | + uinfo->value.integer.max = WAIT_TIME_MS_MAX; |
---|
| 725 | + uinfo->value.integer.step = 1; |
---|
| 726 | + |
---|
| 727 | + return 0; |
---|
| 728 | +} |
---|
| 729 | + |
---|
| 730 | +static int rockchip_i2s_rd_wait_time_get(struct snd_kcontrol *kcontrol, |
---|
| 731 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 732 | +{ |
---|
| 733 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 734 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
---|
| 735 | + |
---|
| 736 | + ucontrol->value.integer.value[0] = i2s->wait_time[SNDRV_PCM_STREAM_CAPTURE]; |
---|
| 737 | + |
---|
| 738 | + return 0; |
---|
| 739 | +} |
---|
| 740 | + |
---|
| 741 | +static int rockchip_i2s_rd_wait_time_put(struct snd_kcontrol *kcontrol, |
---|
| 742 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 743 | +{ |
---|
| 744 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 745 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
---|
| 746 | + |
---|
| 747 | + if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX) |
---|
| 748 | + return -EINVAL; |
---|
| 749 | + |
---|
| 750 | + i2s->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0]; |
---|
| 751 | + |
---|
| 752 | + return 1; |
---|
| 753 | +} |
---|
| 754 | + |
---|
| 755 | +static int rockchip_i2s_wr_wait_time_get(struct snd_kcontrol *kcontrol, |
---|
| 756 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 757 | +{ |
---|
| 758 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 759 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
---|
| 760 | + |
---|
| 761 | + ucontrol->value.integer.value[0] = i2s->wait_time[SNDRV_PCM_STREAM_PLAYBACK]; |
---|
| 762 | + |
---|
| 763 | + return 0; |
---|
| 764 | +} |
---|
| 765 | + |
---|
| 766 | +static int rockchip_i2s_wr_wait_time_put(struct snd_kcontrol *kcontrol, |
---|
| 767 | + struct snd_ctl_elem_value *ucontrol) |
---|
| 768 | +{ |
---|
| 769 | + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
---|
| 770 | + struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component); |
---|
| 771 | + |
---|
| 772 | + if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX) |
---|
| 773 | + return -EINVAL; |
---|
| 774 | + |
---|
| 775 | + i2s->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0]; |
---|
| 776 | + |
---|
| 777 | + return 1; |
---|
| 778 | +} |
---|
| 779 | + |
---|
| 780 | +#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \ |
---|
| 781 | +{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \ |
---|
| 782 | + .info = rockchip_i2s_wait_time_info, \ |
---|
| 783 | + .get = xhandler_get, .put = xhandler_put } |
---|
| 784 | + |
---|
| 785 | +static const struct snd_kcontrol_new rockchip_i2s_snd_controls[] = { |
---|
| 786 | + SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, |
---|
| 787 | + rockchip_i2s_get_bclk_ratio, |
---|
| 788 | + rockchip_i2s_put_bclk_ratio), |
---|
| 789 | + |
---|
| 790 | + SAI_PCM_WAIT_TIME("PCM Read Wait Time MS", |
---|
| 791 | + rockchip_i2s_rd_wait_time_get, |
---|
| 792 | + rockchip_i2s_rd_wait_time_put), |
---|
| 793 | + SAI_PCM_WAIT_TIME("PCM Write Wait Time MS", |
---|
| 794 | + rockchip_i2s_wr_wait_time_get, |
---|
| 795 | + rockchip_i2s_wr_wait_time_put), |
---|
635 | 796 | }; |
---|
636 | 797 | |
---|
637 | 798 | static const struct snd_soc_component_driver rockchip_i2s_component = { |
---|
638 | 799 | .name = DRV_NAME, |
---|
| 800 | + .controls = rockchip_i2s_snd_controls, |
---|
| 801 | + .num_controls = ARRAY_SIZE(rockchip_i2s_snd_controls), |
---|
639 | 802 | }; |
---|
640 | 803 | |
---|
641 | 804 | static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg) |
---|
.. | .. |
---|
667 | 830 | case I2S_CLR: |
---|
668 | 831 | case I2S_TXDR: |
---|
669 | 832 | case I2S_RXDR: |
---|
670 | | - case I2S_FIFOLR: |
---|
| 833 | + case I2S_TXFIFOLR: |
---|
| 834 | + case I2S_RXFIFOLR: |
---|
671 | 835 | case I2S_INTSR: |
---|
672 | 836 | return true; |
---|
673 | 837 | default: |
---|
.. | .. |
---|
680 | 844 | switch (reg) { |
---|
681 | 845 | case I2S_INTSR: |
---|
682 | 846 | case I2S_CLR: |
---|
683 | | - case I2S_FIFOLR: |
---|
| 847 | + case I2S_TXFIFOLR: |
---|
| 848 | + case I2S_RXFIFOLR: |
---|
684 | 849 | case I2S_TXDR: |
---|
685 | 850 | case I2S_RXDR: |
---|
686 | 851 | return true; |
---|
.. | .. |
---|
726 | 891 | .shift = 11, |
---|
727 | 892 | }; |
---|
728 | 893 | |
---|
729 | | -static const struct of_device_id rockchip_i2s_match[] = { |
---|
| 894 | +static const struct of_device_id rockchip_i2s_match[] __maybe_unused = { |
---|
730 | 895 | #ifdef CONFIG_CPU_PX30 |
---|
731 | 896 | { .compatible = "rockchip,px30-i2s", }, |
---|
732 | 897 | #endif |
---|
.. | .. |
---|
743 | 908 | #ifdef CONFIG_CPU_RK3188 |
---|
744 | 909 | { .compatible = "rockchip,rk3188-i2s", }, |
---|
745 | 910 | #endif |
---|
| 911 | +#ifdef CONFIG_CPU_RK322X |
---|
| 912 | + { .compatible = "rockchip,rk3228-i2s", }, |
---|
| 913 | +#endif |
---|
746 | 914 | #ifdef CONFIG_CPU_RK3288 |
---|
747 | 915 | { .compatible = "rockchip,rk3288-i2s", }, |
---|
748 | 916 | #endif |
---|
.. | .. |
---|
751 | 919 | #endif |
---|
752 | 920 | #ifdef CONFIG_CPU_RK3328 |
---|
753 | 921 | { .compatible = "rockchip,rk3328-i2s", }, |
---|
| 922 | +#endif |
---|
| 923 | +#ifdef CONFIG_CPU_RK3366 |
---|
| 924 | + { .compatible = "rockchip,rk3366-i2s", }, |
---|
754 | 925 | #endif |
---|
755 | 926 | #ifdef CONFIG_CPU_RK3368 |
---|
756 | 927 | { .compatible = "rockchip,rk3368-i2s", }, |
---|
.. | .. |
---|
764 | 935 | {}, |
---|
765 | 936 | }; |
---|
766 | 937 | |
---|
| 938 | +static int rockchip_i2s_init_dai(struct rk_i2s_dev *i2s, struct resource *res, |
---|
| 939 | + struct snd_soc_dai_driver **dp) |
---|
| 940 | +{ |
---|
| 941 | + struct device_node *node = i2s->dev->of_node; |
---|
| 942 | + struct snd_soc_dai_driver *dai; |
---|
| 943 | + struct property *dma_names; |
---|
| 944 | + const char *dma_name; |
---|
| 945 | + unsigned int val; |
---|
| 946 | + |
---|
| 947 | + of_property_for_each_string(node, "dma-names", dma_names, dma_name) { |
---|
| 948 | + if (!strcmp(dma_name, "tx")) |
---|
| 949 | + i2s->has_playback = true; |
---|
| 950 | + if (!strcmp(dma_name, "rx")) |
---|
| 951 | + i2s->has_capture = true; |
---|
| 952 | + } |
---|
| 953 | + |
---|
| 954 | + dai = devm_kmemdup(i2s->dev, &rockchip_i2s_dai, |
---|
| 955 | + sizeof(*dai), GFP_KERNEL); |
---|
| 956 | + if (!dai) |
---|
| 957 | + return -ENOMEM; |
---|
| 958 | + |
---|
| 959 | + if (i2s->has_playback) { |
---|
| 960 | + dai->playback.stream_name = "Playback"; |
---|
| 961 | + dai->playback.channels_min = 2; |
---|
| 962 | + dai->playback.channels_max = 8; |
---|
| 963 | + dai->playback.rates = SNDRV_PCM_RATE_8000_192000; |
---|
| 964 | + dai->playback.formats = SNDRV_PCM_FMTBIT_S8 | |
---|
| 965 | + SNDRV_PCM_FMTBIT_S16_LE | |
---|
| 966 | + SNDRV_PCM_FMTBIT_S20_3LE | |
---|
| 967 | + SNDRV_PCM_FMTBIT_S24_LE | |
---|
| 968 | + SNDRV_PCM_FMTBIT_S32_LE | |
---|
| 969 | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; |
---|
| 970 | + |
---|
| 971 | + i2s->playback_dma_data.addr = res->start + I2S_TXDR; |
---|
| 972 | + i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
| 973 | + i2s->playback_dma_data.maxburst = 8; |
---|
| 974 | + |
---|
| 975 | + if (!device_property_read_u32(i2s->dev, "rockchip,playback-channels", &val)) { |
---|
| 976 | + if (val >= 2 && val <= 8) |
---|
| 977 | + dai->playback.channels_max = val; |
---|
| 978 | + } |
---|
| 979 | + } |
---|
| 980 | + |
---|
| 981 | + if (i2s->has_capture) { |
---|
| 982 | + dai->capture.stream_name = "Capture"; |
---|
| 983 | + dai->capture.channels_min = 2; |
---|
| 984 | + dai->capture.channels_max = 8; |
---|
| 985 | + dai->capture.rates = SNDRV_PCM_RATE_8000_192000; |
---|
| 986 | + dai->capture.formats = SNDRV_PCM_FMTBIT_S8 | |
---|
| 987 | + SNDRV_PCM_FMTBIT_S16_LE | |
---|
| 988 | + SNDRV_PCM_FMTBIT_S20_3LE | |
---|
| 989 | + SNDRV_PCM_FMTBIT_S24_LE | |
---|
| 990 | + SNDRV_PCM_FMTBIT_S32_LE | |
---|
| 991 | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; |
---|
| 992 | + |
---|
| 993 | + i2s->capture_dma_data.addr = res->start + I2S_RXDR; |
---|
| 994 | + i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
| 995 | + i2s->capture_dma_data.maxburst = 8; |
---|
| 996 | + |
---|
| 997 | + if (!device_property_read_u32(i2s->dev, "rockchip,capture-channels", &val)) { |
---|
| 998 | + if (val >= 2 && val <= 8) |
---|
| 999 | + dai->capture.channels_max = val; |
---|
| 1000 | + } |
---|
| 1001 | + } |
---|
| 1002 | + |
---|
| 1003 | + i2s->clk_trcm = I2S_CKR_TRCM_TXRX; |
---|
| 1004 | + if (!device_property_read_u32(i2s->dev, "rockchip,clk-trcm", &val)) { |
---|
| 1005 | + if (val >= 0 && val <= 2) { |
---|
| 1006 | + i2s->clk_trcm = val << I2S_CKR_TRCM_SHIFT; |
---|
| 1007 | + if (i2s->clk_trcm) |
---|
| 1008 | + dai->symmetric_rates = 1; |
---|
| 1009 | + } |
---|
| 1010 | + } |
---|
| 1011 | + |
---|
| 1012 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
---|
| 1013 | + I2S_CKR_TRCM_MASK, i2s->clk_trcm); |
---|
| 1014 | + |
---|
| 1015 | + if (dp) |
---|
| 1016 | + *dp = dai; |
---|
| 1017 | + |
---|
| 1018 | + return 0; |
---|
| 1019 | +} |
---|
| 1020 | + |
---|
| 1021 | +static int rockchip_i2s_keep_clk_always_on(struct rk_i2s_dev *i2s) |
---|
| 1022 | +{ |
---|
| 1023 | + unsigned int mclk_rate = DEFAULT_FS * DEFAULT_MCLK_FS; |
---|
| 1024 | + unsigned int bclk_rate = i2s->bclk_ratio * DEFAULT_FS; |
---|
| 1025 | + unsigned int div_lrck = i2s->bclk_ratio; |
---|
| 1026 | + unsigned int div_bclk; |
---|
| 1027 | + |
---|
| 1028 | + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); |
---|
| 1029 | + |
---|
| 1030 | + /* assign generic freq */ |
---|
| 1031 | + clk_set_rate(i2s->mclk, mclk_rate); |
---|
| 1032 | + |
---|
| 1033 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
---|
| 1034 | + I2S_CKR_MDIV_MASK, |
---|
| 1035 | + I2S_CKR_MDIV(div_bclk)); |
---|
| 1036 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
---|
| 1037 | + I2S_CKR_TSD_MASK | |
---|
| 1038 | + I2S_CKR_RSD_MASK, |
---|
| 1039 | + I2S_CKR_TSD(div_lrck) | |
---|
| 1040 | + I2S_CKR_RSD(div_lrck)); |
---|
| 1041 | + regmap_update_bits(i2s->regmap, I2S_XFER, |
---|
| 1042 | + I2S_XFER_TXS_START | I2S_XFER_RXS_START, |
---|
| 1043 | + I2S_XFER_TXS_START | I2S_XFER_RXS_START); |
---|
| 1044 | + |
---|
| 1045 | + pm_runtime_forbid(i2s->dev); |
---|
| 1046 | + |
---|
| 1047 | + dev_info(i2s->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", |
---|
| 1048 | + mclk_rate, bclk_rate, DEFAULT_FS); |
---|
| 1049 | + |
---|
| 1050 | + return 0; |
---|
| 1051 | +} |
---|
| 1052 | + |
---|
| 1053 | +static int rockchip_i2s_get_fifo_count(struct device *dev, |
---|
| 1054 | + struct snd_pcm_substream *substream) |
---|
| 1055 | +{ |
---|
| 1056 | + struct rk_i2s_dev *i2s = dev_get_drvdata(dev); |
---|
| 1057 | + unsigned int tx, rx; |
---|
| 1058 | + int val = 0; |
---|
| 1059 | + |
---|
| 1060 | + regmap_read(i2s->regmap, I2S_TXFIFOLR, &tx); |
---|
| 1061 | + regmap_read(i2s->regmap, I2S_RXFIFOLR, &rx); |
---|
| 1062 | + |
---|
| 1063 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 1064 | + val = I2S_FIFOLR_XFL3(tx) + |
---|
| 1065 | + I2S_FIFOLR_XFL2(tx) + |
---|
| 1066 | + I2S_FIFOLR_XFL1(tx) + |
---|
| 1067 | + I2S_FIFOLR_XFL0(tx); |
---|
| 1068 | + else |
---|
| 1069 | + /* XFL4 is compatible for old version */ |
---|
| 1070 | + val = I2S_FIFOLR_XFL4(tx) + |
---|
| 1071 | + I2S_FIFOLR_XFL3(rx) + |
---|
| 1072 | + I2S_FIFOLR_XFL2(rx) + |
---|
| 1073 | + I2S_FIFOLR_XFL1(rx) + |
---|
| 1074 | + I2S_FIFOLR_XFL0(rx); |
---|
| 1075 | + |
---|
| 1076 | + return val; |
---|
| 1077 | +} |
---|
| 1078 | + |
---|
| 1079 | +static const struct snd_dlp_config dconfig = { |
---|
| 1080 | + .get_fifo_count = rockchip_i2s_get_fifo_count, |
---|
| 1081 | +}; |
---|
| 1082 | + |
---|
767 | 1083 | static int rockchip_i2s_probe(struct platform_device *pdev) |
---|
768 | 1084 | { |
---|
769 | 1085 | struct device_node *node = pdev->dev.of_node; |
---|
770 | 1086 | const struct of_device_id *of_id; |
---|
771 | 1087 | struct rk_i2s_dev *i2s; |
---|
772 | | - struct snd_soc_dai_driver *soc_dai; |
---|
| 1088 | + struct snd_soc_dai_driver *dai; |
---|
773 | 1089 | struct resource *res; |
---|
774 | 1090 | void __iomem *regs; |
---|
775 | | - int ret; |
---|
776 | | - int val; |
---|
| 1091 | + int ret, i, val; |
---|
777 | 1092 | |
---|
778 | 1093 | i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); |
---|
779 | 1094 | if (!i2s) |
---|
780 | 1095 | return -ENOMEM; |
---|
781 | 1096 | |
---|
| 1097 | + spin_lock_init(&i2s->lock); |
---|
782 | 1098 | i2s->dev = &pdev->dev; |
---|
783 | 1099 | |
---|
784 | 1100 | i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); |
---|
.. | .. |
---|
790 | 1106 | i2s->pins = of_id->data; |
---|
791 | 1107 | } |
---|
792 | 1108 | |
---|
793 | | - i2s->reset_m = devm_reset_control_get(&pdev->dev, "reset-m"); |
---|
794 | | - i2s->reset_h = devm_reset_control_get(&pdev->dev, "reset-h"); |
---|
| 1109 | + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) |
---|
| 1110 | + if (device_property_read_bool(i2s->dev, of_quirks[i].quirk)) |
---|
| 1111 | + i2s->quirks |= of_quirks[i].id; |
---|
| 1112 | + |
---|
| 1113 | + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
---|
| 1114 | + if (IS_ERR(regs)) |
---|
| 1115 | + return PTR_ERR(regs); |
---|
| 1116 | + |
---|
| 1117 | + i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, |
---|
| 1118 | + &rockchip_i2s_regmap_config); |
---|
| 1119 | + if (IS_ERR(i2s->regmap)) { |
---|
| 1120 | + dev_err(&pdev->dev, |
---|
| 1121 | + "Failed to initialise managed register map\n"); |
---|
| 1122 | + return PTR_ERR(i2s->regmap); |
---|
| 1123 | + } |
---|
| 1124 | + |
---|
| 1125 | + i2s->bclk_ratio = 64; |
---|
| 1126 | + if (!device_property_read_u32(&pdev->dev, "rockchip,bclk-fs", &val)) { |
---|
| 1127 | + if ((val >= 32) && (val % 2 == 0)) |
---|
| 1128 | + i2s->bclk_ratio = val; |
---|
| 1129 | + } |
---|
| 1130 | + |
---|
| 1131 | + dev_set_drvdata(&pdev->dev, i2s); |
---|
795 | 1132 | |
---|
796 | 1133 | i2s->mclk_calibrate = |
---|
797 | | - of_property_read_bool(node, "rockchip,mclk-calibrate"); |
---|
| 1134 | + device_property_read_bool(&pdev->dev, "rockchip,mclk-calibrate"); |
---|
798 | 1135 | if (i2s->mclk_calibrate) { |
---|
799 | 1136 | i2s->mclk_root = devm_clk_get(&pdev->dev, "i2s_clk_root"); |
---|
800 | 1137 | if (IS_ERR(i2s->mclk_root)) |
---|
.. | .. |
---|
802 | 1139 | |
---|
803 | 1140 | i2s->mclk_root_initial_rate = clk_get_rate(i2s->mclk_root); |
---|
804 | 1141 | i2s->mclk_root_rate = i2s->mclk_root_initial_rate; |
---|
| 1142 | + } |
---|
| 1143 | + |
---|
| 1144 | + i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); |
---|
| 1145 | + if (IS_ERR(i2s->mclk)) { |
---|
| 1146 | + dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); |
---|
| 1147 | + return PTR_ERR(i2s->mclk); |
---|
805 | 1148 | } |
---|
806 | 1149 | |
---|
807 | 1150 | /* try to prepare related clocks */ |
---|
.. | .. |
---|
816 | 1159 | return ret; |
---|
817 | 1160 | } |
---|
818 | 1161 | |
---|
819 | | - i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); |
---|
820 | | - if (IS_ERR(i2s->mclk)) { |
---|
821 | | - dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); |
---|
822 | | - return PTR_ERR(i2s->mclk); |
---|
| 1162 | + ret = rockchip_i2s_init_dai(i2s, res, &dai); |
---|
| 1163 | + if (ret) |
---|
| 1164 | + goto err_clk; |
---|
| 1165 | + |
---|
| 1166 | + /* |
---|
| 1167 | + * CLK_ALWAYS_ON should be placed after all registers write done, |
---|
| 1168 | + * because this situation will enable XFER bit which will make |
---|
| 1169 | + * some registers(depend on XFER) write failed. |
---|
| 1170 | + */ |
---|
| 1171 | + if (i2s->quirks & QUIRK_ALWAYS_ON) { |
---|
| 1172 | + ret = rockchip_i2s_keep_clk_always_on(i2s); |
---|
| 1173 | + if (ret) |
---|
| 1174 | + goto err_clk; |
---|
823 | 1175 | } |
---|
824 | 1176 | |
---|
825 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
826 | | - regs = devm_ioremap_resource(&pdev->dev, res); |
---|
827 | | - if (IS_ERR(regs)) |
---|
828 | | - return PTR_ERR(regs); |
---|
829 | | - |
---|
830 | | - i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, |
---|
831 | | - &rockchip_i2s_regmap_config); |
---|
832 | | - if (IS_ERR(i2s->regmap)) { |
---|
833 | | - dev_err(&pdev->dev, |
---|
834 | | - "Failed to initialise managed register map\n"); |
---|
835 | | - return PTR_ERR(i2s->regmap); |
---|
836 | | - } |
---|
837 | | - |
---|
838 | | - i2s->playback_dma_data.addr = res->start + I2S_TXDR; |
---|
839 | | - i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
840 | | - i2s->playback_dma_data.maxburst = 8; |
---|
841 | | - |
---|
842 | | - i2s->capture_dma_data.addr = res->start + I2S_RXDR; |
---|
843 | | - i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
---|
844 | | - i2s->capture_dma_data.maxburst = 8; |
---|
845 | | - |
---|
846 | | - dev_set_drvdata(&pdev->dev, i2s); |
---|
847 | | - |
---|
| 1177 | + /* |
---|
| 1178 | + * MUST: after pm_runtime_enable step, any register R/W |
---|
| 1179 | + * should be wrapped with pm_runtime_get_sync/put. |
---|
| 1180 | + * |
---|
| 1181 | + * Another approach is to enable the regcache true to |
---|
| 1182 | + * avoid access HW registers. |
---|
| 1183 | + * |
---|
| 1184 | + * Alternatively, performing the registers R/W before |
---|
| 1185 | + * pm_runtime_enable is also a good option. |
---|
| 1186 | + */ |
---|
848 | 1187 | pm_runtime_enable(&pdev->dev); |
---|
849 | 1188 | if (!pm_runtime_enabled(&pdev->dev)) { |
---|
850 | 1189 | ret = i2s_runtime_resume(&pdev->dev); |
---|
.. | .. |
---|
852 | 1191 | goto err_pm_disable; |
---|
853 | 1192 | } |
---|
854 | 1193 | |
---|
855 | | - soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai, |
---|
856 | | - sizeof(*soc_dai), GFP_KERNEL); |
---|
857 | | - if (!soc_dai) { |
---|
858 | | - ret = -ENOMEM; |
---|
859 | | - goto err_pm_disable; |
---|
860 | | - } |
---|
861 | | - |
---|
862 | | - if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { |
---|
863 | | - if (val >= 2 && val <= 8) |
---|
864 | | - soc_dai->playback.channels_max = val; |
---|
865 | | - } |
---|
866 | | - |
---|
867 | | - if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { |
---|
868 | | - if (val >= 2 && val <= 8) |
---|
869 | | - soc_dai->capture.channels_max = val; |
---|
870 | | - } |
---|
871 | | - |
---|
872 | | - if (of_property_read_bool(node, "rockchip,playback-only")) |
---|
873 | | - soc_dai->capture.channels_min = 0; |
---|
874 | | - else if (of_property_read_bool(node, "rockchip,capture-only")) |
---|
875 | | - soc_dai->playback.channels_min = 0; |
---|
876 | | - |
---|
877 | | - i2s->bclk_fs = 64; |
---|
878 | | - if (!of_property_read_u32(node, "rockchip,bclk-fs", &val)) { |
---|
879 | | - if ((val >= 32) && (val % 2 == 0)) |
---|
880 | | - i2s->bclk_fs = val; |
---|
881 | | - } |
---|
882 | | - |
---|
883 | | - i2s->clk_trcm = I2S_CKR_TRCM_TXRX; |
---|
884 | | - if (!of_property_read_u32(node, "rockchip,clk-trcm", &val)) { |
---|
885 | | - if (val >= 0 && val <= 2) { |
---|
886 | | - i2s->clk_trcm = val << I2S_CKR_TRCM_SHIFT; |
---|
887 | | - if (i2s->clk_trcm) |
---|
888 | | - soc_dai->symmetric_rates = 1; |
---|
889 | | - } |
---|
890 | | - } |
---|
891 | | - |
---|
892 | | - regmap_update_bits(i2s->regmap, I2S_CKR, |
---|
893 | | - I2S_CKR_TRCM_MASK, i2s->clk_trcm); |
---|
894 | | - |
---|
895 | 1194 | ret = devm_snd_soc_register_component(&pdev->dev, |
---|
896 | 1195 | &rockchip_i2s_component, |
---|
897 | | - soc_dai, 1); |
---|
| 1196 | + dai, 1); |
---|
898 | 1197 | |
---|
899 | 1198 | if (ret) { |
---|
900 | 1199 | dev_err(&pdev->dev, "Could not register DAI\n"); |
---|
901 | 1200 | goto err_suspend; |
---|
902 | 1201 | } |
---|
903 | 1202 | |
---|
904 | | - if (of_property_read_bool(node, "rockchip,no-dmaengine")) |
---|
905 | | - return ret; |
---|
906 | | - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
---|
| 1203 | + if (device_property_read_bool(&pdev->dev, "rockchip,no-dmaengine")) { |
---|
| 1204 | + dev_info(&pdev->dev, "Used for Multi-DAI\n"); |
---|
| 1205 | + return 0; |
---|
| 1206 | + } |
---|
| 1207 | + |
---|
| 1208 | + if (device_property_read_bool(&pdev->dev, "rockchip,digital-loopback")) |
---|
| 1209 | + ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig); |
---|
| 1210 | + else |
---|
| 1211 | + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
---|
| 1212 | + |
---|
907 | 1213 | if (ret) { |
---|
908 | 1214 | dev_err(&pdev->dev, "Could not register PCM\n"); |
---|
909 | 1215 | goto err_suspend; |
---|
.. | .. |
---|
916 | 1222 | i2s_runtime_suspend(&pdev->dev); |
---|
917 | 1223 | err_pm_disable: |
---|
918 | 1224 | pm_runtime_disable(&pdev->dev); |
---|
| 1225 | +err_clk: |
---|
| 1226 | + clk_disable_unprepare(i2s->hclk); |
---|
919 | 1227 | |
---|
920 | 1228 | return ret; |
---|
921 | 1229 | } |
---|