| .. | .. |
|---|
| 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> |
|---|
| .. | .. |
|---|
| 48 | 44 | |
|---|
| 49 | 45 | struct regmap *regmap; |
|---|
| 50 | 46 | struct regmap *grf; |
|---|
| 51 | | - struct reset_control *reset_m; |
|---|
| 52 | | - struct reset_control *reset_h; |
|---|
| 47 | + |
|---|
| 48 | + bool has_capture; |
|---|
| 49 | + bool has_playback; |
|---|
| 53 | 50 | |
|---|
| 54 | 51 | /* |
|---|
| 55 | 52 | * Used to indicate the tx/rx status. |
|---|
| .. | .. |
|---|
| 60 | 57 | bool rx_start; |
|---|
| 61 | 58 | bool is_master_mode; |
|---|
| 62 | 59 | const struct rk_i2s_pins *pins; |
|---|
| 63 | | - unsigned int bclk_fs; |
|---|
| 60 | + unsigned int bclk_ratio; |
|---|
| 61 | + spinlock_t lock; /* tx/rx lock */ |
|---|
| 64 | 62 | unsigned int clk_trcm; |
|---|
| 65 | 63 | |
|---|
| 66 | 64 | unsigned int mclk_root_rate; |
|---|
| .. | .. |
|---|
| 69 | 67 | bool mclk_calibrate; |
|---|
| 70 | 68 | |
|---|
| 71 | 69 | }; |
|---|
| 72 | | - |
|---|
| 73 | | -/* txctrl/rxctrl lock */ |
|---|
| 74 | | -static DEFINE_SPINLOCK(lock); |
|---|
| 75 | 70 | |
|---|
| 76 | 71 | static int i2s_runtime_suspend(struct device *dev) |
|---|
| 77 | 72 | { |
|---|
| .. | .. |
|---|
| 109 | 104 | return snd_soc_dai_get_drvdata(dai); |
|---|
| 110 | 105 | } |
|---|
| 111 | 106 | |
|---|
| 112 | | -static void rockchip_i2s_reset(struct rk_i2s_dev *i2s) |
|---|
| 107 | +static int rockchip_i2s_clear(struct rk_i2s_dev *i2s) |
|---|
| 113 | 108 | { |
|---|
| 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); |
|---|
| 109 | + unsigned int clr = I2S_CLR_TXC | I2S_CLR_RXC; |
|---|
| 110 | + unsigned int val = 0; |
|---|
| 111 | + int ret; |
|---|
| 112 | + |
|---|
| 113 | + /* |
|---|
| 114 | + * Workaround for FIFO clear on SLAVE mode: |
|---|
| 115 | + * |
|---|
| 116 | + * A Suggest to do reset hclk domain and then do mclk |
|---|
| 117 | + * domain, especially for SLAVE mode without CLK in. |
|---|
| 118 | + * at last, recovery regmap config. |
|---|
| 119 | + * |
|---|
| 120 | + * B Suggest to switch to MASTER, and then do FIFO clr, |
|---|
| 121 | + * at last, bring back to SLAVE. |
|---|
| 122 | + * |
|---|
| 123 | + * Now we choose plan B here. |
|---|
| 124 | + */ |
|---|
| 125 | + if (!i2s->is_master_mode) |
|---|
| 126 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 127 | + I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER); |
|---|
| 128 | + regmap_update_bits(i2s->regmap, I2S_CLR, clr, clr); |
|---|
| 129 | + |
|---|
| 130 | + ret = regmap_read_poll_timeout_atomic(i2s->regmap, I2S_CLR, val, |
|---|
| 131 | + !(val & clr), 10, 100); |
|---|
| 132 | + if (!i2s->is_master_mode) |
|---|
| 133 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 134 | + I2S_CKR_MSS_MASK, I2S_CKR_MSS_SLAVE); |
|---|
| 135 | + if (ret < 0) |
|---|
| 136 | + dev_warn(i2s->dev, "failed to clear fifo on %s mode\n", |
|---|
| 137 | + i2s->is_master_mode ? "master" : "slave"); |
|---|
| 138 | + |
|---|
| 139 | + return ret; |
|---|
| 125 | 140 | } |
|---|
| 126 | 141 | |
|---|
| 127 | 142 | static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) |
|---|
| 128 | 143 | { |
|---|
| 129 | | - unsigned int val = 0; |
|---|
| 130 | | - int retry = 10; |
|---|
| 131 | | - |
|---|
| 132 | | - spin_lock(&lock); |
|---|
| 144 | + spin_lock(&i2s->lock); |
|---|
| 133 | 145 | if (on) { |
|---|
| 134 | 146 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
|---|
| 135 | 147 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); |
|---|
| .. | .. |
|---|
| 153 | 165 | I2S_XFER_RXS_STOP); |
|---|
| 154 | 166 | |
|---|
| 155 | 167 | 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 | | - } |
|---|
| 168 | + rockchip_i2s_clear(i2s); |
|---|
| 172 | 169 | } |
|---|
| 173 | 170 | } |
|---|
| 174 | | - spin_unlock(&lock); |
|---|
| 171 | + spin_unlock(&i2s->lock); |
|---|
| 175 | 172 | } |
|---|
| 176 | 173 | |
|---|
| 177 | 174 | static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) |
|---|
| 178 | 175 | { |
|---|
| 179 | | - unsigned int val = 0; |
|---|
| 180 | | - int retry = 10; |
|---|
| 181 | | - |
|---|
| 182 | | - spin_lock(&lock); |
|---|
| 176 | + spin_lock(&i2s->lock); |
|---|
| 183 | 177 | if (on) { |
|---|
| 184 | 178 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
|---|
| 185 | 179 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); |
|---|
| .. | .. |
|---|
| 203 | 197 | I2S_XFER_RXS_STOP); |
|---|
| 204 | 198 | |
|---|
| 205 | 199 | 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 | | - } |
|---|
| 200 | + rockchip_i2s_clear(i2s); |
|---|
| 222 | 201 | } |
|---|
| 223 | 202 | } |
|---|
| 224 | | - spin_unlock(&lock); |
|---|
| 203 | + spin_unlock(&i2s->lock); |
|---|
| 225 | 204 | } |
|---|
| 226 | 205 | |
|---|
| 227 | 206 | static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
|---|
| .. | .. |
|---|
| 343 | 322 | |
|---|
| 344 | 323 | if (i2s->is_master_mode) { |
|---|
| 345 | 324 | mclk_rate = clk_get_rate(i2s->mclk); |
|---|
| 346 | | - bclk_rate = i2s->bclk_fs * params_rate(params); |
|---|
| 325 | + bclk_rate = i2s->bclk_ratio * params_rate(params); |
|---|
| 347 | 326 | if (!bclk_rate) |
|---|
| 348 | 327 | return -EINVAL; |
|---|
| 349 | 328 | |
|---|
| .. | .. |
|---|
| 471 | 450 | return ret; |
|---|
| 472 | 451 | } |
|---|
| 473 | 452 | |
|---|
| 453 | +static int rockchip_i2s_set_bclk_ratio(struct snd_soc_dai *dai, |
|---|
| 454 | + unsigned int ratio) |
|---|
| 455 | +{ |
|---|
| 456 | + struct rk_i2s_dev *i2s = to_info(dai); |
|---|
| 457 | + |
|---|
| 458 | + i2s->bclk_ratio = ratio; |
|---|
| 459 | + |
|---|
| 460 | + return 0; |
|---|
| 461 | +} |
|---|
| 462 | + |
|---|
| 474 | 463 | static int rockchip_i2s_clk_set_rate(struct rk_i2s_dev *i2s, |
|---|
| 475 | 464 | struct clk *clk, unsigned long rate, |
|---|
| 476 | 465 | int ppm) |
|---|
| .. | .. |
|---|
| 510 | 499 | unsigned int root_rate, div, delta; |
|---|
| 511 | 500 | uint64_t ppm; |
|---|
| 512 | 501 | int ret; |
|---|
| 502 | + |
|---|
| 503 | + if (rate == 0) |
|---|
| 504 | + return 0; |
|---|
| 513 | 505 | |
|---|
| 514 | 506 | if (i2s->mclk_calibrate) { |
|---|
| 515 | 507 | ret = rockchip_i2s_clk_set_rate(i2s, i2s->mclk_root, |
|---|
| .. | .. |
|---|
| 591 | 583 | { |
|---|
| 592 | 584 | struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); |
|---|
| 593 | 585 | |
|---|
| 594 | | - dai->capture_dma_data = &i2s->capture_dma_data; |
|---|
| 595 | | - dai->playback_dma_data = &i2s->playback_dma_data; |
|---|
| 586 | + snd_soc_dai_init_dma_data(dai, |
|---|
| 587 | + i2s->has_playback ? &i2s->playback_dma_data : NULL, |
|---|
| 588 | + i2s->has_capture ? &i2s->capture_dma_data : NULL); |
|---|
| 596 | 589 | |
|---|
| 597 | 590 | if (i2s->mclk_calibrate) |
|---|
| 598 | 591 | snd_soc_add_dai_controls(dai, &rockchip_i2s_compensation_control, 1); |
|---|
| .. | .. |
|---|
| 602 | 595 | |
|---|
| 603 | 596 | static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { |
|---|
| 604 | 597 | .hw_params = rockchip_i2s_hw_params, |
|---|
| 598 | + .set_bclk_ratio = rockchip_i2s_set_bclk_ratio, |
|---|
| 605 | 599 | .set_sysclk = rockchip_i2s_set_sysclk, |
|---|
| 606 | 600 | .set_fmt = rockchip_i2s_set_fmt, |
|---|
| 607 | 601 | .trigger = rockchip_i2s_trigger, |
|---|
| .. | .. |
|---|
| 609 | 603 | |
|---|
| 610 | 604 | static struct snd_soc_dai_driver rockchip_i2s_dai = { |
|---|
| 611 | 605 | .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 | 606 | .ops = &rockchip_i2s_dai_ops, |
|---|
| 635 | 607 | }; |
|---|
| 636 | 608 | |
|---|
| .. | .. |
|---|
| 726 | 698 | .shift = 11, |
|---|
| 727 | 699 | }; |
|---|
| 728 | 700 | |
|---|
| 729 | | -static const struct of_device_id rockchip_i2s_match[] = { |
|---|
| 701 | +static const struct of_device_id rockchip_i2s_match[] __maybe_unused = { |
|---|
| 730 | 702 | #ifdef CONFIG_CPU_PX30 |
|---|
| 731 | 703 | { .compatible = "rockchip,px30-i2s", }, |
|---|
| 732 | 704 | #endif |
|---|
| .. | .. |
|---|
| 743 | 715 | #ifdef CONFIG_CPU_RK3188 |
|---|
| 744 | 716 | { .compatible = "rockchip,rk3188-i2s", }, |
|---|
| 745 | 717 | #endif |
|---|
| 718 | +#ifdef CONFIG_CPU_RK322X |
|---|
| 719 | + { .compatible = "rockchip,rk3228-i2s", }, |
|---|
| 720 | +#endif |
|---|
| 746 | 721 | #ifdef CONFIG_CPU_RK3288 |
|---|
| 747 | 722 | { .compatible = "rockchip,rk3288-i2s", }, |
|---|
| 748 | 723 | #endif |
|---|
| .. | .. |
|---|
| 751 | 726 | #endif |
|---|
| 752 | 727 | #ifdef CONFIG_CPU_RK3328 |
|---|
| 753 | 728 | { .compatible = "rockchip,rk3328-i2s", }, |
|---|
| 729 | +#endif |
|---|
| 730 | +#ifdef CONFIG_CPU_RK3366 |
|---|
| 731 | + { .compatible = "rockchip,rk3366-i2s", }, |
|---|
| 754 | 732 | #endif |
|---|
| 755 | 733 | #ifdef CONFIG_CPU_RK3368 |
|---|
| 756 | 734 | { .compatible = "rockchip,rk3368-i2s", }, |
|---|
| .. | .. |
|---|
| 764 | 742 | {}, |
|---|
| 765 | 743 | }; |
|---|
| 766 | 744 | |
|---|
| 745 | +static int rockchip_i2s_init_dai(struct rk_i2s_dev *i2s, struct resource *res, |
|---|
| 746 | + struct snd_soc_dai_driver **dp) |
|---|
| 747 | +{ |
|---|
| 748 | + struct device_node *node = i2s->dev->of_node; |
|---|
| 749 | + struct snd_soc_dai_driver *dai; |
|---|
| 750 | + struct property *dma_names; |
|---|
| 751 | + const char *dma_name; |
|---|
| 752 | + unsigned int val; |
|---|
| 753 | + |
|---|
| 754 | + of_property_for_each_string(node, "dma-names", dma_names, dma_name) { |
|---|
| 755 | + if (!strcmp(dma_name, "tx")) |
|---|
| 756 | + i2s->has_playback = true; |
|---|
| 757 | + if (!strcmp(dma_name, "rx")) |
|---|
| 758 | + i2s->has_capture = true; |
|---|
| 759 | + } |
|---|
| 760 | + |
|---|
| 761 | + dai = devm_kmemdup(i2s->dev, &rockchip_i2s_dai, |
|---|
| 762 | + sizeof(*dai), GFP_KERNEL); |
|---|
| 763 | + if (!dai) |
|---|
| 764 | + return -ENOMEM; |
|---|
| 765 | + |
|---|
| 766 | + if (i2s->has_playback) { |
|---|
| 767 | + dai->playback.stream_name = "Playback"; |
|---|
| 768 | + dai->playback.channels_min = 2; |
|---|
| 769 | + dai->playback.channels_max = 8; |
|---|
| 770 | + dai->playback.rates = SNDRV_PCM_RATE_8000_192000; |
|---|
| 771 | + dai->playback.formats = SNDRV_PCM_FMTBIT_S8 | |
|---|
| 772 | + SNDRV_PCM_FMTBIT_S16_LE | |
|---|
| 773 | + SNDRV_PCM_FMTBIT_S20_3LE | |
|---|
| 774 | + SNDRV_PCM_FMTBIT_S24_LE | |
|---|
| 775 | + SNDRV_PCM_FMTBIT_S32_LE; |
|---|
| 776 | + |
|---|
| 777 | + i2s->playback_dma_data.addr = res->start + I2S_TXDR; |
|---|
| 778 | + i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
|---|
| 779 | + i2s->playback_dma_data.maxburst = 8; |
|---|
| 780 | + |
|---|
| 781 | + if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { |
|---|
| 782 | + if (val >= 2 && val <= 8) |
|---|
| 783 | + dai->playback.channels_max = val; |
|---|
| 784 | + } |
|---|
| 785 | + } |
|---|
| 786 | + |
|---|
| 787 | + if (i2s->has_capture) { |
|---|
| 788 | + dai->capture.stream_name = "Capture"; |
|---|
| 789 | + dai->capture.channels_min = 2; |
|---|
| 790 | + dai->capture.channels_max = 8; |
|---|
| 791 | + dai->capture.rates = SNDRV_PCM_RATE_8000_192000; |
|---|
| 792 | + dai->capture.formats = SNDRV_PCM_FMTBIT_S8 | |
|---|
| 793 | + SNDRV_PCM_FMTBIT_S16_LE | |
|---|
| 794 | + SNDRV_PCM_FMTBIT_S20_3LE | |
|---|
| 795 | + SNDRV_PCM_FMTBIT_S24_LE | |
|---|
| 796 | + SNDRV_PCM_FMTBIT_S32_LE; |
|---|
| 797 | + |
|---|
| 798 | + i2s->capture_dma_data.addr = res->start + I2S_RXDR; |
|---|
| 799 | + i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
|---|
| 800 | + i2s->capture_dma_data.maxburst = 8; |
|---|
| 801 | + |
|---|
| 802 | + if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { |
|---|
| 803 | + if (val >= 2 && val <= 8) |
|---|
| 804 | + dai->capture.channels_max = val; |
|---|
| 805 | + } |
|---|
| 806 | + } |
|---|
| 807 | + |
|---|
| 808 | + i2s->clk_trcm = I2S_CKR_TRCM_TXRX; |
|---|
| 809 | + if (!of_property_read_u32(node, "rockchip,clk-trcm", &val)) { |
|---|
| 810 | + if (val >= 0 && val <= 2) { |
|---|
| 811 | + i2s->clk_trcm = val << I2S_CKR_TRCM_SHIFT; |
|---|
| 812 | + if (i2s->clk_trcm) |
|---|
| 813 | + dai->symmetric_rates = 1; |
|---|
| 814 | + } |
|---|
| 815 | + } |
|---|
| 816 | + |
|---|
| 817 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 818 | + I2S_CKR_TRCM_MASK, i2s->clk_trcm); |
|---|
| 819 | + |
|---|
| 820 | + if (dp) |
|---|
| 821 | + *dp = dai; |
|---|
| 822 | + |
|---|
| 823 | + return 0; |
|---|
| 824 | +} |
|---|
| 825 | + |
|---|
| 767 | 826 | static int rockchip_i2s_probe(struct platform_device *pdev) |
|---|
| 768 | 827 | { |
|---|
| 769 | 828 | struct device_node *node = pdev->dev.of_node; |
|---|
| 770 | 829 | const struct of_device_id *of_id; |
|---|
| 771 | 830 | struct rk_i2s_dev *i2s; |
|---|
| 772 | | - struct snd_soc_dai_driver *soc_dai; |
|---|
| 831 | + struct snd_soc_dai_driver *dai; |
|---|
| 773 | 832 | struct resource *res; |
|---|
| 774 | 833 | void __iomem *regs; |
|---|
| 775 | 834 | int ret; |
|---|
| 776 | | - int val; |
|---|
| 777 | 835 | |
|---|
| 778 | 836 | i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); |
|---|
| 779 | 837 | if (!i2s) |
|---|
| 780 | 838 | return -ENOMEM; |
|---|
| 781 | 839 | |
|---|
| 840 | + spin_lock_init(&i2s->lock); |
|---|
| 782 | 841 | i2s->dev = &pdev->dev; |
|---|
| 783 | 842 | |
|---|
| 784 | 843 | i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); |
|---|
| .. | .. |
|---|
| 790 | 849 | i2s->pins = of_id->data; |
|---|
| 791 | 850 | } |
|---|
| 792 | 851 | |
|---|
| 793 | | - i2s->reset_m = devm_reset_control_get(&pdev->dev, "reset-m"); |
|---|
| 794 | | - i2s->reset_h = devm_reset_control_get(&pdev->dev, "reset-h"); |
|---|
| 852 | + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
|---|
| 853 | + if (IS_ERR(regs)) |
|---|
| 854 | + return PTR_ERR(regs); |
|---|
| 855 | + |
|---|
| 856 | + i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, |
|---|
| 857 | + &rockchip_i2s_regmap_config); |
|---|
| 858 | + if (IS_ERR(i2s->regmap)) { |
|---|
| 859 | + dev_err(&pdev->dev, |
|---|
| 860 | + "Failed to initialise managed register map\n"); |
|---|
| 861 | + return PTR_ERR(i2s->regmap); |
|---|
| 862 | + } |
|---|
| 863 | + |
|---|
| 864 | + i2s->bclk_ratio = 64; |
|---|
| 865 | + |
|---|
| 866 | + dev_set_drvdata(&pdev->dev, i2s); |
|---|
| 795 | 867 | |
|---|
| 796 | 868 | i2s->mclk_calibrate = |
|---|
| 797 | 869 | of_property_read_bool(node, "rockchip,mclk-calibrate"); |
|---|
| .. | .. |
|---|
| 802 | 874 | |
|---|
| 803 | 875 | i2s->mclk_root_initial_rate = clk_get_rate(i2s->mclk_root); |
|---|
| 804 | 876 | i2s->mclk_root_rate = i2s->mclk_root_initial_rate; |
|---|
| 877 | + } |
|---|
| 878 | + |
|---|
| 879 | + i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); |
|---|
| 880 | + if (IS_ERR(i2s->mclk)) { |
|---|
| 881 | + dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); |
|---|
| 882 | + return PTR_ERR(i2s->mclk); |
|---|
| 805 | 883 | } |
|---|
| 806 | 884 | |
|---|
| 807 | 885 | /* try to prepare related clocks */ |
|---|
| .. | .. |
|---|
| 816 | 894 | return ret; |
|---|
| 817 | 895 | } |
|---|
| 818 | 896 | |
|---|
| 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); |
|---|
| 823 | | - } |
|---|
| 824 | | - |
|---|
| 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 | | - |
|---|
| 848 | 897 | pm_runtime_enable(&pdev->dev); |
|---|
| 849 | 898 | if (!pm_runtime_enabled(&pdev->dev)) { |
|---|
| 850 | 899 | ret = i2s_runtime_resume(&pdev->dev); |
|---|
| .. | .. |
|---|
| 852 | 901 | goto err_pm_disable; |
|---|
| 853 | 902 | } |
|---|
| 854 | 903 | |
|---|
| 855 | | - soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai, |
|---|
| 856 | | - sizeof(*soc_dai), GFP_KERNEL); |
|---|
| 857 | | - if (!soc_dai) { |
|---|
| 858 | | - ret = -ENOMEM; |
|---|
| 904 | + ret = rockchip_i2s_init_dai(i2s, res, &dai); |
|---|
| 905 | + if (ret) |
|---|
| 859 | 906 | 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 | 907 | |
|---|
| 895 | 908 | ret = devm_snd_soc_register_component(&pdev->dev, |
|---|
| 896 | 909 | &rockchip_i2s_component, |
|---|
| 897 | | - soc_dai, 1); |
|---|
| 910 | + dai, 1); |
|---|
| 898 | 911 | |
|---|
| 899 | 912 | if (ret) { |
|---|
| 900 | 913 | dev_err(&pdev->dev, "Could not register DAI\n"); |
|---|
| 901 | 914 | goto err_suspend; |
|---|
| 902 | 915 | } |
|---|
| 903 | 916 | |
|---|
| 904 | | - if (of_property_read_bool(node, "rockchip,no-dmaengine")) |
|---|
| 905 | | - return ret; |
|---|
| 917 | + if (of_property_read_bool(node, "rockchip,no-dmaengine")) { |
|---|
| 918 | + dev_info(&pdev->dev, "Used for Multi-DAI\n"); |
|---|
| 919 | + return 0; |
|---|
| 920 | + } |
|---|
| 921 | + |
|---|
| 906 | 922 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
|---|
| 907 | 923 | if (ret) { |
|---|
| 908 | 924 | dev_err(&pdev->dev, "Could not register PCM\n"); |
|---|
| .. | .. |
|---|
| 917 | 933 | err_pm_disable: |
|---|
| 918 | 934 | pm_runtime_disable(&pdev->dev); |
|---|
| 919 | 935 | |
|---|
| 936 | + clk_disable_unprepare(i2s->hclk); |
|---|
| 937 | + |
|---|
| 920 | 938 | return ret; |
|---|
| 921 | 939 | } |
|---|
| 922 | 940 | |
|---|