Commit 3337744ac41bee00b0068ad5f926dd9c27540809

Authored by Kuninori Morimoto
Committed by Mark Brown
1 parent cdaa3cdfb4

ASoC: add Renesas R-Car Generation feature

Renesas R-Car series sound circuit consists of SSI and its peripheral.
But this peripheral circuit is different between
R-Car Generation1 (E1/M1/H1) and Generation2 (E2/M2/H2)
(Actually, there are many difference in Generation1 chips)

The main difference between Gen1 and Gen2 are
1) register offset, 2) data path

In order to control Gen1/Gen2 by same method,
this patch adds gen.c.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

Showing 5 changed files with 269 additions and 2 deletions Side-by-side Diff

include/sound/rcar_snd.h
... ... @@ -22,6 +22,16 @@
22 22 int ssi_id_capture;
23 23 };
24 24  
  25 +/*
  26 + * flags
  27 + *
  28 + * 0x0000000A
  29 + *
  30 + * A : generation
  31 + */
  32 +#define RSND_GEN1 (1 << 0) /* fixme */
  33 +#define RSND_GEN2 (2 << 0) /* fixme */
  34 +
25 35 struct rcar_snd_info {
26 36 u32 flags;
27 37 struct rsnd_dai_platform_info *dai_info;
sound/soc/sh/rcar/Makefile
1   -snd-soc-rcar-objs := core.o
  1 +snd-soc-rcar-objs := core.o gen.o
2 2 obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
sound/soc/sh/rcar/core.c
... ... @@ -108,6 +108,50 @@
108 108  
109 109  
110 110 /*
  111 + * basic function
  112 + */
  113 +u32 rsnd_read(struct rsnd_priv *priv,
  114 + struct rsnd_mod *mod, enum rsnd_reg reg)
  115 +{
  116 + void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
  117 +
  118 + BUG_ON(!base);
  119 +
  120 + return ioread32(base);
  121 +}
  122 +
  123 +void rsnd_write(struct rsnd_priv *priv,
  124 + struct rsnd_mod *mod,
  125 + enum rsnd_reg reg, u32 data)
  126 +{
  127 + void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
  128 + struct device *dev = rsnd_priv_to_dev(priv);
  129 +
  130 + BUG_ON(!base);
  131 +
  132 + dev_dbg(dev, "w %p : %08x\n", base, data);
  133 +
  134 + iowrite32(data, base);
  135 +}
  136 +
  137 +void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
  138 + enum rsnd_reg reg, u32 mask, u32 data)
  139 +{
  140 + void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
  141 + struct device *dev = rsnd_priv_to_dev(priv);
  142 + u32 val;
  143 +
  144 + BUG_ON(!base);
  145 +
  146 + val = ioread32(base);
  147 + val &= ~mask;
  148 + val |= data & mask;
  149 + iowrite32(val, base);
  150 +
  151 + dev_dbg(dev, "s %p : %08x\n", base, val);
  152 +}
  153 +
  154 +/*
111 155 * rsnd_mod functions
112 156 */
113 157 char *rsnd_mod_name(struct rsnd_mod *mod)
... ... @@ -289,6 +333,10 @@
289 333 if (ret < 0)
290 334 goto dai_trigger_end;
291 335  
  336 + ret = rsnd_gen_path_init(priv, rdai, io);
  337 + if (ret < 0)
  338 + goto dai_trigger_end;
  339 +
292 340 ret = rsnd_dai_call(rdai, io, init);
293 341 if (ret < 0)
294 342 goto dai_trigger_end;
295 343  
... ... @@ -306,10 +354,13 @@
306 354 if (ret < 0)
307 355 goto dai_trigger_end;
308 356  
309   - ret = rsnd_platform_call(priv, dai, stop, ssi_id);
  357 + ret = rsnd_gen_path_exit(priv, rdai, io);
310 358 if (ret < 0)
311 359 goto dai_trigger_end;
312 360  
  361 + ret = rsnd_platform_call(priv, dai, stop, ssi_id);
  362 + if (ret < 0)
  363 + goto dai_trigger_end;
313 364 break;
314 365 default:
315 366 ret = -EINVAL;
... ... @@ -572,6 +623,10 @@
572 623 /*
573 624 * init each module
574 625 */
  626 + ret = rsnd_gen_probe(pdev, info, priv);
  627 + if (ret < 0)
  628 + return ret;
  629 +
575 630 ret = rsnd_dai_probe(pdev, info, priv);
576 631 if (ret < 0)
577 632 return ret;
... ... @@ -615,6 +670,7 @@
615 670 * remove each module
616 671 */
617 672 rsnd_dai_remove(pdev, priv);
  673 + rsnd_gen_remove(pdev, priv);
618 674  
619 675 return 0;
620 676 }
sound/soc/sh/rcar/gen.c
  1 +/*
  2 + * Renesas R-Car Gen1 SRU/SSI support
  3 + *
  4 + * Copyright (C) 2013 Renesas Solutions Corp.
  5 + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify
  8 + * it under the terms of the GNU General Public License version 2 as
  9 + * published by the Free Software Foundation.
  10 + */
  11 +#include "rsnd.h"
  12 +
  13 +struct rsnd_gen_ops {
  14 + int (*path_init)(struct rsnd_priv *priv,
  15 + struct rsnd_dai *rdai,
  16 + struct rsnd_dai_stream *io);
  17 + int (*path_exit)(struct rsnd_priv *priv,
  18 + struct rsnd_dai *rdai,
  19 + struct rsnd_dai_stream *io);
  20 +};
  21 +
  22 +struct rsnd_gen_reg_map {
  23 + int index; /* -1 : not supported */
  24 + u32 offset_id; /* offset of ssi0, ssi1, ssi2... */
  25 + u32 offset_adr; /* offset of SSICR, SSISR, ... */
  26 +};
  27 +
  28 +struct rsnd_gen {
  29 + void __iomem *base[RSND_BASE_MAX];
  30 +
  31 + struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
  32 + struct rsnd_gen_ops *ops;
  33 +};
  34 +
  35 +#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
  36 +
  37 +#define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1)
  38 +#define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2)
  39 +
  40 +/*
  41 + * Gen2
  42 + * will be filled in the future
  43 + */
  44 +
  45 +/*
  46 + * Gen1
  47 + */
  48 +static int rsnd_gen1_probe(struct platform_device *pdev,
  49 + struct rcar_snd_info *info,
  50 + struct rsnd_priv *priv)
  51 +{
  52 + return 0;
  53 +}
  54 +
  55 +static void rsnd_gen1_remove(struct platform_device *pdev,
  56 + struct rsnd_priv *priv)
  57 +{
  58 +}
  59 +
  60 +/*
  61 + * Gen
  62 + */
  63 +int rsnd_gen_path_init(struct rsnd_priv *priv,
  64 + struct rsnd_dai *rdai,
  65 + struct rsnd_dai_stream *io)
  66 +{
  67 + struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
  68 +
  69 + return gen->ops->path_init(priv, rdai, io);
  70 +}
  71 +
  72 +int rsnd_gen_path_exit(struct rsnd_priv *priv,
  73 + struct rsnd_dai *rdai,
  74 + struct rsnd_dai_stream *io)
  75 +{
  76 + struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
  77 +
  78 + return gen->ops->path_exit(priv, rdai, io);
  79 +}
  80 +
  81 +void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
  82 + struct rsnd_mod *mod,
  83 + enum rsnd_reg reg)
  84 +{
  85 + struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
  86 + struct device *dev = rsnd_priv_to_dev(priv);
  87 + int index;
  88 + u32 offset_id, offset_adr;
  89 +
  90 + if (reg >= RSND_REG_MAX) {
  91 + dev_err(dev, "rsnd_reg reg error\n");
  92 + return NULL;
  93 + }
  94 +
  95 + index = gen->reg_map[reg].index;
  96 + offset_id = gen->reg_map[reg].offset_id;
  97 + offset_adr = gen->reg_map[reg].offset_adr;
  98 +
  99 + if (index < 0) {
  100 + dev_err(dev, "unsupported reg access %d\n", reg);
  101 + return NULL;
  102 + }
  103 +
  104 + if (offset_id && mod)
  105 + offset_id *= rsnd_mod_id(mod);
  106 +
  107 + /*
  108 + * index/offset were set on gen1/gen2
  109 + */
  110 +
  111 + return gen->base[index] + offset_id + offset_adr;
  112 +}
  113 +
  114 +int rsnd_gen_probe(struct platform_device *pdev,
  115 + struct rcar_snd_info *info,
  116 + struct rsnd_priv *priv)
  117 +{
  118 + struct device *dev = rsnd_priv_to_dev(priv);
  119 + struct rsnd_gen *gen;
  120 + int i;
  121 +
  122 + gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
  123 + if (!gen) {
  124 + dev_err(dev, "GEN allocate failed\n");
  125 + return -ENOMEM;
  126 + }
  127 +
  128 + priv->gen = gen;
  129 +
  130 + /*
  131 + * see
  132 + * rsnd_reg_get()
  133 + * rsnd_gen_probe()
  134 + */
  135 + for (i = 0; i < RSND_REG_MAX; i++)
  136 + gen->reg_map[i].index = -1;
  137 +
  138 + /*
  139 + * init each module
  140 + */
  141 + if (rsnd_is_gen1(priv))
  142 + return rsnd_gen1_probe(pdev, info, priv);
  143 +
  144 + dev_err(dev, "unknown generation R-Car sound device\n");
  145 +
  146 + return -ENODEV;
  147 +}
  148 +
  149 +void rsnd_gen_remove(struct platform_device *pdev,
  150 + struct rsnd_priv *priv)
  151 +{
  152 + if (rsnd_is_gen1(priv))
  153 + rsnd_gen1_remove(pdev, priv);
  154 +}
sound/soc/sh/rcar/rsnd.h
... ... @@ -27,12 +27,36 @@
27 27 * This driver uses pseudo register in order to hide it.
28 28 * see gen1/gen2 for detail
29 29 */
  30 +enum rsnd_reg {
  31 + RSND_REG_MAX,
  32 +};
  33 +
30 34 struct rsnd_priv;
31 35 struct rsnd_mod;
32 36 struct rsnd_dai;
33 37 struct rsnd_dai_stream;
34 38  
35 39 /*
  40 + * R-Car basic functions
  41 + */
  42 +#define rsnd_mod_read(m, r) \
  43 + rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
  44 +#define rsnd_mod_write(m, r, d) \
  45 + rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
  46 +#define rsnd_mod_bset(m, r, s, d) \
  47 + rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
  48 +
  49 +#define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r)
  50 +#define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d)
  51 +#define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d)
  52 +
  53 +u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
  54 +void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
  55 + enum rsnd_reg reg, u32 data);
  56 +void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
  57 + u32 mask, u32 data);
  58 +
  59 +/*
36 60 * R-Car sound mod
37 61 */
38 62  
... ... @@ -117,6 +141,24 @@
117 141 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
118 142  
119 143 /*
  144 + * R-Car Gen1/Gen2
  145 + */
  146 +int rsnd_gen_probe(struct platform_device *pdev,
  147 + struct rcar_snd_info *info,
  148 + struct rsnd_priv *priv);
  149 +void rsnd_gen_remove(struct platform_device *pdev,
  150 + struct rsnd_priv *priv);
  151 +int rsnd_gen_path_init(struct rsnd_priv *priv,
  152 + struct rsnd_dai *rdai,
  153 + struct rsnd_dai_stream *io);
  154 +int rsnd_gen_path_exit(struct rsnd_priv *priv,
  155 + struct rsnd_dai *rdai,
  156 + struct rsnd_dai_stream *io);
  157 +void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
  158 + struct rsnd_mod *mod,
  159 + enum rsnd_reg reg);
  160 +
  161 +/*
120 162 * R-Car sound priv
121 163 */
122 164 struct rsnd_priv {
... ... @@ -124,6 +166,11 @@
124 166 struct device *dev;
125 167 struct rcar_snd_info *info;
126 168 spinlock_t lock;
  169 +
  170 + /*
  171 + * below value will be filled on rsnd_gen_probe()
  172 + */
  173 + void *gen;
127 174  
128 175 /*
129 176 * below value will be filled on rsnd_dai_probe()