18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Renesas R-Car SSIU support 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "rsnd.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define SSIU_NAME "ssiu" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct rsnd_ssiu { 128c2ecf20Sopenharmony_ci struct rsnd_mod mod; 138c2ecf20Sopenharmony_ci u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ 148c2ecf20Sopenharmony_ci unsigned int usrcnt; 158c2ecf20Sopenharmony_ci int id; 168c2ecf20Sopenharmony_ci int id_sub; 178c2ecf20Sopenharmony_ci}; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* SSI_MODE */ 208c2ecf20Sopenharmony_ci#define TDM_EXT (1 << 0) 218c2ecf20Sopenharmony_ci#define TDM_SPLIT (1 << 8) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) 248c2ecf20Sopenharmony_ci#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) 258c2ecf20Sopenharmony_ci#define for_each_rsnd_ssiu(pos, priv, i) \ 268c2ecf20Sopenharmony_ci for (i = 0; \ 278c2ecf20Sopenharmony_ci (i < rsnd_ssiu_nr(priv)) && \ 288c2ecf20Sopenharmony_ci ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ 298c2ecf20Sopenharmony_ci i++) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * SSI Gen2 Gen3 338c2ecf20Sopenharmony_ci * 0 BUSIF0-3 BUSIF0-7 348c2ecf20Sopenharmony_ci * 1 BUSIF0-3 BUSIF0-7 358c2ecf20Sopenharmony_ci * 2 BUSIF0-3 BUSIF0-7 368c2ecf20Sopenharmony_ci * 3 BUSIF0 BUSIF0-7 378c2ecf20Sopenharmony_ci * 4 BUSIF0 BUSIF0-7 388c2ecf20Sopenharmony_ci * 5 BUSIF0 BUSIF0 398c2ecf20Sopenharmony_ci * 6 BUSIF0 BUSIF0 408c2ecf20Sopenharmony_ci * 7 BUSIF0 BUSIF0 418c2ecf20Sopenharmony_ci * 8 BUSIF0 BUSIF0 428c2ecf20Sopenharmony_ci * 9 BUSIF0-3 BUSIF0-7 438c2ecf20Sopenharmony_ci * total 22 52 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; 468c2ecf20Sopenharmony_cistatic const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, 498c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 508c2ecf20Sopenharmony_ci enum rsnd_mod_type type) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); 538c2ecf20Sopenharmony_ci int busif = rsnd_mod_id_sub(mod); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return &ssiu->busif_status[busif]; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int rsnd_ssiu_init(struct rsnd_mod *mod, 598c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 608c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct rsnd_dai *rdai = rsnd_io_to_rdai(io); 638c2ecf20Sopenharmony_ci u32 ssis = rsnd_ssi_multi_secondaries_runtime(io); 648c2ecf20Sopenharmony_ci int use_busif = rsnd_ssi_use_busif(io); 658c2ecf20Sopenharmony_ci int id = rsnd_mod_id(mod); 668c2ecf20Sopenharmony_ci int is_clk_master = rsnd_rdai_is_clk_master(rdai); 678c2ecf20Sopenharmony_ci u32 val1, val2; 688c2ecf20Sopenharmony_ci int i; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* clear status */ 718c2ecf20Sopenharmony_ci switch (id) { 728c2ecf20Sopenharmony_ci case 0: 738c2ecf20Sopenharmony_ci case 1: 748c2ecf20Sopenharmony_ci case 2: 758c2ecf20Sopenharmony_ci case 3: 768c2ecf20Sopenharmony_ci case 4: 778c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 788c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4)); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci case 9: 818c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 828c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * SSI_MODE0 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* 928c2ecf20Sopenharmony_ci * SSI_MODE1 / SSI_MODE2 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * FIXME 958c2ecf20Sopenharmony_ci * sharing/multi with SSI0 are mainly supported 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci val1 = rsnd_mod_read(mod, SSI_MODE1); 988c2ecf20Sopenharmony_ci val2 = rsnd_mod_read(mod, SSI_MODE2); 998c2ecf20Sopenharmony_ci if (rsnd_ssi_is_pin_sharing(io)) { 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ssis |= (1 << id); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci } else if (ssis) { 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Multi SSI 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * set synchronized bit here 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* SSI4 is synchronized with SSI3 */ 1118c2ecf20Sopenharmony_ci if (ssis & (1 << 4)) 1128c2ecf20Sopenharmony_ci val1 |= (1 << 20); 1138c2ecf20Sopenharmony_ci /* SSI012 are synchronized */ 1148c2ecf20Sopenharmony_ci if (ssis == 0x0006) 1158c2ecf20Sopenharmony_ci val1 |= (1 << 4); 1168c2ecf20Sopenharmony_ci /* SSI0129 are synchronized */ 1178c2ecf20Sopenharmony_ci if (ssis == 0x0206) 1188c2ecf20Sopenharmony_ci val2 |= (1 << 4); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* SSI1 is sharing pin with SSI0 */ 1228c2ecf20Sopenharmony_ci if (ssis & (1 << 1)) 1238c2ecf20Sopenharmony_ci val1 |= is_clk_master ? 0x2 : 0x1; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* SSI2 is sharing pin with SSI0 */ 1268c2ecf20Sopenharmony_ci if (ssis & (1 << 2)) 1278c2ecf20Sopenharmony_ci val1 |= is_clk_master ? 0x2 << 2 : 1288c2ecf20Sopenharmony_ci 0x1 << 2; 1298c2ecf20Sopenharmony_ci /* SSI4 is sharing pin with SSI3 */ 1308c2ecf20Sopenharmony_ci if (ssis & (1 << 4)) 1318c2ecf20Sopenharmony_ci val1 |= is_clk_master ? 0x2 << 16 : 1328c2ecf20Sopenharmony_ci 0x1 << 16; 1338c2ecf20Sopenharmony_ci /* SSI9 is sharing pin with SSI0 */ 1348c2ecf20Sopenharmony_ci if (ssis & (1 << 9)) 1358c2ecf20Sopenharmony_ci val2 |= is_clk_master ? 0x2 : 0x1; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); 1388c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { 1448c2ecf20Sopenharmony_ci .name = SSIU_NAME, 1458c2ecf20Sopenharmony_ci .init = rsnd_ssiu_init, 1468c2ecf20Sopenharmony_ci .get_status = rsnd_ssiu_get_status, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, 1508c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 1518c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); 1548c2ecf20Sopenharmony_ci u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); 1558c2ecf20Sopenharmony_ci u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); 1568c2ecf20Sopenharmony_ci int ret; 1578c2ecf20Sopenharmony_ci u32 mode = 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ret = rsnd_ssiu_init(mod, io, priv); 1608c2ecf20Sopenharmony_ci if (ret < 0) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ssiu->usrcnt++; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * TDM Extend/Split Mode 1678c2ecf20Sopenharmony_ci * see 1688c2ecf20Sopenharmony_ci * rsnd_ssi_config_init() 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci if (rsnd_runtime_is_tdm(io)) 1718c2ecf20Sopenharmony_ci mode = TDM_EXT; 1728c2ecf20Sopenharmony_ci else if (rsnd_runtime_is_tdm_split(io)) 1738c2ecf20Sopenharmony_ci mode = TDM_SPLIT; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SSI_MODE, mode); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (rsnd_ssi_use_busif(io)) { 1788c2ecf20Sopenharmony_ci int id = rsnd_mod_id(mod); 1798c2ecf20Sopenharmony_ci int busif = rsnd_mod_id_sub(mod); 1808c2ecf20Sopenharmony_ci enum rsnd_reg adinr_reg, mode_reg, dalign_reg; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if ((id == 9) && (busif >= 4)) { 1838c2ecf20Sopenharmony_ci adinr_reg = SSI9_BUSIF_ADINR(busif); 1848c2ecf20Sopenharmony_ci mode_reg = SSI9_BUSIF_MODE(busif); 1858c2ecf20Sopenharmony_ci dalign_reg = SSI9_BUSIF_DALIGN(busif); 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci adinr_reg = SSI_BUSIF_ADINR(busif); 1888c2ecf20Sopenharmony_ci mode_reg = SSI_BUSIF_MODE(busif); 1898c2ecf20Sopenharmony_ci dalign_reg = SSI_BUSIF_DALIGN(busif); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci rsnd_mod_write(mod, adinr_reg, 1938c2ecf20Sopenharmony_ci rsnd_get_adinr_bit(mod, io) | 1948c2ecf20Sopenharmony_ci (rsnd_io_is_play(io) ? 1958c2ecf20Sopenharmony_ci rsnd_runtime_channel_after_ctu(io) : 1968c2ecf20Sopenharmony_ci rsnd_runtime_channel_original(io))); 1978c2ecf20Sopenharmony_ci rsnd_mod_write(mod, mode_reg, 1988c2ecf20Sopenharmony_ci rsnd_get_busif_shift(io, mod) | 1); 1998c2ecf20Sopenharmony_ci rsnd_mod_write(mod, dalign_reg, 2008c2ecf20Sopenharmony_ci rsnd_get_dalign(mod, io)); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (has_hdmi0 || has_hdmi1) { 2048c2ecf20Sopenharmony_ci enum rsnd_mod_type rsnd_ssi_array[] = { 2058c2ecf20Sopenharmony_ci RSND_MOD_SSIM1, 2068c2ecf20Sopenharmony_ci RSND_MOD_SSIM2, 2078c2ecf20Sopenharmony_ci RSND_MOD_SSIM3, 2088c2ecf20Sopenharmony_ci }; 2098c2ecf20Sopenharmony_ci struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); 2108c2ecf20Sopenharmony_ci struct rsnd_mod *pos; 2118c2ecf20Sopenharmony_ci u32 val; 2128c2ecf20Sopenharmony_ci int i, shift; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci i = rsnd_mod_id(ssi_mod); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* output all same SSI as default */ 2178c2ecf20Sopenharmony_ci val = i << 16 | 2188c2ecf20Sopenharmony_ci i << 20 | 2198c2ecf20Sopenharmony_ci i << 24 | 2208c2ecf20Sopenharmony_ci i << 28 | 2218c2ecf20Sopenharmony_ci i; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { 2248c2ecf20Sopenharmony_ci shift = (i * 4) + 20; 2258c2ecf20Sopenharmony_ci val = (val & ~(0xF << shift)) | 2268c2ecf20Sopenharmony_ci rsnd_mod_id(pos) << shift; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (has_hdmi0) 2308c2ecf20Sopenharmony_ci rsnd_mod_write(mod, HDMI0_SEL, val); 2318c2ecf20Sopenharmony_ci if (has_hdmi1) 2328c2ecf20Sopenharmony_ci rsnd_mod_write(mod, HDMI1_SEL, val); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, 2398c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 2408c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci int busif = rsnd_mod_id_sub(mod); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (!rsnd_ssi_use_busif(io)) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (rsnd_ssi_multi_secondaries_runtime(io)) 2508c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SSI_CONTROL, 0x1); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, 2568c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 2578c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); 2608c2ecf20Sopenharmony_ci int busif = rsnd_mod_id_sub(mod); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!rsnd_ssi_use_busif(io)) 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (--ssiu->usrcnt) 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (rsnd_ssi_multi_secondaries_runtime(io)) 2718c2ecf20Sopenharmony_ci rsnd_mod_write(mod, SSI_CONTROL, 0); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int rsnd_ssiu_id(struct rsnd_mod *mod) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* see rsnd_ssiu_probe() */ 2818c2ecf20Sopenharmony_ci return ssiu->id; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int rsnd_ssiu_id_sub(struct rsnd_mod *mod) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* see rsnd_ssiu_probe() */ 2898c2ecf20Sopenharmony_ci return ssiu->id_sub; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, 2938c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 2968c2ecf20Sopenharmony_ci int is_play = rsnd_io_is_play(io); 2978c2ecf20Sopenharmony_ci char *name; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * It should use "rcar_sound,ssiu" on DT. 3018c2ecf20Sopenharmony_ci * But, we need to keep compatibility for old version. 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * If it has "rcar_sound.ssiu", it will be used. 3048c2ecf20Sopenharmony_ci * If not, "rcar_sound.ssi" will be used. 3058c2ecf20Sopenharmony_ci * see 3068c2ecf20Sopenharmony_ci * rsnd_ssi_dma_req() 3078c2ecf20Sopenharmony_ci * rsnd_dma_of_path() 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci name = is_play ? "rx" : "tx"; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), 3138c2ecf20Sopenharmony_ci mod, name); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { 3178c2ecf20Sopenharmony_ci .name = SSIU_NAME, 3188c2ecf20Sopenharmony_ci .dma_req = rsnd_ssiu_dma_req, 3198c2ecf20Sopenharmony_ci .init = rsnd_ssiu_init_gen2, 3208c2ecf20Sopenharmony_ci .start = rsnd_ssiu_start_gen2, 3218c2ecf20Sopenharmony_ci .stop = rsnd_ssiu_stop_gen2, 3228c2ecf20Sopenharmony_ci .get_status = rsnd_ssiu_get_status, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) 3288c2ecf20Sopenharmony_ci id = 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, 3348c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); 3378c2ecf20Sopenharmony_ci struct rsnd_mod *mod; 3388c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu; 3398c2ecf20Sopenharmony_ci int i; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!ssi_mod) 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* select BUSIF0 */ 3458c2ecf20Sopenharmony_ci for_each_rsnd_ssiu(ssiu, priv, i) { 3468c2ecf20Sopenharmony_ci mod = rsnd_mod_get(ssiu); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && 3498c2ecf20Sopenharmony_ci (rsnd_mod_id_sub(mod) == 0)) { 3508c2ecf20Sopenharmony_ci rsnd_dai_connect(mod, io, mod->type); 3518c2ecf20Sopenharmony_ci return; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_civoid rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, 3578c2ecf20Sopenharmony_ci struct device_node *playback, 3588c2ecf20Sopenharmony_ci struct device_node *capture) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); 3618c2ecf20Sopenharmony_ci struct device_node *node = rsnd_ssiu_of_node(priv); 3628c2ecf20Sopenharmony_ci struct device_node *np; 3638c2ecf20Sopenharmony_ci struct rsnd_mod *mod; 3648c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io_p = &rdai->playback; 3658c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io_c = &rdai->capture; 3668c2ecf20Sopenharmony_ci int i; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* use rcar_sound,ssiu if exist */ 3698c2ecf20Sopenharmony_ci if (node) { 3708c2ecf20Sopenharmony_ci i = 0; 3718c2ecf20Sopenharmony_ci for_each_child_of_node(node, np) { 3728c2ecf20Sopenharmony_ci mod = rsnd_ssiu_mod_get(priv, i); 3738c2ecf20Sopenharmony_ci if (np == playback) 3748c2ecf20Sopenharmony_ci rsnd_dai_connect(mod, io_p, mod->type); 3758c2ecf20Sopenharmony_ci if (np == capture) 3768c2ecf20Sopenharmony_ci rsnd_dai_connect(mod, io_c, mod->type); 3778c2ecf20Sopenharmony_ci i++; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci of_node_put(node); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Keep DT compatibility */ 3848c2ecf20Sopenharmony_ci if (!rsnd_io_to_mod_ssiu(io_p)) 3858c2ecf20Sopenharmony_ci rsnd_parse_connect_ssiu_compatible(priv, io_p); 3868c2ecf20Sopenharmony_ci if (!rsnd_io_to_mod_ssiu(io_c)) 3878c2ecf20Sopenharmony_ci rsnd_parse_connect_ssiu_compatible(priv, io_c); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciint rsnd_ssiu_probe(struct rsnd_priv *priv) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 3938c2ecf20Sopenharmony_ci struct device_node *node; 3948c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu; 3958c2ecf20Sopenharmony_ci struct rsnd_mod_ops *ops; 3968c2ecf20Sopenharmony_ci const int *list = NULL; 3978c2ecf20Sopenharmony_ci int i, nr, ret; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * Keep DT compatibility. 4018c2ecf20Sopenharmony_ci * if it has "rcar_sound,ssiu", use it. 4028c2ecf20Sopenharmony_ci * if not, use "rcar_sound,ssi" 4038c2ecf20Sopenharmony_ci * see 4048c2ecf20Sopenharmony_ci * rsnd_ssiu_bufsif_to_id() 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci node = rsnd_ssiu_of_node(priv); 4078c2ecf20Sopenharmony_ci if (node) 4088c2ecf20Sopenharmony_ci nr = of_get_child_count(node); 4098c2ecf20Sopenharmony_ci else 4108c2ecf20Sopenharmony_ci nr = priv->ssi_nr; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); 4138c2ecf20Sopenharmony_ci if (!ssiu) 4148c2ecf20Sopenharmony_ci return -ENOMEM; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci priv->ssiu = ssiu; 4178c2ecf20Sopenharmony_ci priv->ssiu_nr = nr; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (rsnd_is_gen1(priv)) 4208c2ecf20Sopenharmony_ci ops = &rsnd_ssiu_ops_gen1; 4218c2ecf20Sopenharmony_ci else 4228c2ecf20Sopenharmony_ci ops = &rsnd_ssiu_ops_gen2; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Keep compatibility */ 4258c2ecf20Sopenharmony_ci nr = 0; 4268c2ecf20Sopenharmony_ci if ((node) && 4278c2ecf20Sopenharmony_ci (ops == &rsnd_ssiu_ops_gen2)) { 4288c2ecf20Sopenharmony_ci ops->id = rsnd_ssiu_id; 4298c2ecf20Sopenharmony_ci ops->id_sub = rsnd_ssiu_id_sub; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (rsnd_is_gen2(priv)) { 4328c2ecf20Sopenharmony_ci list = gen2_id; 4338c2ecf20Sopenharmony_ci nr = ARRAY_SIZE(gen2_id); 4348c2ecf20Sopenharmony_ci } else if (rsnd_is_gen3(priv)) { 4358c2ecf20Sopenharmony_ci list = gen3_id; 4368c2ecf20Sopenharmony_ci nr = ARRAY_SIZE(gen3_id); 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci dev_err(dev, "unknown SSIU\n"); 4398c2ecf20Sopenharmony_ci return -ENODEV; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci for_each_rsnd_ssiu(ssiu, priv, i) { 4448c2ecf20Sopenharmony_ci if (node) { 4458c2ecf20Sopenharmony_ci int j; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* 4488c2ecf20Sopenharmony_ci * see 4498c2ecf20Sopenharmony_ci * rsnd_ssiu_get_id() 4508c2ecf20Sopenharmony_ci * rsnd_ssiu_get_id_sub() 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci for (j = 0; j < nr; j++) { 4538c2ecf20Sopenharmony_ci if (list[j] > i) 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci ssiu->id = j; 4568c2ecf20Sopenharmony_ci ssiu->id_sub = i - list[ssiu->id]; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } else { 4598c2ecf20Sopenharmony_ci ssiu->id = i; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), 4638c2ecf20Sopenharmony_ci ops, NULL, RSND_MOD_SSIU, i); 4648c2ecf20Sopenharmony_ci if (ret) 4658c2ecf20Sopenharmony_ci return ret; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_civoid rsnd_ssiu_remove(struct rsnd_priv *priv) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct rsnd_ssiu *ssiu; 4748c2ecf20Sopenharmony_ci int i; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci for_each_rsnd_ssiu(ssiu, priv, i) { 4778c2ecf20Sopenharmony_ci rsnd_mod_quit(rsnd_mod_get(ssiu)); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci} 480