| .. | .. |
|---|
| 10 | 10 | |
|---|
| 11 | 11 | struct rsnd_ssiu { |
|---|
| 12 | 12 | struct rsnd_mod mod; |
|---|
| 13 | + u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ |
|---|
| 14 | + unsigned int usrcnt; |
|---|
| 15 | + int id; |
|---|
| 16 | + int id_sub; |
|---|
| 13 | 17 | }; |
|---|
| 14 | 18 | |
|---|
| 19 | +/* SSI_MODE */ |
|---|
| 20 | +#define TDM_EXT (1 << 0) |
|---|
| 21 | +#define TDM_SPLIT (1 << 8) |
|---|
| 22 | + |
|---|
| 15 | 23 | #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) |
|---|
| 24 | +#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) |
|---|
| 16 | 25 | #define for_each_rsnd_ssiu(pos, priv, i) \ |
|---|
| 17 | 26 | for (i = 0; \ |
|---|
| 18 | 27 | (i < rsnd_ssiu_nr(priv)) && \ |
|---|
| 19 | 28 | ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ |
|---|
| 20 | 29 | i++) |
|---|
| 21 | 30 | |
|---|
| 31 | +/* |
|---|
| 32 | + * SSI Gen2 Gen3 |
|---|
| 33 | + * 0 BUSIF0-3 BUSIF0-7 |
|---|
| 34 | + * 1 BUSIF0-3 BUSIF0-7 |
|---|
| 35 | + * 2 BUSIF0-3 BUSIF0-7 |
|---|
| 36 | + * 3 BUSIF0 BUSIF0-7 |
|---|
| 37 | + * 4 BUSIF0 BUSIF0-7 |
|---|
| 38 | + * 5 BUSIF0 BUSIF0 |
|---|
| 39 | + * 6 BUSIF0 BUSIF0 |
|---|
| 40 | + * 7 BUSIF0 BUSIF0 |
|---|
| 41 | + * 8 BUSIF0 BUSIF0 |
|---|
| 42 | + * 9 BUSIF0-3 BUSIF0-7 |
|---|
| 43 | + * total 22 52 |
|---|
| 44 | + */ |
|---|
| 45 | +static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; |
|---|
| 46 | +static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; |
|---|
| 47 | + |
|---|
| 48 | +static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, |
|---|
| 49 | + struct rsnd_dai_stream *io, |
|---|
| 50 | + enum rsnd_mod_type type) |
|---|
| 51 | +{ |
|---|
| 52 | + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
|---|
| 53 | + int busif = rsnd_mod_id_sub(mod); |
|---|
| 54 | + |
|---|
| 55 | + return &ssiu->busif_status[busif]; |
|---|
| 56 | +} |
|---|
| 57 | + |
|---|
| 22 | 58 | static int rsnd_ssiu_init(struct rsnd_mod *mod, |
|---|
| 23 | 59 | struct rsnd_dai_stream *io, |
|---|
| 24 | 60 | struct rsnd_priv *priv) |
|---|
| 25 | 61 | { |
|---|
| 26 | 62 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
|---|
| 27 | | - u32 multi_ssi_slaves = rsnd_ssi_multi_slaves_runtime(io); |
|---|
| 63 | + u32 ssis = rsnd_ssi_multi_secondaries_runtime(io); |
|---|
| 28 | 64 | int use_busif = rsnd_ssi_use_busif(io); |
|---|
| 29 | 65 | int id = rsnd_mod_id(mod); |
|---|
| 30 | | - u32 mask1, val1; |
|---|
| 31 | | - u32 mask2, val2; |
|---|
| 66 | + int is_clk_master = rsnd_rdai_is_clk_master(rdai); |
|---|
| 67 | + u32 val1, val2; |
|---|
| 68 | + int i; |
|---|
| 32 | 69 | |
|---|
| 33 | 70 | /* clear status */ |
|---|
| 34 | 71 | switch (id) { |
|---|
| .. | .. |
|---|
| 37 | 74 | case 2: |
|---|
| 38 | 75 | case 3: |
|---|
| 39 | 76 | case 4: |
|---|
| 40 | | - rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4)); |
|---|
| 41 | | - rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4)); |
|---|
| 42 | | - rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4)); |
|---|
| 43 | | - rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4)); |
|---|
| 77 | + for (i = 0; i < 4; i++) |
|---|
| 78 | + rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4)); |
|---|
| 44 | 79 | break; |
|---|
| 45 | 80 | case 9: |
|---|
| 46 | | - rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4); |
|---|
| 47 | | - rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4); |
|---|
| 48 | | - rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4); |
|---|
| 49 | | - rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4); |
|---|
| 81 | + for (i = 0; i < 4; i++) |
|---|
| 82 | + rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4); |
|---|
| 50 | 83 | break; |
|---|
| 51 | 84 | } |
|---|
| 52 | 85 | |
|---|
| .. | .. |
|---|
| 56 | 89 | rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); |
|---|
| 57 | 90 | |
|---|
| 58 | 91 | /* |
|---|
| 59 | | - * SSI_MODE1 |
|---|
| 92 | + * SSI_MODE1 / SSI_MODE2 |
|---|
| 93 | + * |
|---|
| 94 | + * FIXME |
|---|
| 95 | + * sharing/multi with SSI0 are mainly supported |
|---|
| 60 | 96 | */ |
|---|
| 61 | | - mask1 = (1 << 4) | (1 << 20); /* mask sync bit */ |
|---|
| 62 | | - mask2 = (1 << 4); /* mask sync bit */ |
|---|
| 63 | | - val1 = val2 = 0; |
|---|
| 64 | | - if (id == 8) { |
|---|
| 97 | + val1 = rsnd_mod_read(mod, SSI_MODE1); |
|---|
| 98 | + val2 = rsnd_mod_read(mod, SSI_MODE2); |
|---|
| 99 | + if (rsnd_ssi_is_pin_sharing(io)) { |
|---|
| 100 | + |
|---|
| 101 | + ssis |= (1 << id); |
|---|
| 102 | + |
|---|
| 103 | + } else if (ssis) { |
|---|
| 65 | 104 | /* |
|---|
| 66 | | - * SSI8 pin is sharing with SSI7, nothing to do. |
|---|
| 105 | + * Multi SSI |
|---|
| 106 | + * |
|---|
| 107 | + * set synchronized bit here |
|---|
| 67 | 108 | */ |
|---|
| 68 | | - } else if (rsnd_ssi_is_pin_sharing(io)) { |
|---|
| 69 | | - int shift = -1; |
|---|
| 70 | 109 | |
|---|
| 71 | | - switch (id) { |
|---|
| 72 | | - case 1: |
|---|
| 73 | | - shift = 0; |
|---|
| 74 | | - break; |
|---|
| 75 | | - case 2: |
|---|
| 76 | | - shift = 2; |
|---|
| 77 | | - break; |
|---|
| 78 | | - case 4: |
|---|
| 79 | | - shift = 16; |
|---|
| 80 | | - break; |
|---|
| 81 | | - default: |
|---|
| 82 | | - return -EINVAL; |
|---|
| 83 | | - } |
|---|
| 84 | | - |
|---|
| 85 | | - mask1 |= 0x3 << shift; |
|---|
| 86 | | - val1 = rsnd_rdai_is_clk_master(rdai) ? |
|---|
| 87 | | - 0x2 << shift : 0x1 << shift; |
|---|
| 88 | | - |
|---|
| 89 | | - } else if (multi_ssi_slaves) { |
|---|
| 90 | | - |
|---|
| 91 | | - mask2 |= 0x00000007; |
|---|
| 92 | | - mask1 |= 0x0000000f; |
|---|
| 93 | | - |
|---|
| 94 | | - switch (multi_ssi_slaves) { |
|---|
| 95 | | - case 0x0206: /* SSI0/1/2/9 */ |
|---|
| 96 | | - val2 = (1 << 4) | /* SSI0129 sync */ |
|---|
| 97 | | - (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1); |
|---|
| 98 | | - /* fall through */ |
|---|
| 99 | | - case 0x0006: /* SSI0/1/2 */ |
|---|
| 100 | | - val1 = rsnd_rdai_is_clk_master(rdai) ? |
|---|
| 101 | | - 0xa : 0x5; |
|---|
| 102 | | - |
|---|
| 103 | | - if (!val2) /* SSI012 sync */ |
|---|
| 104 | | - val1 |= (1 << 4); |
|---|
| 105 | | - } |
|---|
| 110 | + /* SSI4 is synchronized with SSI3 */ |
|---|
| 111 | + if (ssis & (1 << 4)) |
|---|
| 112 | + val1 |= (1 << 20); |
|---|
| 113 | + /* SSI012 are synchronized */ |
|---|
| 114 | + if (ssis == 0x0006) |
|---|
| 115 | + val1 |= (1 << 4); |
|---|
| 116 | + /* SSI0129 are synchronized */ |
|---|
| 117 | + if (ssis == 0x0206) |
|---|
| 118 | + val2 |= (1 << 4); |
|---|
| 106 | 119 | } |
|---|
| 107 | 120 | |
|---|
| 108 | | - rsnd_mod_bset(mod, SSI_MODE1, mask1, val1); |
|---|
| 109 | | - rsnd_mod_bset(mod, SSI_MODE2, mask2, val2); |
|---|
| 121 | + /* SSI1 is sharing pin with SSI0 */ |
|---|
| 122 | + if (ssis & (1 << 1)) |
|---|
| 123 | + val1 |= is_clk_master ? 0x2 : 0x1; |
|---|
| 124 | + |
|---|
| 125 | + /* SSI2 is sharing pin with SSI0 */ |
|---|
| 126 | + if (ssis & (1 << 2)) |
|---|
| 127 | + val1 |= is_clk_master ? 0x2 << 2 : |
|---|
| 128 | + 0x1 << 2; |
|---|
| 129 | + /* SSI4 is sharing pin with SSI3 */ |
|---|
| 130 | + if (ssis & (1 << 4)) |
|---|
| 131 | + val1 |= is_clk_master ? 0x2 << 16 : |
|---|
| 132 | + 0x1 << 16; |
|---|
| 133 | + /* SSI9 is sharing pin with SSI0 */ |
|---|
| 134 | + if (ssis & (1 << 9)) |
|---|
| 135 | + val2 |= is_clk_master ? 0x2 : 0x1; |
|---|
| 136 | + |
|---|
| 137 | + rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); |
|---|
| 138 | + rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); |
|---|
| 110 | 139 | |
|---|
| 111 | 140 | return 0; |
|---|
| 112 | 141 | } |
|---|
| 113 | 142 | |
|---|
| 114 | 143 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { |
|---|
| 115 | | - .name = SSIU_NAME, |
|---|
| 116 | | - .init = rsnd_ssiu_init, |
|---|
| 144 | + .name = SSIU_NAME, |
|---|
| 145 | + .init = rsnd_ssiu_init, |
|---|
| 146 | + .get_status = rsnd_ssiu_get_status, |
|---|
| 117 | 147 | }; |
|---|
| 118 | 148 | |
|---|
| 119 | 149 | static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, |
|---|
| 120 | 150 | struct rsnd_dai_stream *io, |
|---|
| 121 | 151 | struct rsnd_priv *priv) |
|---|
| 122 | 152 | { |
|---|
| 123 | | - int hdmi = rsnd_ssi_hdmi_port(io); |
|---|
| 153 | + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
|---|
| 154 | + u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); |
|---|
| 155 | + u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); |
|---|
| 124 | 156 | int ret; |
|---|
| 125 | 157 | u32 mode = 0; |
|---|
| 126 | 158 | |
|---|
| .. | .. |
|---|
| 128 | 160 | if (ret < 0) |
|---|
| 129 | 161 | return ret; |
|---|
| 130 | 162 | |
|---|
| 131 | | - if (rsnd_runtime_is_ssi_tdm(io)) { |
|---|
| 132 | | - /* |
|---|
| 133 | | - * TDM Extend Mode |
|---|
| 134 | | - * see |
|---|
| 135 | | - * rsnd_ssi_config_init() |
|---|
| 136 | | - */ |
|---|
| 137 | | - mode = 0x1; |
|---|
| 138 | | - } |
|---|
| 163 | + ssiu->usrcnt++; |
|---|
| 164 | + |
|---|
| 165 | + /* |
|---|
| 166 | + * TDM Extend/Split Mode |
|---|
| 167 | + * see |
|---|
| 168 | + * rsnd_ssi_config_init() |
|---|
| 169 | + */ |
|---|
| 170 | + if (rsnd_runtime_is_tdm(io)) |
|---|
| 171 | + mode = TDM_EXT; |
|---|
| 172 | + else if (rsnd_runtime_is_tdm_split(io)) |
|---|
| 173 | + mode = TDM_SPLIT; |
|---|
| 139 | 174 | |
|---|
| 140 | 175 | rsnd_mod_write(mod, SSI_MODE, mode); |
|---|
| 141 | 176 | |
|---|
| 142 | 177 | if (rsnd_ssi_use_busif(io)) { |
|---|
| 143 | | - rsnd_mod_write(mod, SSI_BUSIF_ADINR, |
|---|
| 178 | + int id = rsnd_mod_id(mod); |
|---|
| 179 | + int busif = rsnd_mod_id_sub(mod); |
|---|
| 180 | + enum rsnd_reg adinr_reg, mode_reg, dalign_reg; |
|---|
| 181 | + |
|---|
| 182 | + if ((id == 9) && (busif >= 4)) { |
|---|
| 183 | + adinr_reg = SSI9_BUSIF_ADINR(busif); |
|---|
| 184 | + mode_reg = SSI9_BUSIF_MODE(busif); |
|---|
| 185 | + dalign_reg = SSI9_BUSIF_DALIGN(busif); |
|---|
| 186 | + } else { |
|---|
| 187 | + adinr_reg = SSI_BUSIF_ADINR(busif); |
|---|
| 188 | + mode_reg = SSI_BUSIF_MODE(busif); |
|---|
| 189 | + dalign_reg = SSI_BUSIF_DALIGN(busif); |
|---|
| 190 | + } |
|---|
| 191 | + |
|---|
| 192 | + rsnd_mod_write(mod, adinr_reg, |
|---|
| 144 | 193 | rsnd_get_adinr_bit(mod, io) | |
|---|
| 145 | 194 | (rsnd_io_is_play(io) ? |
|---|
| 146 | 195 | rsnd_runtime_channel_after_ctu(io) : |
|---|
| 147 | 196 | rsnd_runtime_channel_original(io))); |
|---|
| 148 | | - rsnd_mod_write(mod, SSI_BUSIF_MODE, |
|---|
| 197 | + rsnd_mod_write(mod, mode_reg, |
|---|
| 149 | 198 | rsnd_get_busif_shift(io, mod) | 1); |
|---|
| 150 | | - rsnd_mod_write(mod, SSI_BUSIF_DALIGN, |
|---|
| 199 | + rsnd_mod_write(mod, dalign_reg, |
|---|
| 151 | 200 | rsnd_get_dalign(mod, io)); |
|---|
| 152 | 201 | } |
|---|
| 153 | 202 | |
|---|
| 154 | | - if (hdmi) { |
|---|
| 203 | + if (has_hdmi0 || has_hdmi1) { |
|---|
| 155 | 204 | enum rsnd_mod_type rsnd_ssi_array[] = { |
|---|
| 156 | 205 | RSND_MOD_SSIM1, |
|---|
| 157 | 206 | RSND_MOD_SSIM2, |
|---|
| .. | .. |
|---|
| 177 | 226 | rsnd_mod_id(pos) << shift; |
|---|
| 178 | 227 | } |
|---|
| 179 | 228 | |
|---|
| 180 | | - switch (hdmi) { |
|---|
| 181 | | - case RSND_SSI_HDMI_PORT0: |
|---|
| 229 | + if (has_hdmi0) |
|---|
| 182 | 230 | rsnd_mod_write(mod, HDMI0_SEL, val); |
|---|
| 183 | | - break; |
|---|
| 184 | | - case RSND_SSI_HDMI_PORT1: |
|---|
| 231 | + if (has_hdmi1) |
|---|
| 185 | 232 | rsnd_mod_write(mod, HDMI1_SEL, val); |
|---|
| 186 | | - break; |
|---|
| 187 | | - } |
|---|
| 188 | 233 | } |
|---|
| 189 | 234 | |
|---|
| 190 | 235 | return 0; |
|---|
| .. | .. |
|---|
| 194 | 239 | struct rsnd_dai_stream *io, |
|---|
| 195 | 240 | struct rsnd_priv *priv) |
|---|
| 196 | 241 | { |
|---|
| 242 | + int busif = rsnd_mod_id_sub(mod); |
|---|
| 243 | + |
|---|
| 197 | 244 | if (!rsnd_ssi_use_busif(io)) |
|---|
| 198 | 245 | return 0; |
|---|
| 199 | 246 | |
|---|
| 200 | | - rsnd_mod_write(mod, SSI_CTRL, 0x1); |
|---|
| 247 | + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); |
|---|
| 201 | 248 | |
|---|
| 202 | | - if (rsnd_ssi_multi_slaves_runtime(io)) |
|---|
| 249 | + if (rsnd_ssi_multi_secondaries_runtime(io)) |
|---|
| 203 | 250 | rsnd_mod_write(mod, SSI_CONTROL, 0x1); |
|---|
| 204 | 251 | |
|---|
| 205 | 252 | return 0; |
|---|
| .. | .. |
|---|
| 209 | 256 | struct rsnd_dai_stream *io, |
|---|
| 210 | 257 | struct rsnd_priv *priv) |
|---|
| 211 | 258 | { |
|---|
| 259 | + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
|---|
| 260 | + int busif = rsnd_mod_id_sub(mod); |
|---|
| 261 | + |
|---|
| 212 | 262 | if (!rsnd_ssi_use_busif(io)) |
|---|
| 213 | 263 | return 0; |
|---|
| 214 | 264 | |
|---|
| 215 | | - rsnd_mod_write(mod, SSI_CTRL, 0); |
|---|
| 265 | + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); |
|---|
| 216 | 266 | |
|---|
| 217 | | - if (rsnd_ssi_multi_slaves_runtime(io)) |
|---|
| 267 | + if (--ssiu->usrcnt) |
|---|
| 268 | + return 0; |
|---|
| 269 | + |
|---|
| 270 | + if (rsnd_ssi_multi_secondaries_runtime(io)) |
|---|
| 218 | 271 | rsnd_mod_write(mod, SSI_CONTROL, 0); |
|---|
| 219 | 272 | |
|---|
| 220 | 273 | return 0; |
|---|
| 221 | 274 | } |
|---|
| 222 | 275 | |
|---|
| 276 | +static int rsnd_ssiu_id(struct rsnd_mod *mod) |
|---|
| 277 | +{ |
|---|
| 278 | + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
|---|
| 279 | + |
|---|
| 280 | + /* see rsnd_ssiu_probe() */ |
|---|
| 281 | + return ssiu->id; |
|---|
| 282 | +} |
|---|
| 283 | + |
|---|
| 284 | +static int rsnd_ssiu_id_sub(struct rsnd_mod *mod) |
|---|
| 285 | +{ |
|---|
| 286 | + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); |
|---|
| 287 | + |
|---|
| 288 | + /* see rsnd_ssiu_probe() */ |
|---|
| 289 | + return ssiu->id_sub; |
|---|
| 290 | +} |
|---|
| 291 | + |
|---|
| 292 | +static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, |
|---|
| 293 | + struct rsnd_mod *mod) |
|---|
| 294 | +{ |
|---|
| 295 | + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
|---|
| 296 | + int is_play = rsnd_io_is_play(io); |
|---|
| 297 | + char *name; |
|---|
| 298 | + |
|---|
| 299 | + /* |
|---|
| 300 | + * It should use "rcar_sound,ssiu" on DT. |
|---|
| 301 | + * But, we need to keep compatibility for old version. |
|---|
| 302 | + * |
|---|
| 303 | + * If it has "rcar_sound.ssiu", it will be used. |
|---|
| 304 | + * If not, "rcar_sound.ssi" will be used. |
|---|
| 305 | + * see |
|---|
| 306 | + * rsnd_ssi_dma_req() |
|---|
| 307 | + * rsnd_dma_of_path() |
|---|
| 308 | + */ |
|---|
| 309 | + |
|---|
| 310 | + name = is_play ? "rx" : "tx"; |
|---|
| 311 | + |
|---|
| 312 | + return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), |
|---|
| 313 | + mod, name); |
|---|
| 314 | +} |
|---|
| 315 | + |
|---|
| 223 | 316 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { |
|---|
| 224 | | - .name = SSIU_NAME, |
|---|
| 225 | | - .init = rsnd_ssiu_init_gen2, |
|---|
| 226 | | - .start = rsnd_ssiu_start_gen2, |
|---|
| 227 | | - .stop = rsnd_ssiu_stop_gen2, |
|---|
| 317 | + .name = SSIU_NAME, |
|---|
| 318 | + .dma_req = rsnd_ssiu_dma_req, |
|---|
| 319 | + .init = rsnd_ssiu_init_gen2, |
|---|
| 320 | + .start = rsnd_ssiu_start_gen2, |
|---|
| 321 | + .stop = rsnd_ssiu_stop_gen2, |
|---|
| 322 | + .get_status = rsnd_ssiu_get_status, |
|---|
| 228 | 323 | }; |
|---|
| 229 | 324 | |
|---|
| 230 | 325 | static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) |
|---|
| .. | .. |
|---|
| 235 | 330 | return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); |
|---|
| 236 | 331 | } |
|---|
| 237 | 332 | |
|---|
| 238 | | -int rsnd_ssiu_attach(struct rsnd_dai_stream *io, |
|---|
| 239 | | - struct rsnd_mod *ssi_mod) |
|---|
| 333 | +static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, |
|---|
| 334 | + struct rsnd_dai_stream *io) |
|---|
| 240 | 335 | { |
|---|
| 241 | | - struct rsnd_priv *priv = rsnd_io_to_priv(io); |
|---|
| 242 | | - struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod)); |
|---|
| 336 | + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); |
|---|
| 337 | + struct rsnd_mod *mod; |
|---|
| 338 | + struct rsnd_ssiu *ssiu; |
|---|
| 339 | + int i; |
|---|
| 243 | 340 | |
|---|
| 244 | | - rsnd_mod_confirm_ssi(ssi_mod); |
|---|
| 341 | + if (!ssi_mod) |
|---|
| 342 | + return; |
|---|
| 245 | 343 | |
|---|
| 246 | | - return rsnd_dai_connect(mod, io, mod->type); |
|---|
| 344 | + /* select BUSIF0 */ |
|---|
| 345 | + for_each_rsnd_ssiu(ssiu, priv, i) { |
|---|
| 346 | + mod = rsnd_mod_get(ssiu); |
|---|
| 347 | + |
|---|
| 348 | + if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && |
|---|
| 349 | + (rsnd_mod_id_sub(mod) == 0)) { |
|---|
| 350 | + rsnd_dai_connect(mod, io, mod->type); |
|---|
| 351 | + return; |
|---|
| 352 | + } |
|---|
| 353 | + } |
|---|
| 354 | +} |
|---|
| 355 | + |
|---|
| 356 | +void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, |
|---|
| 357 | + struct device_node *playback, |
|---|
| 358 | + struct device_node *capture) |
|---|
| 359 | +{ |
|---|
| 360 | + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
|---|
| 361 | + struct device_node *node = rsnd_ssiu_of_node(priv); |
|---|
| 362 | + struct device_node *np; |
|---|
| 363 | + struct rsnd_mod *mod; |
|---|
| 364 | + struct rsnd_dai_stream *io_p = &rdai->playback; |
|---|
| 365 | + struct rsnd_dai_stream *io_c = &rdai->capture; |
|---|
| 366 | + int i; |
|---|
| 367 | + |
|---|
| 368 | + /* use rcar_sound,ssiu if exist */ |
|---|
| 369 | + if (node) { |
|---|
| 370 | + i = 0; |
|---|
| 371 | + for_each_child_of_node(node, np) { |
|---|
| 372 | + mod = rsnd_ssiu_mod_get(priv, i); |
|---|
| 373 | + if (np == playback) |
|---|
| 374 | + rsnd_dai_connect(mod, io_p, mod->type); |
|---|
| 375 | + if (np == capture) |
|---|
| 376 | + rsnd_dai_connect(mod, io_c, mod->type); |
|---|
| 377 | + i++; |
|---|
| 378 | + } |
|---|
| 379 | + |
|---|
| 380 | + of_node_put(node); |
|---|
| 381 | + } |
|---|
| 382 | + |
|---|
| 383 | + /* Keep DT compatibility */ |
|---|
| 384 | + if (!rsnd_io_to_mod_ssiu(io_p)) |
|---|
| 385 | + rsnd_parse_connect_ssiu_compatible(priv, io_p); |
|---|
| 386 | + if (!rsnd_io_to_mod_ssiu(io_c)) |
|---|
| 387 | + rsnd_parse_connect_ssiu_compatible(priv, io_c); |
|---|
| 247 | 388 | } |
|---|
| 248 | 389 | |
|---|
| 249 | 390 | int rsnd_ssiu_probe(struct rsnd_priv *priv) |
|---|
| 250 | 391 | { |
|---|
| 251 | 392 | struct device *dev = rsnd_priv_to_dev(priv); |
|---|
| 393 | + struct device_node *node; |
|---|
| 252 | 394 | struct rsnd_ssiu *ssiu; |
|---|
| 253 | 395 | struct rsnd_mod_ops *ops; |
|---|
| 396 | + const int *list = NULL; |
|---|
| 254 | 397 | int i, nr, ret; |
|---|
| 255 | 398 | |
|---|
| 256 | | - /* same number to SSI */ |
|---|
| 257 | | - nr = priv->ssi_nr; |
|---|
| 399 | + /* |
|---|
| 400 | + * Keep DT compatibility. |
|---|
| 401 | + * if it has "rcar_sound,ssiu", use it. |
|---|
| 402 | + * if not, use "rcar_sound,ssi" |
|---|
| 403 | + * see |
|---|
| 404 | + * rsnd_ssiu_bufsif_to_id() |
|---|
| 405 | + */ |
|---|
| 406 | + node = rsnd_ssiu_of_node(priv); |
|---|
| 407 | + if (node) |
|---|
| 408 | + nr = of_get_child_count(node); |
|---|
| 409 | + else |
|---|
| 410 | + nr = priv->ssi_nr; |
|---|
| 411 | + |
|---|
| 258 | 412 | ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); |
|---|
| 259 | 413 | if (!ssiu) |
|---|
| 260 | 414 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 267 | 421 | else |
|---|
| 268 | 422 | ops = &rsnd_ssiu_ops_gen2; |
|---|
| 269 | 423 | |
|---|
| 424 | + /* Keep compatibility */ |
|---|
| 425 | + nr = 0; |
|---|
| 426 | + if ((node) && |
|---|
| 427 | + (ops == &rsnd_ssiu_ops_gen2)) { |
|---|
| 428 | + ops->id = rsnd_ssiu_id; |
|---|
| 429 | + ops->id_sub = rsnd_ssiu_id_sub; |
|---|
| 430 | + |
|---|
| 431 | + if (rsnd_is_gen2(priv)) { |
|---|
| 432 | + list = gen2_id; |
|---|
| 433 | + nr = ARRAY_SIZE(gen2_id); |
|---|
| 434 | + } else if (rsnd_is_gen3(priv)) { |
|---|
| 435 | + list = gen3_id; |
|---|
| 436 | + nr = ARRAY_SIZE(gen3_id); |
|---|
| 437 | + } else { |
|---|
| 438 | + dev_err(dev, "unknown SSIU\n"); |
|---|
| 439 | + return -ENODEV; |
|---|
| 440 | + } |
|---|
| 441 | + } |
|---|
| 442 | + |
|---|
| 270 | 443 | for_each_rsnd_ssiu(ssiu, priv, i) { |
|---|
| 444 | + if (node) { |
|---|
| 445 | + int j; |
|---|
| 446 | + |
|---|
| 447 | + /* |
|---|
| 448 | + * see |
|---|
| 449 | + * rsnd_ssiu_get_id() |
|---|
| 450 | + * rsnd_ssiu_get_id_sub() |
|---|
| 451 | + */ |
|---|
| 452 | + for (j = 0; j < nr; j++) { |
|---|
| 453 | + if (list[j] > i) |
|---|
| 454 | + break; |
|---|
| 455 | + ssiu->id = j; |
|---|
| 456 | + ssiu->id_sub = i - list[ssiu->id]; |
|---|
| 457 | + } |
|---|
| 458 | + } else { |
|---|
| 459 | + ssiu->id = i; |
|---|
| 460 | + } |
|---|
| 461 | + |
|---|
| 271 | 462 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), |
|---|
| 272 | | - ops, NULL, rsnd_mod_get_status, |
|---|
| 273 | | - RSND_MOD_SSIU, i); |
|---|
| 463 | + ops, NULL, RSND_MOD_SSIU, i); |
|---|
| 274 | 464 | if (ret) |
|---|
| 275 | 465 | return ret; |
|---|
| 276 | 466 | } |
|---|