root/sound/soc/sh/rcar/ssiu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rsnd_ssiu_get_status
  2. rsnd_ssiu_init
  3. rsnd_ssiu_init_gen2
  4. rsnd_ssiu_start_gen2
  5. rsnd_ssiu_stop_gen2
  6. rsnd_ssiu_id
  7. rsnd_ssiu_id_sub
  8. rsnd_ssiu_dma_req
  9. rsnd_ssiu_mod_get
  10. rsnd_parse_connect_ssiu_compatible
  11. rsnd_parse_connect_ssiu
  12. rsnd_ssiu_probe
  13. rsnd_ssiu_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // Renesas R-Car SSIU support
   4 //
   5 // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   6 
   7 #include "rsnd.h"
   8 
   9 #define SSIU_NAME "ssiu"
  10 
  11 struct rsnd_ssiu {
  12         struct rsnd_mod mod;
  13         u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
  14         unsigned int usrcnt;
  15         int id;
  16         int id_sub;
  17 };
  18 
  19 /* SSI_MODE */
  20 #define TDM_EXT         (1 << 0)
  21 #define TDM_SPLIT       (1 << 8)
  22 
  23 #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
  24 #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
  25 #define for_each_rsnd_ssiu(pos, priv, i)                                \
  26         for (i = 0;                                                     \
  27              (i < rsnd_ssiu_nr(priv)) &&                                \
  28                      ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));  \
  29              i++)
  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 
  58 static int rsnd_ssiu_init(struct rsnd_mod *mod,
  59                           struct rsnd_dai_stream *io,
  60                           struct rsnd_priv *priv)
  61 {
  62         struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
  63         u32 ssis = rsnd_ssi_multi_slaves_runtime(io);
  64         int use_busif = rsnd_ssi_use_busif(io);
  65         int id = rsnd_mod_id(mod);
  66         int is_clk_master = rsnd_rdai_is_clk_master(rdai);
  67         u32 val1, val2;
  68         int i;
  69 
  70         /* clear status */
  71         switch (id) {
  72         case 0:
  73         case 1:
  74         case 2:
  75         case 3:
  76         case 4:
  77                 for (i = 0; i < 4; i++)
  78                         rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
  79                 break;
  80         case 9:
  81                 for (i = 0; i < 4; i++)
  82                         rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4);
  83                 break;
  84         }
  85 
  86         /*
  87          * SSI_MODE0
  88          */
  89         rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
  90 
  91         /*
  92          * SSI_MODE1 / SSI_MODE2
  93          *
  94          * FIXME
  95          * sharing/multi with SSI0 are mainly supported
  96          */
  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) {
 104                 /*
 105                  * Multi SSI
 106                  *
 107                  * set synchronized bit here
 108                  */
 109 
 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);
 119         }
 120 
 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);
 139 
 140         return 0;
 141 }
 142 
 143 static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
 144         .name           = SSIU_NAME,
 145         .init           = rsnd_ssiu_init,
 146         .get_status     = rsnd_ssiu_get_status,
 147 };
 148 
 149 static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
 150                                struct rsnd_dai_stream *io,
 151                                struct rsnd_priv *priv)
 152 {
 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);
 156         int ret;
 157         u32 mode = 0;
 158 
 159         ret = rsnd_ssiu_init(mod, io, priv);
 160         if (ret < 0)
 161                 return ret;
 162 
 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;
 174 
 175         rsnd_mod_write(mod, SSI_MODE, mode);
 176 
 177         if (rsnd_ssi_use_busif(io)) {
 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,
 193                                rsnd_get_adinr_bit(mod, io) |
 194                                (rsnd_io_is_play(io) ?
 195                                 rsnd_runtime_channel_after_ctu(io) :
 196                                 rsnd_runtime_channel_original(io)));
 197                 rsnd_mod_write(mod, mode_reg,
 198                                rsnd_get_busif_shift(io, mod) | 1);
 199                 rsnd_mod_write(mod, dalign_reg,
 200                                rsnd_get_dalign(mod, io));
 201         }
 202 
 203         if (has_hdmi0 || has_hdmi1) {
 204                 enum rsnd_mod_type rsnd_ssi_array[] = {
 205                         RSND_MOD_SSIM1,
 206                         RSND_MOD_SSIM2,
 207                         RSND_MOD_SSIM3,
 208                 };
 209                 struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
 210                 struct rsnd_mod *pos;
 211                 u32 val;
 212                 int i, shift;
 213 
 214                 i = rsnd_mod_id(ssi_mod);
 215 
 216                 /* output all same SSI as default */
 217                 val =   i << 16 |
 218                         i << 20 |
 219                         i << 24 |
 220                         i << 28 |
 221                         i;
 222 
 223                 for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
 224                         shift   = (i * 4) + 20;
 225                         val     = (val & ~(0xF << shift)) |
 226                                 rsnd_mod_id(pos) << shift;
 227                 }
 228 
 229                 if (has_hdmi0)
 230                         rsnd_mod_write(mod, HDMI0_SEL, val);
 231                 if (has_hdmi1)
 232                         rsnd_mod_write(mod, HDMI1_SEL, val);
 233         }
 234 
 235         return 0;
 236 }
 237 
 238 static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
 239                                 struct rsnd_dai_stream *io,
 240                                 struct rsnd_priv *priv)
 241 {
 242         int busif = rsnd_mod_id_sub(mod);
 243 
 244         if (!rsnd_ssi_use_busif(io))
 245                 return 0;
 246 
 247         rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
 248 
 249         if (rsnd_ssi_multi_slaves_runtime(io))
 250                 rsnd_mod_write(mod, SSI_CONTROL, 0x1);
 251 
 252         return 0;
 253 }
 254 
 255 static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
 256                                struct rsnd_dai_stream *io,
 257                                struct rsnd_priv *priv)
 258 {
 259         struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
 260         int busif = rsnd_mod_id_sub(mod);
 261 
 262         if (!rsnd_ssi_use_busif(io))
 263                 return 0;
 264 
 265         rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
 266 
 267         if (--ssiu->usrcnt)
 268                 return 0;
 269 
 270         if (rsnd_ssi_multi_slaves_runtime(io))
 271                 rsnd_mod_write(mod, SSI_CONTROL, 0);
 272 
 273         return 0;
 274 }
 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 
 316 static struct rsnd_mod_ops rsnd_ssiu_ops_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,
 323 };
 324 
 325 static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
 326 {
 327         if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
 328                 id = 0;
 329 
 330         return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
 331 }
 332 
 333 static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
 334                                                struct rsnd_dai_stream *io)
 335 {
 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;
 340 
 341         if (!ssi_mod)
 342                 return;
 343 
 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);
 388 }
 389 
 390 int rsnd_ssiu_probe(struct rsnd_priv *priv)
 391 {
 392         struct device *dev = rsnd_priv_to_dev(priv);
 393         struct device_node *node;
 394         struct rsnd_ssiu *ssiu;
 395         struct rsnd_mod_ops *ops;
 396         const int *list = NULL;
 397         int i, nr, ret;
 398 
 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 
 412         ssiu    = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
 413         if (!ssiu)
 414                 return -ENOMEM;
 415 
 416         priv->ssiu      = ssiu;
 417         priv->ssiu_nr   = nr;
 418 
 419         if (rsnd_is_gen1(priv))
 420                 ops = &rsnd_ssiu_ops_gen1;
 421         else
 422                 ops = &rsnd_ssiu_ops_gen2;
 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 
 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 
 462                 ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
 463                                     ops, NULL, RSND_MOD_SSIU, i);
 464                 if (ret)
 465                         return ret;
 466         }
 467 
 468         return 0;
 469 }
 470 
 471 void rsnd_ssiu_remove(struct rsnd_priv *priv)
 472 {
 473         struct rsnd_ssiu *ssiu;
 474         int i;
 475 
 476         for_each_rsnd_ssiu(ssiu, priv, i) {
 477                 rsnd_mod_quit(rsnd_mod_get(ssiu));
 478         }
 479 }

/* [<][>][^][v][top][bottom][index][help] */