diff options
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/sh/fsi.c | 36 | ||||
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 151 | ||||
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 256 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 46 | ||||
-rw-r--r-- | sound/soc/sh/rcar/scu.c | 181 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 19 |
7 files changed, 499 insertions, 191 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 14011d90d70a..ff60e11ecb56 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU | |||
37 | config SND_SOC_RCAR | 37 | config SND_SOC_RCAR |
38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" | 38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" |
39 | select SND_SIMPLE_CARD | 39 | select SND_SIMPLE_CARD |
40 | select REGMAP | ||
40 | help | 41 | help |
41 | This option enables R-Car SUR/SCU/SSIU/SSI sound support | 42 | This option enables R-Car SUR/SCU/SSIU/SSI sound support |
42 | 43 | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index b33ca7cd085b..6101055aae1d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -232,9 +232,9 @@ struct fsi_stream { | |||
232 | * these are for DMAEngine | 232 | * these are for DMAEngine |
233 | */ | 233 | */ |
234 | struct dma_chan *chan; | 234 | struct dma_chan *chan; |
235 | struct sh_dmae_slave slave; /* see fsi_handler_init() */ | ||
236 | struct work_struct work; | 235 | struct work_struct work; |
237 | dma_addr_t dma; | 236 | dma_addr_t dma; |
237 | int dma_id; | ||
238 | int loop_cnt; | 238 | int loop_cnt; |
239 | int additional_pos; | 239 | int additional_pos; |
240 | }; | 240 | }; |
@@ -1410,15 +1410,6 @@ static void fsi_dma_do_work(struct work_struct *work) | |||
1410 | } | 1410 | } |
1411 | } | 1411 | } |
1412 | 1412 | ||
1413 | static bool fsi_dma_filter(struct dma_chan *chan, void *param) | ||
1414 | { | ||
1415 | struct sh_dmae_slave *slave = param; | ||
1416 | |||
1417 | chan->private = slave; | ||
1418 | |||
1419 | return true; | ||
1420 | } | ||
1421 | |||
1422 | static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) | 1413 | static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) |
1423 | { | 1414 | { |
1424 | schedule_work(&io->work); | 1415 | schedule_work(&io->work); |
@@ -1446,15 +1437,34 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, | |||
1446 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) | 1437 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) |
1447 | { | 1438 | { |
1448 | dma_cap_mask_t mask; | 1439 | dma_cap_mask_t mask; |
1440 | int is_play = fsi_stream_is_play(fsi, io); | ||
1449 | 1441 | ||
1450 | dma_cap_zero(mask); | 1442 | dma_cap_zero(mask); |
1451 | dma_cap_set(DMA_SLAVE, mask); | 1443 | dma_cap_set(DMA_SLAVE, mask); |
1452 | 1444 | ||
1453 | io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); | 1445 | io->chan = dma_request_slave_channel_compat(mask, |
1446 | shdma_chan_filter, (void *)io->dma_id, | ||
1447 | dev, is_play ? "tx" : "rx"); | ||
1448 | if (io->chan) { | ||
1449 | struct dma_slave_config cfg; | ||
1450 | int ret; | ||
1451 | |||
1452 | cfg.slave_id = io->dma_id; | ||
1453 | cfg.dst_addr = 0; /* use default addr */ | ||
1454 | cfg.src_addr = 0; /* use default addr */ | ||
1455 | cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; | ||
1456 | |||
1457 | ret = dmaengine_slave_config(io->chan, &cfg); | ||
1458 | if (ret < 0) { | ||
1459 | dma_release_channel(io->chan); | ||
1460 | io->chan = NULL; | ||
1461 | } | ||
1462 | } | ||
1463 | |||
1454 | if (!io->chan) { | 1464 | if (!io->chan) { |
1455 | 1465 | ||
1456 | /* switch to PIO handler */ | 1466 | /* switch to PIO handler */ |
1457 | if (fsi_stream_is_play(fsi, io)) | 1467 | if (is_play) |
1458 | fsi->playback.handler = &fsi_pio_push_handler; | 1468 | fsi->playback.handler = &fsi_pio_push_handler; |
1459 | else | 1469 | else |
1460 | fsi->capture.handler = &fsi_pio_pop_handler; | 1470 | fsi->capture.handler = &fsi_pio_pop_handler; |
@@ -1960,7 +1970,7 @@ static void fsi_handler_init(struct fsi_priv *fsi, | |||
1960 | fsi->capture.priv = fsi; | 1970 | fsi->capture.priv = fsi; |
1961 | 1971 | ||
1962 | if (info->tx_id) { | 1972 | if (info->tx_id) { |
1963 | fsi->playback.slave.shdma_slave.slave_id = info->tx_id; | 1973 | fsi->playback.dma_id = info->tx_id; |
1964 | fsi->playback.handler = &fsi_dma_push_handler; | 1974 | fsi->playback.handler = &fsi_dma_push_handler; |
1965 | } | 1975 | } |
1966 | } | 1976 | } |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 9430097979a5..a53235c4d1b0 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -19,8 +19,8 @@ | |||
19 | struct rsnd_adg { | 19 | struct rsnd_adg { |
20 | struct clk *clk[CLKMAX]; | 20 | struct clk *clk[CLKMAX]; |
21 | 21 | ||
22 | int rate_of_441khz_div_6; | 22 | int rbga_rate_for_441khz_div_6; /* RBGA */ |
23 | int rate_of_48khz_div_6; | 23 | int rbgb_rate_for_48khz_div_6; /* RBGB */ |
24 | u32 ckr; | 24 | u32 ckr; |
25 | }; | 25 | }; |
26 | 26 | ||
@@ -30,41 +30,114 @@ struct rsnd_adg { | |||
30 | i++, (pos) = adg->clk[i]) | 30 | i++, (pos) = adg->clk[i]) |
31 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) | 31 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) |
32 | 32 | ||
33 | static enum rsnd_reg rsnd_adg_ssi_reg_get(int id) | 33 | static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, |
34 | struct rsnd_mod *mod, | ||
35 | unsigned int src_rate, | ||
36 | unsigned int dst_rate) | ||
34 | { | 37 | { |
35 | enum rsnd_reg reg; | 38 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
39 | struct device *dev = rsnd_priv_to_dev(priv); | ||
40 | int idx, sel, div, shift; | ||
41 | u32 mask, val; | ||
42 | int id = rsnd_mod_id(mod); | ||
43 | unsigned int sel_rate [] = { | ||
44 | clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */ | ||
45 | clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */ | ||
46 | clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */ | ||
47 | 0, /* 011: MLBCLK (not used) */ | ||
48 | adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */ | ||
49 | adg->rbgb_rate_for_48khz_div_6, /* 101: RBGB */ | ||
50 | }; | ||
51 | |||
52 | /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */ | ||
53 | for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { | ||
54 | for (div = 128, idx = 0; | ||
55 | div <= 2048; | ||
56 | div *= 2, idx++) { | ||
57 | if (src_rate == sel_rate[sel] / div) { | ||
58 | val = (idx << 4) | sel; | ||
59 | goto find_rate; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | dev_err(dev, "can't find convert src clk\n"); | ||
64 | return -EINVAL; | ||
65 | |||
66 | find_rate: | ||
67 | shift = (id % 4) * 8; | ||
68 | mask = 0xFF << shift; | ||
69 | val = val << shift; | ||
70 | |||
71 | dev_dbg(dev, "adg convert src clk = %02x\n", val); | ||
72 | |||
73 | switch (id / 4) { | ||
74 | case 0: | ||
75 | rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val); | ||
76 | break; | ||
77 | case 1: | ||
78 | rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val); | ||
79 | break; | ||
80 | case 2: | ||
81 | rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val); | ||
82 | break; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Gen1 doesn't need dst_rate settings, | ||
87 | * since it uses SSI WS pin. | ||
88 | * see also rsnd_src_set_route_if_gen1() | ||
89 | */ | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, | ||
95 | struct rsnd_mod *mod, | ||
96 | unsigned int src_rate, | ||
97 | unsigned int dst_rate) | ||
98 | { | ||
99 | if (rsnd_is_gen1(priv)) | ||
100 | return rsnd_adg_set_convert_clk_gen1(priv, mod, | ||
101 | src_rate, dst_rate); | ||
102 | |||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) | ||
107 | { | ||
108 | int id = rsnd_mod_id(mod); | ||
109 | int shift = (id % 4) * 8; | ||
110 | u32 mask = 0xFF << shift; | ||
111 | |||
112 | val = val << shift; | ||
36 | 113 | ||
37 | /* | 114 | /* |
38 | * SSI 8 is not connected to ADG. | 115 | * SSI 8 is not connected to ADG. |
39 | * it works with SSI 7 | 116 | * it works with SSI 7 |
40 | */ | 117 | */ |
41 | if (id == 8) | 118 | if (id == 8) |
42 | return RSND_REG_MAX; | 119 | return; |
43 | 120 | ||
44 | if (0 <= id && id <= 3) | 121 | switch (id / 4) { |
45 | reg = RSND_REG_AUDIO_CLK_SEL0; | 122 | case 0: |
46 | else if (4 <= id && id <= 7) | 123 | rsnd_mod_bset(mod, AUDIO_CLK_SEL0, mask, val); |
47 | reg = RSND_REG_AUDIO_CLK_SEL1; | 124 | break; |
48 | else | 125 | case 1: |
49 | reg = RSND_REG_AUDIO_CLK_SEL2; | 126 | rsnd_mod_bset(mod, AUDIO_CLK_SEL1, mask, val); |
50 | 127 | break; | |
51 | return reg; | 128 | case 2: |
129 | rsnd_mod_bset(mod, AUDIO_CLK_SEL2, mask, val); | ||
130 | break; | ||
131 | } | ||
52 | } | 132 | } |
53 | 133 | ||
54 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod) | 134 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod) |
55 | { | 135 | { |
56 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
57 | enum rsnd_reg reg; | ||
58 | int id; | ||
59 | |||
60 | /* | 136 | /* |
61 | * "mod" = "ssi" here. | 137 | * "mod" = "ssi" here. |
62 | * we can get "ssi id" from mod | 138 | * we can get "ssi id" from mod |
63 | */ | 139 | */ |
64 | id = rsnd_mod_id(mod); | 140 | rsnd_adg_set_ssi_clk(mod, 0); |
65 | reg = rsnd_adg_ssi_reg_get(id); | ||
66 | |||
67 | rsnd_write(priv, mod, reg, 0); | ||
68 | 141 | ||
69 | return 0; | 142 | return 0; |
70 | } | 143 | } |
@@ -75,8 +148,7 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) | |||
75 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | 148 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
76 | struct device *dev = rsnd_priv_to_dev(priv); | 149 | struct device *dev = rsnd_priv_to_dev(priv); |
77 | struct clk *clk; | 150 | struct clk *clk; |
78 | enum rsnd_reg reg; | 151 | int i; |
79 | int id, shift, i; | ||
80 | u32 data; | 152 | u32 data; |
81 | int sel_table[] = { | 153 | int sel_table[] = { |
82 | [CLKA] = 0x1, | 154 | [CLKA] = 0x1, |
@@ -102,12 +174,12 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) | |||
102 | /* | 174 | /* |
103 | * find 1/6 clock from BRGA/BRGB | 175 | * find 1/6 clock from BRGA/BRGB |
104 | */ | 176 | */ |
105 | if (rate == adg->rate_of_441khz_div_6) { | 177 | if (rate == adg->rbga_rate_for_441khz_div_6) { |
106 | data = 0x10; | 178 | data = 0x10; |
107 | goto found_clock; | 179 | goto found_clock; |
108 | } | 180 | } |
109 | 181 | ||
110 | if (rate == adg->rate_of_48khz_div_6) { | 182 | if (rate == adg->rbgb_rate_for_48khz_div_6) { |
111 | data = 0x20; | 183 | data = 0x20; |
112 | goto found_clock; | 184 | goto found_clock; |
113 | } | 185 | } |
@@ -125,19 +197,10 @@ found_clock: | |||
125 | * This "mod" = "ssi" here. | 197 | * This "mod" = "ssi" here. |
126 | * we can get "ssi id" from mod | 198 | * we can get "ssi id" from mod |
127 | */ | 199 | */ |
128 | id = rsnd_mod_id(mod); | 200 | rsnd_adg_set_ssi_clk(mod, data); |
129 | reg = rsnd_adg_ssi_reg_get(id); | ||
130 | |||
131 | dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate); | ||
132 | |||
133 | /* | ||
134 | * Enable SSIx clock | ||
135 | */ | ||
136 | shift = (id % 4) * 8; | ||
137 | 201 | ||
138 | rsnd_bset(priv, mod, reg, | 202 | dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", |
139 | 0xFF << shift, | 203 | rsnd_mod_id(mod), i, rate); |
140 | data << shift); | ||
141 | 204 | ||
142 | return 0; | 205 | return 0; |
143 | } | 206 | } |
@@ -166,8 +229,8 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) | |||
166 | * rsnd_adg_ssi_clk_try_start() | 229 | * rsnd_adg_ssi_clk_try_start() |
167 | */ | 230 | */ |
168 | ckr = 0; | 231 | ckr = 0; |
169 | adg->rate_of_441khz_div_6 = 0; | 232 | adg->rbga_rate_for_441khz_div_6 = 0; |
170 | adg->rate_of_48khz_div_6 = 0; | 233 | adg->rbgb_rate_for_48khz_div_6 = 0; |
171 | for_each_rsnd_clk(clk, adg, i) { | 234 | for_each_rsnd_clk(clk, adg, i) { |
172 | rate = clk_get_rate(clk); | 235 | rate = clk_get_rate(clk); |
173 | 236 | ||
@@ -175,14 +238,14 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) | |||
175 | continue; | 238 | continue; |
176 | 239 | ||
177 | /* RBGA */ | 240 | /* RBGA */ |
178 | if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) { | 241 | if (!adg->rbga_rate_for_441khz_div_6 && (0 == rate % 44100)) { |
179 | adg->rate_of_441khz_div_6 = rate / 6; | 242 | adg->rbga_rate_for_441khz_div_6 = rate / 6; |
180 | ckr |= brg_table[i] << 20; | 243 | ckr |= brg_table[i] << 20; |
181 | } | 244 | } |
182 | 245 | ||
183 | /* RBGB */ | 246 | /* RBGB */ |
184 | if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) { | 247 | if (!adg->rbgb_rate_for_48khz_div_6 && (0 == rate % 48000)) { |
185 | adg->rate_of_48khz_div_6 = rate / 6; | 248 | adg->rbgb_rate_for_48khz_div_6 = rate / 6; |
186 | ckr |= brg_table[i] << 16; | 249 | ckr |= brg_table[i] << 16; |
187 | } | 250 | } |
188 | } | 251 | } |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 61212ee97c28..add088bd4b2a 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -10,20 +10,6 @@ | |||
10 | */ | 10 | */ |
11 | #include "rsnd.h" | 11 | #include "rsnd.h" |
12 | 12 | ||
13 | struct rsnd_gen_ops { | ||
14 | int (*probe)(struct platform_device *pdev, | ||
15 | struct rcar_snd_info *info, | ||
16 | struct rsnd_priv *priv); | ||
17 | void (*remove)(struct platform_device *pdev, | ||
18 | struct rsnd_priv *priv); | ||
19 | int (*path_init)(struct rsnd_priv *priv, | ||
20 | struct rsnd_dai *rdai, | ||
21 | struct rsnd_dai_stream *io); | ||
22 | int (*path_exit)(struct rsnd_priv *priv, | ||
23 | struct rsnd_dai *rdai, | ||
24 | struct rsnd_dai_stream *io); | ||
25 | }; | ||
26 | |||
27 | struct rsnd_gen { | 13 | struct rsnd_gen { |
28 | void __iomem *base[RSND_BASE_MAX]; | 14 | void __iomem *base[RSND_BASE_MAX]; |
29 | 15 | ||
@@ -86,12 +72,28 @@ static struct regmap_bus rsnd_regmap_bus = { | |||
86 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | 72 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, |
87 | }; | 73 | }; |
88 | 74 | ||
75 | static int rsnd_is_accessible_reg(struct rsnd_priv *priv, | ||
76 | struct rsnd_gen *gen, enum rsnd_reg reg) | ||
77 | { | ||
78 | if (!gen->regs[reg]) { | ||
79 | struct device *dev = rsnd_priv_to_dev(priv); | ||
80 | |||
81 | dev_err(dev, "unsupported register access %x\n", reg); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | return 1; | ||
86 | } | ||
87 | |||
89 | u32 rsnd_read(struct rsnd_priv *priv, | 88 | u32 rsnd_read(struct rsnd_priv *priv, |
90 | struct rsnd_mod *mod, enum rsnd_reg reg) | 89 | struct rsnd_mod *mod, enum rsnd_reg reg) |
91 | { | 90 | { |
92 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 91 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
93 | u32 val; | 92 | u32 val; |
94 | 93 | ||
94 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | ||
95 | return 0; | ||
96 | |||
95 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); | 97 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); |
96 | 98 | ||
97 | return val; | 99 | return val; |
@@ -103,6 +105,9 @@ void rsnd_write(struct rsnd_priv *priv, | |||
103 | { | 105 | { |
104 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 106 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
105 | 107 | ||
108 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | ||
109 | return; | ||
110 | |||
106 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); | 111 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); |
107 | } | 112 | } |
108 | 113 | ||
@@ -111,21 +116,48 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
111 | { | 116 | { |
112 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 117 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
113 | 118 | ||
119 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | ||
120 | return; | ||
121 | |||
114 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), | 122 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), |
115 | mask, data); | 123 | mask, data); |
116 | } | 124 | } |
117 | 125 | ||
118 | /* | 126 | static int rsnd_gen_regmap_init(struct rsnd_priv *priv, |
119 | * Gen2 | 127 | struct rsnd_gen *gen, |
120 | * will be filled in the future | 128 | struct reg_field *regf) |
121 | */ | 129 | { |
130 | int i; | ||
131 | struct device *dev = rsnd_priv_to_dev(priv); | ||
132 | struct regmap_config regc; | ||
122 | 133 | ||
123 | /* | 134 | memset(®c, 0, sizeof(regc)); |
124 | * Gen1 | 135 | regc.reg_bits = 32; |
125 | */ | 136 | regc.val_bits = 32; |
126 | static int rsnd_gen1_path_init(struct rsnd_priv *priv, | 137 | |
127 | struct rsnd_dai *rdai, | 138 | gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); |
128 | struct rsnd_dai_stream *io) | 139 | if (IS_ERR(gen->regmap)) { |
140 | dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); | ||
141 | return PTR_ERR(gen->regmap); | ||
142 | } | ||
143 | |||
144 | for (i = 0; i < RSND_REG_MAX; i++) { | ||
145 | gen->regs[i] = NULL; | ||
146 | if (!regf[i].reg) | ||
147 | continue; | ||
148 | |||
149 | gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); | ||
150 | if (IS_ERR(gen->regs[i])) | ||
151 | return PTR_ERR(gen->regs[i]); | ||
152 | |||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
159 | struct rsnd_dai *rdai, | ||
160 | struct rsnd_dai_stream *io) | ||
129 | { | 161 | { |
130 | struct rsnd_mod *mod; | 162 | struct rsnd_mod *mod; |
131 | int ret; | 163 | int ret; |
@@ -163,9 +195,9 @@ static int rsnd_gen1_path_init(struct rsnd_priv *priv, | |||
163 | return ret; | 195 | return ret; |
164 | } | 196 | } |
165 | 197 | ||
166 | static int rsnd_gen1_path_exit(struct rsnd_priv *priv, | 198 | int rsnd_gen_path_exit(struct rsnd_priv *priv, |
167 | struct rsnd_dai *rdai, | 199 | struct rsnd_dai *rdai, |
168 | struct rsnd_dai_stream *io) | 200 | struct rsnd_dai_stream *io) |
169 | { | 201 | { |
170 | struct rsnd_mod *mod, *n; | 202 | struct rsnd_mod *mod, *n; |
171 | int ret = 0; | 203 | int ret = 0; |
@@ -179,6 +211,94 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv, | |||
179 | return ret; | 211 | return ret; |
180 | } | 212 | } |
181 | 213 | ||
214 | /* | ||
215 | * Gen2 | ||
216 | */ | ||
217 | |||
218 | /* single address mapping */ | ||
219 | #define RSND_GEN2_S_REG(gen, reg, id, offset) \ | ||
220 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10) | ||
221 | |||
222 | /* multi address mapping */ | ||
223 | #define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset) \ | ||
224 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10) | ||
225 | |||
226 | static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | ||
227 | { | ||
228 | struct reg_field regf[RSND_REG_MAX] = { | ||
229 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), | ||
230 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), | ||
231 | /* FIXME: it needs SSI_MODE2/3 in the future */ | ||
232 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), | ||
233 | |||
234 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), | ||
235 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), | ||
236 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), | ||
237 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | ||
238 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | ||
239 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), | ||
240 | |||
241 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), | ||
242 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), | ||
243 | RSND_GEN2_M_REG(gen, SSI, SSITDR, 0x08, 0x40), | ||
244 | RSND_GEN2_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), | ||
245 | RSND_GEN2_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), | ||
246 | }; | ||
247 | |||
248 | return rsnd_gen_regmap_init(priv, gen, regf); | ||
249 | } | ||
250 | |||
251 | static int rsnd_gen2_probe(struct platform_device *pdev, | ||
252 | struct rcar_snd_info *info, | ||
253 | struct rsnd_priv *priv) | ||
254 | { | ||
255 | struct device *dev = rsnd_priv_to_dev(priv); | ||
256 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
257 | struct resource *scu_res; | ||
258 | struct resource *adg_res; | ||
259 | struct resource *ssiu_res; | ||
260 | struct resource *ssi_res; | ||
261 | int ret; | ||
262 | |||
263 | /* | ||
264 | * map address | ||
265 | */ | ||
266 | scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU); | ||
267 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG); | ||
268 | ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU); | ||
269 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI); | ||
270 | |||
271 | gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res); | ||
272 | gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res); | ||
273 | gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res); | ||
274 | gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res); | ||
275 | if (IS_ERR(gen->base[RSND_GEN2_SCU]) || | ||
276 | IS_ERR(gen->base[RSND_GEN2_ADG]) || | ||
277 | IS_ERR(gen->base[RSND_GEN2_SSIU]) || | ||
278 | IS_ERR(gen->base[RSND_GEN2_SSI])) | ||
279 | return -ENODEV; | ||
280 | |||
281 | ret = rsnd_gen2_regmap_init(priv, gen); | ||
282 | if (ret < 0) | ||
283 | return ret; | ||
284 | |||
285 | dev_dbg(dev, "Gen2 device probed\n"); | ||
286 | dev_dbg(dev, "SRU : %08x => %p\n", scu_res->start, | ||
287 | gen->base[RSND_GEN2_SCU]); | ||
288 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, | ||
289 | gen->base[RSND_GEN2_ADG]); | ||
290 | dev_dbg(dev, "SSIU : %08x => %p\n", ssiu_res->start, | ||
291 | gen->base[RSND_GEN2_SSIU]); | ||
292 | dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, | ||
293 | gen->base[RSND_GEN2_SSI]); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Gen1 | ||
300 | */ | ||
301 | |||
182 | /* single address mapping */ | 302 | /* single address mapping */ |
183 | #define RSND_GEN1_S_REG(gen, reg, id, offset) \ | 303 | #define RSND_GEN1_S_REG(gen, reg, id, offset) \ |
184 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) | 304 | RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) |
@@ -189,19 +309,23 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv, | |||
189 | 309 | ||
190 | static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | 310 | static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) |
191 | { | 311 | { |
192 | int i; | ||
193 | struct device *dev = rsnd_priv_to_dev(priv); | ||
194 | struct regmap_config regc; | ||
195 | struct reg_field regf[RSND_REG_MAX] = { | 312 | struct reg_field regf[RSND_REG_MAX] = { |
196 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), | 313 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), |
197 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), | 314 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), |
198 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), | 315 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), |
199 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), | 316 | RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), |
200 | RSND_GEN1_S_REG(gen, SRU, SRC_CTRL, 0xc0), | 317 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), |
201 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), | 318 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), |
202 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), | 319 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), |
203 | RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), | 320 | RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), |
204 | RSND_GEN1_M_REG(gen, SRU, BUSIF_ADINR, 0x214, 0x40), | 321 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), |
322 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), | ||
323 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), | ||
324 | RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40), | ||
325 | RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40), | ||
326 | RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40), | ||
327 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40), | ||
328 | RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40), | ||
205 | 329 | ||
206 | RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), | 330 | RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), |
207 | RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), | 331 | RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), |
@@ -219,24 +343,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
219 | RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), | 343 | RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), |
220 | }; | 344 | }; |
221 | 345 | ||
222 | memset(®c, 0, sizeof(regc)); | 346 | return rsnd_gen_regmap_init(priv, gen, regf); |
223 | regc.reg_bits = 32; | ||
224 | regc.val_bits = 32; | ||
225 | |||
226 | gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); | ||
227 | if (IS_ERR(gen->regmap)) { | ||
228 | dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); | ||
229 | return PTR_ERR(gen->regmap); | ||
230 | } | ||
231 | |||
232 | for (i = 0; i < RSND_REG_MAX; i++) { | ||
233 | gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); | ||
234 | if (IS_ERR(gen->regs[i])) | ||
235 | return PTR_ERR(gen->regs[i]); | ||
236 | |||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | 347 | } |
241 | 348 | ||
242 | static int rsnd_gen1_probe(struct platform_device *pdev, | 349 | static int rsnd_gen1_probe(struct platform_device *pdev, |
@@ -281,45 +388,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev, | |||
281 | 388 | ||
282 | } | 389 | } |
283 | 390 | ||
284 | static void rsnd_gen1_remove(struct platform_device *pdev, | ||
285 | struct rsnd_priv *priv) | ||
286 | { | ||
287 | } | ||
288 | |||
289 | static struct rsnd_gen_ops rsnd_gen1_ops = { | ||
290 | .probe = rsnd_gen1_probe, | ||
291 | .remove = rsnd_gen1_remove, | ||
292 | .path_init = rsnd_gen1_path_init, | ||
293 | .path_exit = rsnd_gen1_path_exit, | ||
294 | }; | ||
295 | |||
296 | /* | 391 | /* |
297 | * Gen | 392 | * Gen |
298 | */ | 393 | */ |
299 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
300 | struct rsnd_dai *rdai, | ||
301 | struct rsnd_dai_stream *io) | ||
302 | { | ||
303 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
304 | |||
305 | return gen->ops->path_init(priv, rdai, io); | ||
306 | } | ||
307 | |||
308 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
309 | struct rsnd_dai *rdai, | ||
310 | struct rsnd_dai_stream *io) | ||
311 | { | ||
312 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
313 | |||
314 | return gen->ops->path_exit(priv, rdai, io); | ||
315 | } | ||
316 | |||
317 | int rsnd_gen_probe(struct platform_device *pdev, | 394 | int rsnd_gen_probe(struct platform_device *pdev, |
318 | struct rcar_snd_info *info, | 395 | struct rcar_snd_info *info, |
319 | struct rsnd_priv *priv) | 396 | struct rsnd_priv *priv) |
320 | { | 397 | { |
321 | struct device *dev = rsnd_priv_to_dev(priv); | 398 | struct device *dev = rsnd_priv_to_dev(priv); |
322 | struct rsnd_gen *gen; | 399 | struct rsnd_gen *gen; |
400 | int ret; | ||
323 | 401 | ||
324 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); | 402 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); |
325 | if (!gen) { | 403 | if (!gen) { |
@@ -327,23 +405,21 @@ int rsnd_gen_probe(struct platform_device *pdev, | |||
327 | return -ENOMEM; | 405 | return -ENOMEM; |
328 | } | 406 | } |
329 | 407 | ||
408 | priv->gen = gen; | ||
409 | |||
410 | ret = -ENODEV; | ||
330 | if (rsnd_is_gen1(priv)) | 411 | if (rsnd_is_gen1(priv)) |
331 | gen->ops = &rsnd_gen1_ops; | 412 | ret = rsnd_gen1_probe(pdev, info, priv); |
413 | else if (rsnd_is_gen2(priv)) | ||
414 | ret = rsnd_gen2_probe(pdev, info, priv); | ||
332 | 415 | ||
333 | if (!gen->ops) { | 416 | if (ret < 0) |
334 | dev_err(dev, "unknown generation R-Car sound device\n"); | 417 | dev_err(dev, "unknown generation R-Car sound device\n"); |
335 | return -ENODEV; | ||
336 | } | ||
337 | |||
338 | priv->gen = gen; | ||
339 | 418 | ||
340 | return gen->ops->probe(pdev, info, priv); | 419 | return ret; |
341 | } | 420 | } |
342 | 421 | ||
343 | void rsnd_gen_remove(struct platform_device *pdev, | 422 | void rsnd_gen_remove(struct platform_device *pdev, |
344 | struct rsnd_priv *priv) | 423 | struct rsnd_priv *priv) |
345 | { | 424 | { |
346 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | ||
347 | |||
348 | gen->ops->remove(pdev, priv); | ||
349 | } | 425 | } |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9e463e50e7e6..4ca66cd899c8 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -31,16 +31,24 @@ | |||
31 | * see gen1/gen2 for detail | 31 | * see gen1/gen2 for detail |
32 | */ | 32 | */ |
33 | enum rsnd_reg { | 33 | enum rsnd_reg { |
34 | /* SRU/SCU */ | 34 | /* SRU/SCU/SSIU */ |
35 | RSND_REG_SRC_ROUTE_SEL, | 35 | RSND_REG_SRC_ROUTE_SEL, /* for Gen1 */ |
36 | RSND_REG_SRC_TMG_SEL0, | 36 | RSND_REG_SRC_TMG_SEL0, /* for Gen1 */ |
37 | RSND_REG_SRC_TMG_SEL1, | 37 | RSND_REG_SRC_TMG_SEL1, /* for Gen1 */ |
38 | RSND_REG_SRC_TMG_SEL2, | 38 | RSND_REG_SRC_TMG_SEL2, /* for Gen1 */ |
39 | RSND_REG_SRC_CTRL, | 39 | RSND_REG_SRC_ROUTE_CTRL, /* for Gen1 */ |
40 | RSND_REG_SSI_MODE0, | 40 | RSND_REG_SSI_MODE0, |
41 | RSND_REG_SSI_MODE1, | 41 | RSND_REG_SSI_MODE1, |
42 | RSND_REG_BUSIF_MODE, | 42 | RSND_REG_BUSIF_MODE, |
43 | RSND_REG_BUSIF_ADINR, | 43 | RSND_REG_INT_ENABLE, /* for Gen2 */ |
44 | RSND_REG_SRC_ROUTE_MODE0, | ||
45 | RSND_REG_SRC_SWRSR, | ||
46 | RSND_REG_SRC_SRCIR, | ||
47 | RSND_REG_SRC_ADINR, | ||
48 | RSND_REG_SRC_IFSCR, | ||
49 | RSND_REG_SRC_IFSVR, | ||
50 | RSND_REG_SRC_SRCCR, | ||
51 | RSND_REG_SRC_MNFSR, | ||
44 | 52 | ||
45 | /* ADG */ | 53 | /* ADG */ |
46 | RSND_REG_BRRA, | 54 | RSND_REG_BRRA, |
@@ -49,9 +57,9 @@ enum rsnd_reg { | |||
49 | RSND_REG_AUDIO_CLK_SEL0, | 57 | RSND_REG_AUDIO_CLK_SEL0, |
50 | RSND_REG_AUDIO_CLK_SEL1, | 58 | RSND_REG_AUDIO_CLK_SEL1, |
51 | RSND_REG_AUDIO_CLK_SEL2, | 59 | RSND_REG_AUDIO_CLK_SEL2, |
52 | RSND_REG_AUDIO_CLK_SEL3, | 60 | RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */ |
53 | RSND_REG_AUDIO_CLK_SEL4, | 61 | RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */ |
54 | RSND_REG_AUDIO_CLK_SEL5, | 62 | RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */ |
55 | 63 | ||
56 | /* SSI */ | 64 | /* SSI */ |
57 | RSND_REG_SSICR, | 65 | RSND_REG_SSICR, |
@@ -174,11 +182,11 @@ struct rsnd_dai { | |||
174 | struct rsnd_dai_stream playback; | 182 | struct rsnd_dai_stream playback; |
175 | struct rsnd_dai_stream capture; | 183 | struct rsnd_dai_stream capture; |
176 | 184 | ||
177 | int clk_master:1; | 185 | unsigned int clk_master:1; |
178 | int bit_clk_inv:1; | 186 | unsigned int bit_clk_inv:1; |
179 | int frm_clk_inv:1; | 187 | unsigned int frm_clk_inv:1; |
180 | int sys_delay:1; | 188 | unsigned int sys_delay:1; |
181 | int data_alignment:1; | 189 | unsigned int data_alignment:1; |
182 | }; | 190 | }; |
183 | 191 | ||
184 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) | 192 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) |
@@ -229,6 +237,10 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
229 | struct rsnd_priv *priv); | 237 | struct rsnd_priv *priv); |
230 | void rsnd_adg_remove(struct platform_device *pdev, | 238 | void rsnd_adg_remove(struct platform_device *pdev, |
231 | struct rsnd_priv *priv); | 239 | struct rsnd_priv *priv); |
240 | int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, | ||
241 | struct rsnd_mod *mod, | ||
242 | unsigned int src_rate, | ||
243 | unsigned int dst_rate); | ||
232 | 244 | ||
233 | /* | 245 | /* |
234 | * R-Car sound priv | 246 | * R-Car sound priv |
@@ -282,6 +294,10 @@ void rsnd_scu_remove(struct platform_device *pdev, | |||
282 | struct rsnd_priv *priv); | 294 | struct rsnd_priv *priv); |
283 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); | 295 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); |
284 | bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); | 296 | bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); |
297 | unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, | ||
298 | struct rsnd_mod *ssi_mod, | ||
299 | struct snd_pcm_runtime *runtime); | ||
300 | |||
285 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) | 301 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) |
286 | 302 | ||
287 | /* | 303 | /* |
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c index fa8fa15860b9..9bb08bb1d455 100644 --- a/sound/soc/sh/rcar/scu.c +++ b/sound/soc/sh/rcar/scu.c | |||
@@ -13,9 +13,13 @@ | |||
13 | struct rsnd_scu { | 13 | struct rsnd_scu { |
14 | struct rsnd_scu_platform_info *info; /* rcar_snd.h */ | 14 | struct rsnd_scu_platform_info *info; /* rcar_snd.h */ |
15 | struct rsnd_mod mod; | 15 | struct rsnd_mod mod; |
16 | struct clk *clk; | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | #define rsnd_scu_mode_flags(p) ((p)->info->flags) | 19 | #define rsnd_scu_mode_flags(p) ((p)->info->flags) |
20 | #define rsnd_scu_convert_rate(p) ((p)->info->convert_rate) | ||
21 | |||
22 | #define RSND_SCU_NAME_SIZE 16 | ||
19 | 23 | ||
20 | /* | 24 | /* |
21 | * ADINR | 25 | * ADINR |
@@ -26,6 +30,15 @@ struct rsnd_scu { | |||
26 | #define OTBL_18 (6 << 16) | 30 | #define OTBL_18 (6 << 16) |
27 | #define OTBL_16 (8 << 16) | 31 | #define OTBL_16 (8 << 16) |
28 | 32 | ||
33 | /* | ||
34 | * image of SRC (Sampling Rate Converter) | ||
35 | * | ||
36 | * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ | ||
37 | * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | | ||
38 | * 44.1kHz <-> +-----+ +-----+ +-------+ | ||
39 | * ... | ||
40 | * | ||
41 | */ | ||
29 | 42 | ||
30 | #define rsnd_mod_to_scu(_mod) \ | 43 | #define rsnd_mod_to_scu(_mod) \ |
31 | container_of((_mod), struct rsnd_scu, mod) | 44 | container_of((_mod), struct rsnd_scu, mod) |
@@ -36,7 +49,8 @@ struct rsnd_scu { | |||
36 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ | 49 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ |
37 | i++) | 50 | i++) |
38 | 51 | ||
39 | static int rsnd_scu_set_route(struct rsnd_priv *priv, | 52 | /* Gen1 only */ |
53 | static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, | ||
40 | struct rsnd_mod *mod, | 54 | struct rsnd_mod *mod, |
41 | struct rsnd_dai *rdai, | 55 | struct rsnd_dai *rdai, |
42 | struct rsnd_dai_stream *io) | 56 | struct rsnd_dai_stream *io) |
@@ -55,7 +69,7 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv, | |||
55 | { 0x3, 28, }, /* 7 */ | 69 | { 0x3, 28, }, /* 7 */ |
56 | { 0x3, 30, }, /* 8 */ | 70 | { 0x3, 30, }, /* 8 */ |
57 | }; | 71 | }; |
58 | 72 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | |
59 | u32 mask; | 73 | u32 mask; |
60 | u32 val; | 74 | u32 val; |
61 | int shift; | 75 | int shift; |
@@ -85,9 +99,18 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv, | |||
85 | */ | 99 | */ |
86 | shift = (id % 4) * 8; | 100 | shift = (id % 4) * 8; |
87 | mask = 0x1F << shift; | 101 | mask = 0x1F << shift; |
88 | if (8 == id) /* SRU8 is very special */ | 102 | |
103 | /* | ||
104 | * ADG is used as source clock if SRC was used, | ||
105 | * then, SSI WS is used as destination clock. | ||
106 | * SSI WS is used as source clock if SRC is not used | ||
107 | * (when playback, source/destination become reverse when capture) | ||
108 | */ | ||
109 | if (rsnd_scu_convert_rate(scu)) /* use ADG */ | ||
110 | val = 0; | ||
111 | else if (8 == id) /* use SSI WS, but SRU8 is special */ | ||
89 | val = id << shift; | 112 | val = id << shift; |
90 | else | 113 | else /* use SSI WS */ |
91 | val = (id + 1) << shift; | 114 | val = (id + 1) << shift; |
92 | 115 | ||
93 | switch (id / 4) { | 116 | switch (id / 4) { |
@@ -105,30 +128,45 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv, | |||
105 | return 0; | 128 | return 0; |
106 | } | 129 | } |
107 | 130 | ||
108 | static int rsnd_scu_set_mode(struct rsnd_priv *priv, | 131 | unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, |
109 | struct rsnd_mod *mod, | 132 | struct rsnd_mod *ssi_mod, |
110 | struct rsnd_dai *rdai, | 133 | struct snd_pcm_runtime *runtime) |
111 | struct rsnd_dai_stream *io) | ||
112 | { | 134 | { |
113 | int id = rsnd_mod_id(mod); | 135 | struct rsnd_scu *scu; |
114 | u32 val; | 136 | unsigned int rate; |
115 | 137 | ||
116 | if (rsnd_is_gen1(priv)) { | 138 | /* this function is assuming SSI id = SCU id here */ |
117 | val = (1 << id); | 139 | scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod))); |
118 | rsnd_mod_bset(mod, SRC_CTRL, val, val); | ||
119 | } | ||
120 | 140 | ||
121 | return 0; | 141 | /* |
142 | * return convert rate if SRC is used, | ||
143 | * otherwise, return runtime->rate as usual | ||
144 | */ | ||
145 | rate = rsnd_scu_convert_rate(scu); | ||
146 | if (!rate) | ||
147 | rate = runtime->rate; | ||
148 | |||
149 | return rate; | ||
122 | } | 150 | } |
123 | 151 | ||
124 | static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, | 152 | static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv, |
125 | struct rsnd_mod *mod, | 153 | struct rsnd_mod *mod, |
126 | struct rsnd_dai *rdai, | 154 | struct rsnd_dai *rdai, |
127 | struct rsnd_dai_stream *io) | 155 | struct rsnd_dai_stream *io) |
128 | { | 156 | { |
129 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 157 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
158 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
159 | u32 convert_rate = rsnd_scu_convert_rate(scu); | ||
130 | u32 adinr = runtime->channels; | 160 | u32 adinr = runtime->channels; |
131 | 161 | ||
162 | /* set/clear soft reset */ | ||
163 | rsnd_mod_write(mod, SRC_SWRSR, 0); | ||
164 | rsnd_mod_write(mod, SRC_SWRSR, 1); | ||
165 | |||
166 | /* Initialize the operation of the SRC internal circuits */ | ||
167 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
168 | |||
169 | /* Set channel number and output bit length */ | ||
132 | switch (runtime->sample_bits) { | 170 | switch (runtime->sample_bits) { |
133 | case 16: | 171 | case 16: |
134 | adinr |= OTBL_16; | 172 | adinr |= OTBL_16; |
@@ -139,9 +177,81 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, | |||
139 | default: | 177 | default: |
140 | return -EIO; | 178 | return -EIO; |
141 | } | 179 | } |
180 | rsnd_mod_write(mod, SRC_ADINR, adinr); | ||
181 | |||
182 | if (convert_rate) { | ||
183 | u32 fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
184 | int ret; | ||
185 | |||
186 | /* Enable the initial value of IFS */ | ||
187 | rsnd_mod_write(mod, SRC_IFSCR, 1); | ||
188 | |||
189 | /* Set initial value of IFS */ | ||
190 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
191 | |||
192 | /* Select SRC mode (fixed value) */ | ||
193 | rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); | ||
194 | |||
195 | /* Set the restriction value of the FS ratio (98%) */ | ||
196 | rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98); | ||
197 | |||
198 | if (rsnd_is_gen1(priv)) { | ||
199 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | ||
200 | } | ||
142 | 201 | ||
202 | /* set convert clock */ | ||
203 | ret = rsnd_adg_set_convert_clk(priv, mod, | ||
204 | runtime->rate, | ||
205 | convert_rate); | ||
206 | if (ret < 0) | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | /* Cancel the initialization and operate the SRC function */ | ||
211 | rsnd_mod_write(mod, SRC_SRCIR, 0); | ||
212 | |||
213 | /* use DMA transfer */ | ||
143 | rsnd_mod_write(mod, BUSIF_MODE, 1); | 214 | rsnd_mod_write(mod, BUSIF_MODE, 1); |
144 | rsnd_mod_write(mod, BUSIF_ADINR, adinr); | 215 | |
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int rsnd_scu_transfer_start(struct rsnd_priv *priv, | ||
220 | struct rsnd_mod *mod, | ||
221 | struct rsnd_dai *rdai, | ||
222 | struct rsnd_dai_stream *io) | ||
223 | { | ||
224 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
225 | int id = rsnd_mod_id(mod); | ||
226 | u32 val; | ||
227 | |||
228 | if (rsnd_is_gen1(priv)) { | ||
229 | val = (1 << id); | ||
230 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); | ||
231 | } | ||
232 | |||
233 | if (rsnd_scu_convert_rate(scu)) | ||
234 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int rsnd_scu_transfer_stop(struct rsnd_priv *priv, | ||
240 | struct rsnd_mod *mod, | ||
241 | struct rsnd_dai *rdai, | ||
242 | struct rsnd_dai_stream *io) | ||
243 | { | ||
244 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
245 | int id = rsnd_mod_id(mod); | ||
246 | u32 mask; | ||
247 | |||
248 | if (rsnd_is_gen1(priv)) { | ||
249 | mask = (1 << id); | ||
250 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0); | ||
251 | } | ||
252 | |||
253 | if (rsnd_scu_convert_rate(scu)) | ||
254 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
145 | 255 | ||
146 | return 0; | 256 | return 0; |
147 | } | 257 | } |
@@ -159,6 +269,7 @@ static int rsnd_scu_start(struct rsnd_mod *mod, | |||
159 | struct rsnd_dai_stream *io) | 269 | struct rsnd_dai_stream *io) |
160 | { | 270 | { |
161 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 271 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
272 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
162 | struct device *dev = rsnd_priv_to_dev(priv); | 273 | struct device *dev = rsnd_priv_to_dev(priv); |
163 | int ret; | 274 | int ret; |
164 | 275 | ||
@@ -173,16 +284,19 @@ static int rsnd_scu_start(struct rsnd_mod *mod, | |||
173 | return 0; | 284 | return 0; |
174 | } | 285 | } |
175 | 286 | ||
287 | clk_enable(scu->clk); | ||
288 | |||
176 | /* it use DMA transter */ | 289 | /* it use DMA transter */ |
177 | ret = rsnd_scu_set_route(priv, mod, rdai, io); | 290 | |
291 | ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io); | ||
178 | if (ret < 0) | 292 | if (ret < 0) |
179 | return ret; | 293 | return ret; |
180 | 294 | ||
181 | ret = rsnd_scu_set_mode(priv, mod, rdai, io); | 295 | ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io); |
182 | if (ret < 0) | 296 | if (ret < 0) |
183 | return ret; | 297 | return ret; |
184 | 298 | ||
185 | ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); | 299 | ret = rsnd_scu_transfer_start(priv, mod, rdai, io); |
186 | if (ret < 0) | 300 | if (ret < 0) |
187 | return ret; | 301 | return ret; |
188 | 302 | ||
@@ -191,9 +305,27 @@ static int rsnd_scu_start(struct rsnd_mod *mod, | |||
191 | return 0; | 305 | return 0; |
192 | } | 306 | } |
193 | 307 | ||
308 | static int rsnd_scu_stop(struct rsnd_mod *mod, | ||
309 | struct rsnd_dai *rdai, | ||
310 | struct rsnd_dai_stream *io) | ||
311 | { | ||
312 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
313 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
314 | |||
315 | if (!rsnd_scu_hpbif_is_enable(mod)) | ||
316 | return 0; | ||
317 | |||
318 | rsnd_scu_transfer_stop(priv, mod, rdai, io); | ||
319 | |||
320 | clk_disable(scu->clk); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
194 | static struct rsnd_mod_ops rsnd_scu_ops = { | 325 | static struct rsnd_mod_ops rsnd_scu_ops = { |
195 | .name = "scu", | 326 | .name = "scu", |
196 | .start = rsnd_scu_start, | 327 | .start = rsnd_scu_start, |
328 | .stop = rsnd_scu_stop, | ||
197 | }; | 329 | }; |
198 | 330 | ||
199 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) | 331 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) |
@@ -210,6 +342,8 @@ int rsnd_scu_probe(struct platform_device *pdev, | |||
210 | { | 342 | { |
211 | struct device *dev = rsnd_priv_to_dev(priv); | 343 | struct device *dev = rsnd_priv_to_dev(priv); |
212 | struct rsnd_scu *scu; | 344 | struct rsnd_scu *scu; |
345 | struct clk *clk; | ||
346 | char name[RSND_SCU_NAME_SIZE]; | ||
213 | int i, nr; | 347 | int i, nr; |
214 | 348 | ||
215 | /* | 349 | /* |
@@ -226,9 +360,16 @@ int rsnd_scu_probe(struct platform_device *pdev, | |||
226 | priv->scu = scu; | 360 | priv->scu = scu; |
227 | 361 | ||
228 | for_each_rsnd_scu(scu, priv, i) { | 362 | for_each_rsnd_scu(scu, priv, i) { |
363 | snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i); | ||
364 | |||
365 | clk = devm_clk_get(dev, name); | ||
366 | if (IS_ERR(clk)) | ||
367 | return PTR_ERR(clk); | ||
368 | |||
229 | rsnd_mod_init(priv, &scu->mod, | 369 | rsnd_mod_init(priv, &scu->mod, |
230 | &rsnd_scu_ops, i); | 370 | &rsnd_scu_ops, i); |
231 | scu->info = &info->scu_info[i]; | 371 | scu->info = &info->scu_info[i]; |
372 | scu->clk = clk; | ||
232 | 373 | ||
233 | dev_dbg(dev, "SCU%d probed\n", i); | 374 | dev_dbg(dev, "SCU%d probed\n", i); |
234 | } | 375 | } |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 5ac20cd5e006..4b8cf7ca9d19 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -187,9 +187,10 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, | |||
187 | } | 187 | } |
188 | 188 | ||
189 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | 189 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, |
190 | unsigned int rate) | 190 | struct rsnd_dai_stream *io) |
191 | { | 191 | { |
192 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 192 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
193 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
193 | struct device *dev = rsnd_priv_to_dev(priv); | 194 | struct device *dev = rsnd_priv_to_dev(priv); |
194 | int i, j, ret; | 195 | int i, j, ret; |
195 | int adg_clk_div_table[] = { | 196 | int adg_clk_div_table[] = { |
@@ -199,6 +200,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
199 | 1, 2, 4, 8, 16, 6, 12, | 200 | 1, 2, 4, 8, 16, 6, 12, |
200 | }; | 201 | }; |
201 | unsigned int main_rate; | 202 | unsigned int main_rate; |
203 | unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime); | ||
202 | 204 | ||
203 | /* | 205 | /* |
204 | * Find best clock, and try to start ADG | 206 | * Find best clock, and try to start ADG |
@@ -209,7 +211,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
209 | /* | 211 | /* |
210 | * this driver is assuming that | 212 | * this driver is assuming that |
211 | * system word is 64fs (= 2 x 32bit) | 213 | * system word is 64fs (= 2 x 32bit) |
212 | * see rsnd_ssi_start() | 214 | * see rsnd_ssi_init() |
213 | */ | 215 | */ |
214 | main_rate = rate / adg_clk_div_table[i] | 216 | main_rate = rate / adg_clk_div_table[i] |
215 | * 32 * 2 * ssi_clk_mul_table[j]; | 217 | * 32 * 2 * ssi_clk_mul_table[j]; |
@@ -251,14 +253,10 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
251 | clk_enable(ssi->clk); | 253 | clk_enable(ssi->clk); |
252 | 254 | ||
253 | if (rsnd_rdai_is_clk_master(rdai)) { | 255 | if (rsnd_rdai_is_clk_master(rdai)) { |
254 | struct snd_pcm_runtime *runtime; | ||
255 | |||
256 | runtime = rsnd_io_to_runtime(io); | ||
257 | |||
258 | if (rsnd_ssi_clk_from_parent(ssi)) | 256 | if (rsnd_ssi_clk_from_parent(ssi)) |
259 | rsnd_ssi_hw_start(ssi->parent, rdai, io); | 257 | rsnd_ssi_hw_start(ssi->parent, rdai, io); |
260 | else | 258 | else |
261 | rsnd_ssi_master_clk_start(ssi, runtime->rate); | 259 | rsnd_ssi_master_clk_start(ssi, io); |
262 | } | 260 | } |
263 | } | 261 | } |
264 | 262 | ||
@@ -457,6 +455,10 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | |||
457 | /* enable PIO IRQ */ | 455 | /* enable PIO IRQ */ |
458 | ssi->cr_etc = UIEN | OIEN | DIEN; | 456 | ssi->cr_etc = UIEN | OIEN | DIEN; |
459 | 457 | ||
458 | /* enable PIO interrupt if gen2 */ | ||
459 | if (rsnd_is_gen2(priv)) | ||
460 | rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000); | ||
461 | |||
460 | rsnd_ssi_hw_start(ssi, rdai, io); | 462 | rsnd_ssi_hw_start(ssi, rdai, io); |
461 | 463 | ||
462 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 464 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
@@ -650,7 +652,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
650 | 652 | ||
651 | snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); | 653 | snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); |
652 | 654 | ||
653 | clk = clk_get(dev, name); | 655 | clk = devm_clk_get(dev, name); |
654 | if (IS_ERR(clk)) | 656 | if (IS_ERR(clk)) |
655 | return PTR_ERR(clk); | 657 | return PTR_ERR(clk); |
656 | 658 | ||
@@ -711,7 +713,6 @@ void rsnd_ssi_remove(struct platform_device *pdev, | |||
711 | int i; | 713 | int i; |
712 | 714 | ||
713 | for_each_rsnd_ssi(ssi, priv, i) { | 715 | for_each_rsnd_ssi(ssi, priv, i) { |
714 | clk_put(ssi->clk); | ||
715 | if (rsnd_ssi_dma_available(ssi)) | 716 | if (rsnd_ssi_dma_available(ssi)) |
716 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); | 717 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); |
717 | } | 718 | } |