| .. | .. |
|---|
| 61 | 61 | bool is_master_mode; |
|---|
| 62 | 62 | const struct rk_i2s_pins *pins; |
|---|
| 63 | 63 | unsigned int bclk_fs; |
|---|
| 64 | + spinlock_t lock; /* tx/rx lock */ |
|---|
| 64 | 65 | unsigned int clk_trcm; |
|---|
| 65 | 66 | |
|---|
| 66 | 67 | unsigned int mclk_root_rate; |
|---|
| .. | .. |
|---|
| 69 | 70 | bool mclk_calibrate; |
|---|
| 70 | 71 | |
|---|
| 71 | 72 | }; |
|---|
| 72 | | - |
|---|
| 73 | | -/* txctrl/rxctrl lock */ |
|---|
| 74 | | -static DEFINE_SPINLOCK(lock); |
|---|
| 75 | 73 | |
|---|
| 76 | 74 | static int i2s_runtime_suspend(struct device *dev) |
|---|
| 77 | 75 | { |
|---|
| .. | .. |
|---|
| 124 | 122 | regcache_sync(i2s->regmap); |
|---|
| 125 | 123 | } |
|---|
| 126 | 124 | |
|---|
| 125 | +static int rockchip_i2s_clear(struct rk_i2s_dev *i2s) |
|---|
| 126 | +{ |
|---|
| 127 | + unsigned int clr = I2S_CLR_TXC | I2S_CLR_RXC; |
|---|
| 128 | + unsigned int val = 0; |
|---|
| 129 | + int ret; |
|---|
| 130 | + |
|---|
| 131 | + /* |
|---|
| 132 | + * Workaround for FIFO clear on SLAVE mode: |
|---|
| 133 | + * |
|---|
| 134 | + * A Suggest to do reset hclk domain and then do mclk |
|---|
| 135 | + * domain, especially for SLAVE mode without CLK in. |
|---|
| 136 | + * at last, recovery regmap config. |
|---|
| 137 | + * |
|---|
| 138 | + * B Suggest to switch to MASTER, and then do FIFO clr, |
|---|
| 139 | + * at last, bring back to SLAVE. |
|---|
| 140 | + * |
|---|
| 141 | + * Now we choose plan B here. |
|---|
| 142 | + */ |
|---|
| 143 | + if (!i2s->is_master_mode) |
|---|
| 144 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 145 | + I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER); |
|---|
| 146 | + regmap_update_bits(i2s->regmap, I2S_CLR, clr, clr); |
|---|
| 147 | + |
|---|
| 148 | + ret = regmap_read_poll_timeout_atomic(i2s->regmap, I2S_CLR, val, |
|---|
| 149 | + !(val & clr), 10, 100); |
|---|
| 150 | + if (!i2s->is_master_mode) |
|---|
| 151 | + regmap_update_bits(i2s->regmap, I2S_CKR, |
|---|
| 152 | + I2S_CKR_MSS_MASK, I2S_CKR_MSS_SLAVE); |
|---|
| 153 | + if (ret < 0) { |
|---|
| 154 | + dev_warn(i2s->dev, "failed to clear fifo on %s mode\n", |
|---|
| 155 | + i2s->is_master_mode ? "master" : "slave"); |
|---|
| 156 | + goto reset; |
|---|
| 157 | + } |
|---|
| 158 | + |
|---|
| 159 | + return 0; |
|---|
| 160 | + |
|---|
| 161 | +reset: |
|---|
| 162 | + rockchip_i2s_reset(i2s); |
|---|
| 163 | + |
|---|
| 164 | + return ret; |
|---|
| 165 | +} |
|---|
| 166 | + |
|---|
| 127 | 167 | static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) |
|---|
| 128 | 168 | { |
|---|
| 129 | | - unsigned int val = 0; |
|---|
| 130 | | - int retry = 10; |
|---|
| 131 | | - |
|---|
| 132 | | - spin_lock(&lock); |
|---|
| 169 | + spin_lock(&i2s->lock); |
|---|
| 133 | 170 | if (on) { |
|---|
| 134 | 171 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
|---|
| 135 | 172 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); |
|---|
| .. | .. |
|---|
| 153 | 190 | I2S_XFER_RXS_STOP); |
|---|
| 154 | 191 | |
|---|
| 155 | 192 | 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 | | - } |
|---|
| 193 | + rockchip_i2s_clear(i2s); |
|---|
| 172 | 194 | } |
|---|
| 173 | 195 | } |
|---|
| 174 | | - spin_unlock(&lock); |
|---|
| 196 | + spin_unlock(&i2s->lock); |
|---|
| 175 | 197 | } |
|---|
| 176 | 198 | |
|---|
| 177 | 199 | static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) |
|---|
| 178 | 200 | { |
|---|
| 179 | | - unsigned int val = 0; |
|---|
| 180 | | - int retry = 10; |
|---|
| 181 | | - |
|---|
| 182 | | - spin_lock(&lock); |
|---|
| 201 | + spin_lock(&i2s->lock); |
|---|
| 183 | 202 | if (on) { |
|---|
| 184 | 203 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
|---|
| 185 | 204 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); |
|---|
| .. | .. |
|---|
| 203 | 222 | I2S_XFER_RXS_STOP); |
|---|
| 204 | 223 | |
|---|
| 205 | 224 | 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 | | - } |
|---|
| 225 | + rockchip_i2s_clear(i2s); |
|---|
| 222 | 226 | } |
|---|
| 223 | 227 | } |
|---|
| 224 | | - spin_unlock(&lock); |
|---|
| 228 | + spin_unlock(&i2s->lock); |
|---|
| 225 | 229 | } |
|---|
| 226 | 230 | |
|---|
| 227 | 231 | static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
|---|
| .. | .. |
|---|
| 779 | 783 | if (!i2s) |
|---|
| 780 | 784 | return -ENOMEM; |
|---|
| 781 | 785 | |
|---|
| 786 | + spin_lock_init(&i2s->lock); |
|---|
| 782 | 787 | i2s->dev = &pdev->dev; |
|---|
| 783 | 788 | |
|---|
| 784 | 789 | i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); |
|---|
| .. | .. |
|---|
| 819 | 824 | i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); |
|---|
| 820 | 825 | if (IS_ERR(i2s->mclk)) { |
|---|
| 821 | 826 | dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); |
|---|
| 822 | | - return PTR_ERR(i2s->mclk); |
|---|
| 827 | + ret = PTR_ERR(i2s->mclk); |
|---|
| 828 | + goto err_clk; |
|---|
| 823 | 829 | } |
|---|
| 824 | 830 | |
|---|
| 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); |
|---|
| 831 | + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
|---|
| 832 | + if (IS_ERR(regs)) { |
|---|
| 833 | + ret = PTR_ERR(regs); |
|---|
| 834 | + goto err_clk; |
|---|
| 835 | + } |
|---|
| 829 | 836 | |
|---|
| 830 | 837 | i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, |
|---|
| 831 | 838 | &rockchip_i2s_regmap_config); |
|---|
| 832 | 839 | if (IS_ERR(i2s->regmap)) { |
|---|
| 833 | 840 | dev_err(&pdev->dev, |
|---|
| 834 | 841 | "Failed to initialise managed register map\n"); |
|---|
| 835 | | - return PTR_ERR(i2s->regmap); |
|---|
| 842 | + ret = PTR_ERR(i2s->regmap); |
|---|
| 843 | + goto err_clk; |
|---|
| 836 | 844 | } |
|---|
| 837 | 845 | |
|---|
| 838 | 846 | i2s->playback_dma_data.addr = res->start + I2S_TXDR; |
|---|
| .. | .. |
|---|
| 901 | 909 | goto err_suspend; |
|---|
| 902 | 910 | } |
|---|
| 903 | 911 | |
|---|
| 904 | | - if (of_property_read_bool(node, "rockchip,no-dmaengine")) |
|---|
| 905 | | - return ret; |
|---|
| 912 | + if (of_property_read_bool(node, "rockchip,no-dmaengine")) { |
|---|
| 913 | + dev_info(&pdev->dev, "Used for Multi-DAI\n"); |
|---|
| 914 | + return 0; |
|---|
| 915 | + } |
|---|
| 916 | + |
|---|
| 906 | 917 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
|---|
| 907 | 918 | if (ret) { |
|---|
| 908 | 919 | dev_err(&pdev->dev, "Could not register PCM\n"); |
|---|
| .. | .. |
|---|
| 916 | 927 | i2s_runtime_suspend(&pdev->dev); |
|---|
| 917 | 928 | err_pm_disable: |
|---|
| 918 | 929 | pm_runtime_disable(&pdev->dev); |
|---|
| 919 | | - |
|---|
| 930 | +err_clk: |
|---|
| 931 | + clk_disable_unprepare(i2s->hclk); |
|---|
| 920 | 932 | return ret; |
|---|
| 921 | 933 | } |
|---|
| 922 | 934 | |
|---|