Commit 374a528111fa07878090bd9694a3e153814de39c
Committed by
Mark Brown
1 parent
849fc82a6f
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
ASoC: rsnd: SSI supports DMA transfer via BUSIF
This patch adds BUSIF support for R-Car sound DMAEngine transfer. The sound data will be transferred via FIFO which can cover blank time which will happen when DMA channel is switching. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Showing 5 changed files with 190 additions and 7 deletions Inline Diff
include/sound/rcar_snd.h
1 | /* | 1 | /* |
2 | * Renesas R-Car SRU/SCU/SSIU/SSI support | 2 | * Renesas R-Car SRU/SCU/SSIU/SSI support |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Renesas Solutions Corp. | 4 | * Copyright (C) 2013 Renesas Solutions Corp. |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef RCAR_SND_H | 12 | #ifndef RCAR_SND_H |
13 | #define RCAR_SND_H | 13 | #define RCAR_SND_H |
14 | 14 | ||
15 | #include <linux/sh_clk.h> | 15 | #include <linux/sh_clk.h> |
16 | 16 | ||
17 | #define RSND_GEN1_SRU 0 | 17 | #define RSND_GEN1_SRU 0 |
18 | #define RSND_GEN1_ADG 1 | 18 | #define RSND_GEN1_ADG 1 |
19 | #define RSND_GEN1_SSI 2 | 19 | #define RSND_GEN1_SSI 2 |
20 | 20 | ||
21 | #define RSND_GEN2_SRU 0 | 21 | #define RSND_GEN2_SRU 0 |
22 | #define RSND_GEN2_ADG 1 | 22 | #define RSND_GEN2_ADG 1 |
23 | #define RSND_GEN2_SSIU 2 | 23 | #define RSND_GEN2_SSIU 2 |
24 | #define RSND_GEN2_SSI 3 | 24 | #define RSND_GEN2_SSI 3 |
25 | 25 | ||
26 | #define RSND_BASE_MAX 4 | 26 | #define RSND_BASE_MAX 4 |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * flags | 29 | * flags |
30 | * | 30 | * |
31 | * 0xAB000000 | 31 | * 0xAB000000 |
32 | * | 32 | * |
33 | * A : clock sharing settings | 33 | * A : clock sharing settings |
34 | * B : SSI direction | 34 | * B : SSI direction |
35 | */ | 35 | */ |
36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) | 36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) |
37 | #define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */ | 37 | #define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */ |
38 | #define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */ | 38 | #define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */ |
39 | #define RSND_SSI_DEPENDENT (1 << 28) /* SSI needs SRU/SCU */ | ||
39 | 40 | ||
40 | #define RSND_SSI_PLAY (1 << 24) | 41 | #define RSND_SSI_PLAY (1 << 24) |
41 | 42 | ||
42 | #define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \ | 43 | #define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \ |
43 | { .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } | 44 | { .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } |
44 | #define RSND_SSI_UNUSED \ | 45 | #define RSND_SSI_UNUSED \ |
45 | { .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 } | 46 | { .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 } |
46 | 47 | ||
47 | struct rsnd_ssi_platform_info { | 48 | struct rsnd_ssi_platform_info { |
48 | int dai_id; | 49 | int dai_id; |
49 | int dma_id; | 50 | int dma_id; |
50 | int pio_irq; | 51 | int pio_irq; |
51 | u32 flags; | 52 | u32 flags; |
52 | }; | 53 | }; |
54 | |||
55 | /* | ||
56 | * flags | ||
57 | */ | ||
58 | #define RSND_SCU_USB_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */ | ||
53 | 59 | ||
54 | struct rsnd_scu_platform_info { | 60 | struct rsnd_scu_platform_info { |
55 | u32 flags; | 61 | u32 flags; |
56 | }; | 62 | }; |
57 | 63 | ||
58 | /* | 64 | /* |
59 | * flags | 65 | * flags |
60 | * | 66 | * |
61 | * 0x0000000A | 67 | * 0x0000000A |
62 | * | 68 | * |
63 | * A : generation | 69 | * A : generation |
64 | */ | 70 | */ |
65 | #define RSND_GEN1 (1 << 0) /* fixme */ | 71 | #define RSND_GEN1 (1 << 0) /* fixme */ |
66 | #define RSND_GEN2 (2 << 0) /* fixme */ | 72 | #define RSND_GEN2 (2 << 0) /* fixme */ |
67 | 73 | ||
68 | struct rcar_snd_info { | 74 | struct rcar_snd_info { |
69 | u32 flags; | 75 | u32 flags; |
70 | struct rsnd_ssi_platform_info *ssi_info; | 76 | struct rsnd_ssi_platform_info *ssi_info; |
71 | int ssi_info_nr; | 77 | int ssi_info_nr; |
72 | struct rsnd_scu_platform_info *scu_info; | 78 | struct rsnd_scu_platform_info *scu_info; |
73 | int scu_info_nr; | 79 | int scu_info_nr; |
74 | int (*start)(int id); | 80 | int (*start)(int id); |
75 | int (*stop)(int id); | 81 | int (*stop)(int id); |
76 | }; | 82 | }; |
77 | 83 | ||
78 | #endif | 84 | #endif |
79 | 85 |
sound/soc/sh/rcar/gen.c
1 | /* | 1 | /* |
2 | * Renesas R-Car Gen1 SRU/SSI support | 2 | * Renesas R-Car Gen1 SRU/SSI support |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Renesas Solutions Corp. | 4 | * Copyright (C) 2013 Renesas Solutions Corp. |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include "rsnd.h" | 11 | #include "rsnd.h" |
12 | 12 | ||
13 | struct rsnd_gen_ops { | 13 | struct rsnd_gen_ops { |
14 | int (*path_init)(struct rsnd_priv *priv, | 14 | int (*path_init)(struct rsnd_priv *priv, |
15 | struct rsnd_dai *rdai, | 15 | struct rsnd_dai *rdai, |
16 | struct rsnd_dai_stream *io); | 16 | struct rsnd_dai_stream *io); |
17 | int (*path_exit)(struct rsnd_priv *priv, | 17 | int (*path_exit)(struct rsnd_priv *priv, |
18 | struct rsnd_dai *rdai, | 18 | struct rsnd_dai *rdai, |
19 | struct rsnd_dai_stream *io); | 19 | struct rsnd_dai_stream *io); |
20 | }; | 20 | }; |
21 | 21 | ||
22 | struct rsnd_gen_reg_map { | 22 | struct rsnd_gen_reg_map { |
23 | int index; /* -1 : not supported */ | 23 | int index; /* -1 : not supported */ |
24 | u32 offset_id; /* offset of ssi0, ssi1, ssi2... */ | 24 | u32 offset_id; /* offset of ssi0, ssi1, ssi2... */ |
25 | u32 offset_adr; /* offset of SSICR, SSISR, ... */ | 25 | u32 offset_adr; /* offset of SSICR, SSISR, ... */ |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct rsnd_gen { | 28 | struct rsnd_gen { |
29 | void __iomem *base[RSND_BASE_MAX]; | 29 | void __iomem *base[RSND_BASE_MAX]; |
30 | 30 | ||
31 | struct rsnd_gen_reg_map reg_map[RSND_REG_MAX]; | 31 | struct rsnd_gen_reg_map reg_map[RSND_REG_MAX]; |
32 | struct rsnd_gen_ops *ops; | 32 | struct rsnd_gen_ops *ops; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) | 35 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) |
36 | 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 | /* | 37 | /* |
41 | * Gen2 | 38 | * Gen2 |
42 | * will be filled in the future | 39 | * will be filled in the future |
43 | */ | 40 | */ |
44 | 41 | ||
45 | /* | 42 | /* |
46 | * Gen1 | 43 | * Gen1 |
47 | */ | 44 | */ |
48 | static int rsnd_gen1_path_init(struct rsnd_priv *priv, | 45 | static int rsnd_gen1_path_init(struct rsnd_priv *priv, |
49 | struct rsnd_dai *rdai, | 46 | struct rsnd_dai *rdai, |
50 | struct rsnd_dai_stream *io) | 47 | struct rsnd_dai_stream *io) |
51 | { | 48 | { |
52 | struct rsnd_mod *mod; | 49 | struct rsnd_mod *mod; |
53 | int ret; | 50 | int ret; |
54 | int id; | 51 | int id; |
55 | 52 | ||
56 | /* | 53 | /* |
57 | * Gen1 is created by SRU/SSI, and this SRU is base module of | 54 | * Gen1 is created by SRU/SSI, and this SRU is base module of |
58 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | 55 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) |
59 | * | 56 | * |
60 | * Easy image is.. | 57 | * Easy image is.. |
61 | * Gen1 SRU = Gen2 SCU + SSIU + etc | 58 | * Gen1 SRU = Gen2 SCU + SSIU + etc |
62 | * | 59 | * |
63 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | 60 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is |
64 | * using fixed path. | 61 | * using fixed path. |
65 | * | 62 | * |
66 | * Then, SSI id = SCU id here | 63 | * Then, SSI id = SCU id here |
67 | */ | 64 | */ |
68 | 65 | ||
69 | /* get SSI's ID */ | 66 | /* get SSI's ID */ |
70 | mod = rsnd_ssi_mod_get_frm_dai(priv, | 67 | mod = rsnd_ssi_mod_get_frm_dai(priv, |
71 | rsnd_dai_id(priv, rdai), | 68 | rsnd_dai_id(priv, rdai), |
72 | rsnd_dai_is_play(rdai, io)); | 69 | rsnd_dai_is_play(rdai, io)); |
73 | id = rsnd_mod_id(mod); | 70 | id = rsnd_mod_id(mod); |
74 | 71 | ||
75 | /* SSI */ | 72 | /* SSI */ |
76 | mod = rsnd_ssi_mod_get(priv, id); | 73 | mod = rsnd_ssi_mod_get(priv, id); |
77 | ret = rsnd_dai_connect(rdai, mod, io); | 74 | ret = rsnd_dai_connect(rdai, mod, io); |
78 | if (ret < 0) | 75 | if (ret < 0) |
79 | return ret; | 76 | return ret; |
80 | 77 | ||
81 | /* SCU */ | 78 | /* SCU */ |
82 | mod = rsnd_scu_mod_get(priv, id); | 79 | mod = rsnd_scu_mod_get(priv, id); |
83 | ret = rsnd_dai_connect(rdai, mod, io); | 80 | ret = rsnd_dai_connect(rdai, mod, io); |
84 | 81 | ||
85 | return ret; | 82 | return ret; |
86 | } | 83 | } |
87 | 84 | ||
88 | static int rsnd_gen1_path_exit(struct rsnd_priv *priv, | 85 | static int rsnd_gen1_path_exit(struct rsnd_priv *priv, |
89 | struct rsnd_dai *rdai, | 86 | struct rsnd_dai *rdai, |
90 | struct rsnd_dai_stream *io) | 87 | struct rsnd_dai_stream *io) |
91 | { | 88 | { |
92 | struct rsnd_mod *mod, *n; | 89 | struct rsnd_mod *mod, *n; |
93 | int ret = 0; | 90 | int ret = 0; |
94 | 91 | ||
95 | /* | 92 | /* |
96 | * remove all mod from rdai | 93 | * remove all mod from rdai |
97 | */ | 94 | */ |
98 | for_each_rsnd_mod(mod, n, io) | 95 | for_each_rsnd_mod(mod, n, io) |
99 | ret |= rsnd_dai_disconnect(mod); | 96 | ret |= rsnd_dai_disconnect(mod); |
100 | 97 | ||
101 | return ret; | 98 | return ret; |
102 | } | 99 | } |
103 | 100 | ||
104 | static struct rsnd_gen_ops rsnd_gen1_ops = { | 101 | static struct rsnd_gen_ops rsnd_gen1_ops = { |
105 | .path_init = rsnd_gen1_path_init, | 102 | .path_init = rsnd_gen1_path_init, |
106 | .path_exit = rsnd_gen1_path_exit, | 103 | .path_exit = rsnd_gen1_path_exit, |
107 | }; | 104 | }; |
108 | 105 | ||
109 | #define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \ | 106 | #define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \ |
110 | do { \ | 107 | do { \ |
111 | (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \ | 108 | (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \ |
112 | (g)->reg_map[RSND_REG_##i].offset_id = oi; \ | 109 | (g)->reg_map[RSND_REG_##i].offset_id = oi; \ |
113 | (g)->reg_map[RSND_REG_##i].offset_adr = oa; \ | 110 | (g)->reg_map[RSND_REG_##i].offset_adr = oa; \ |
114 | } while (0) | 111 | } while (0) |
115 | 112 | ||
116 | static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen) | 113 | static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen) |
117 | { | 114 | { |
115 | RSND_GEN1_REG_MAP(gen, SRU, SRC_ROUTE_SEL, 0x0, 0x00); | ||
116 | RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL0, 0x0, 0x08); | ||
117 | RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL1, 0x0, 0x0c); | ||
118 | RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL2, 0x0, 0x10); | ||
119 | RSND_GEN1_REG_MAP(gen, SRU, SRC_CTRL, 0x0, 0xc0); | ||
118 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0); | 120 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0); |
119 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4); | 121 | RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4); |
122 | RSND_GEN1_REG_MAP(gen, SRU, BUSIF_MODE, 0x4, 0x20); | ||
123 | RSND_GEN1_REG_MAP(gen, SRU, BUSIF_ADINR, 0x40, 0x214); | ||
120 | 124 | ||
121 | RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00); | 125 | RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00); |
122 | RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04); | 126 | RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04); |
123 | RSND_GEN1_REG_MAP(gen, ADG, SSICKR, 0x0, 0x08); | 127 | RSND_GEN1_REG_MAP(gen, ADG, SSICKR, 0x0, 0x08); |
124 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL0, 0x0, 0x0c); | 128 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL0, 0x0, 0x0c); |
125 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL1, 0x0, 0x10); | 129 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL1, 0x0, 0x10); |
126 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18); | 130 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18); |
127 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c); | 131 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c); |
128 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20); | 132 | RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20); |
129 | 133 | ||
130 | RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00); | 134 | RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00); |
131 | RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04); | 135 | RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04); |
132 | RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08); | 136 | RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08); |
133 | RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c); | 137 | RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c); |
134 | RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20); | 138 | RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20); |
135 | } | 139 | } |
136 | 140 | ||
137 | static int rsnd_gen1_probe(struct platform_device *pdev, | 141 | static int rsnd_gen1_probe(struct platform_device *pdev, |
138 | struct rcar_snd_info *info, | 142 | struct rcar_snd_info *info, |
139 | struct rsnd_priv *priv) | 143 | struct rsnd_priv *priv) |
140 | { | 144 | { |
141 | struct device *dev = rsnd_priv_to_dev(priv); | 145 | struct device *dev = rsnd_priv_to_dev(priv); |
142 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 146 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
143 | struct resource *sru_res; | 147 | struct resource *sru_res; |
144 | struct resource *adg_res; | 148 | struct resource *adg_res; |
145 | struct resource *ssi_res; | 149 | struct resource *ssi_res; |
146 | 150 | ||
147 | /* | 151 | /* |
148 | * map address | 152 | * map address |
149 | */ | 153 | */ |
150 | sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); | 154 | sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); |
151 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); | 155 | adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); |
152 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); | 156 | ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); |
153 | 157 | ||
154 | gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); | 158 | gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); |
155 | gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); | 159 | gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); |
156 | gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); | 160 | gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); |
157 | if (IS_ERR(gen->base[RSND_GEN1_SRU]) || | 161 | if (IS_ERR(gen->base[RSND_GEN1_SRU]) || |
158 | IS_ERR(gen->base[RSND_GEN1_ADG]) || | 162 | IS_ERR(gen->base[RSND_GEN1_ADG]) || |
159 | IS_ERR(gen->base[RSND_GEN1_SSI])) | 163 | IS_ERR(gen->base[RSND_GEN1_SSI])) |
160 | return -ENODEV; | 164 | return -ENODEV; |
161 | 165 | ||
162 | gen->ops = &rsnd_gen1_ops; | 166 | gen->ops = &rsnd_gen1_ops; |
163 | rsnd_gen1_reg_map_init(gen); | 167 | rsnd_gen1_reg_map_init(gen); |
164 | 168 | ||
165 | dev_dbg(dev, "Gen1 device probed\n"); | 169 | dev_dbg(dev, "Gen1 device probed\n"); |
166 | dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start, | 170 | dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start, |
167 | gen->base[RSND_GEN1_SRU]); | 171 | gen->base[RSND_GEN1_SRU]); |
168 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, | 172 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, |
169 | gen->base[RSND_GEN1_ADG]); | 173 | gen->base[RSND_GEN1_ADG]); |
170 | dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, | 174 | dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start, |
171 | gen->base[RSND_GEN1_SSI]); | 175 | gen->base[RSND_GEN1_SSI]); |
172 | 176 | ||
173 | return 0; | 177 | return 0; |
174 | 178 | ||
175 | } | 179 | } |
176 | 180 | ||
177 | static void rsnd_gen1_remove(struct platform_device *pdev, | 181 | static void rsnd_gen1_remove(struct platform_device *pdev, |
178 | struct rsnd_priv *priv) | 182 | struct rsnd_priv *priv) |
179 | { | 183 | { |
180 | } | 184 | } |
181 | 185 | ||
182 | /* | 186 | /* |
183 | * Gen | 187 | * Gen |
184 | */ | 188 | */ |
185 | int rsnd_gen_path_init(struct rsnd_priv *priv, | 189 | int rsnd_gen_path_init(struct rsnd_priv *priv, |
186 | struct rsnd_dai *rdai, | 190 | struct rsnd_dai *rdai, |
187 | struct rsnd_dai_stream *io) | 191 | struct rsnd_dai_stream *io) |
188 | { | 192 | { |
189 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 193 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
190 | 194 | ||
191 | return gen->ops->path_init(priv, rdai, io); | 195 | return gen->ops->path_init(priv, rdai, io); |
192 | } | 196 | } |
193 | 197 | ||
194 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | 198 | int rsnd_gen_path_exit(struct rsnd_priv *priv, |
195 | struct rsnd_dai *rdai, | 199 | struct rsnd_dai *rdai, |
196 | struct rsnd_dai_stream *io) | 200 | struct rsnd_dai_stream *io) |
197 | { | 201 | { |
198 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 202 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
199 | 203 | ||
200 | return gen->ops->path_exit(priv, rdai, io); | 204 | return gen->ops->path_exit(priv, rdai, io); |
201 | } | 205 | } |
202 | 206 | ||
203 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | 207 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
204 | struct rsnd_mod *mod, | 208 | struct rsnd_mod *mod, |
205 | enum rsnd_reg reg) | 209 | enum rsnd_reg reg) |
206 | { | 210 | { |
207 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); | 211 | struct rsnd_gen *gen = rsnd_priv_to_gen(priv); |
208 | struct device *dev = rsnd_priv_to_dev(priv); | 212 | struct device *dev = rsnd_priv_to_dev(priv); |
209 | int index; | 213 | int index; |
210 | u32 offset_id, offset_adr; | 214 | u32 offset_id, offset_adr; |
211 | 215 | ||
212 | if (reg >= RSND_REG_MAX) { | 216 | if (reg >= RSND_REG_MAX) { |
213 | dev_err(dev, "rsnd_reg reg error\n"); | 217 | dev_err(dev, "rsnd_reg reg error\n"); |
214 | return NULL; | 218 | return NULL; |
215 | } | 219 | } |
216 | 220 | ||
217 | index = gen->reg_map[reg].index; | 221 | index = gen->reg_map[reg].index; |
218 | offset_id = gen->reg_map[reg].offset_id; | 222 | offset_id = gen->reg_map[reg].offset_id; |
219 | offset_adr = gen->reg_map[reg].offset_adr; | 223 | offset_adr = gen->reg_map[reg].offset_adr; |
220 | 224 | ||
221 | if (index < 0) { | 225 | if (index < 0) { |
222 | dev_err(dev, "unsupported reg access %d\n", reg); | 226 | dev_err(dev, "unsupported reg access %d\n", reg); |
223 | return NULL; | 227 | return NULL; |
224 | } | 228 | } |
225 | 229 | ||
226 | if (offset_id && mod) | 230 | if (offset_id && mod) |
227 | offset_id *= rsnd_mod_id(mod); | 231 | offset_id *= rsnd_mod_id(mod); |
228 | 232 | ||
229 | /* | 233 | /* |
230 | * index/offset were set on gen1/gen2 | 234 | * index/offset were set on gen1/gen2 |
231 | */ | 235 | */ |
232 | 236 | ||
233 | return gen->base[index] + offset_id + offset_adr; | 237 | return gen->base[index] + offset_id + offset_adr; |
234 | } | 238 | } |
235 | 239 | ||
236 | int rsnd_gen_probe(struct platform_device *pdev, | 240 | int rsnd_gen_probe(struct platform_device *pdev, |
237 | struct rcar_snd_info *info, | 241 | struct rcar_snd_info *info, |
238 | struct rsnd_priv *priv) | 242 | struct rsnd_priv *priv) |
239 | { | 243 | { |
240 | struct device *dev = rsnd_priv_to_dev(priv); | 244 | struct device *dev = rsnd_priv_to_dev(priv); |
241 | struct rsnd_gen *gen; | 245 | struct rsnd_gen *gen; |
242 | int i; | 246 | int i; |
243 | 247 | ||
244 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); | 248 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); |
245 | if (!gen) { | 249 | if (!gen) { |
246 | dev_err(dev, "GEN allocate failed\n"); | 250 | dev_err(dev, "GEN allocate failed\n"); |
247 | return -ENOMEM; | 251 | return -ENOMEM; |
248 | } | 252 | } |
249 | 253 | ||
250 | priv->gen = gen; | 254 | priv->gen = gen; |
251 | 255 | ||
252 | /* | 256 | /* |
253 | * see | 257 | * see |
254 | * rsnd_reg_get() | 258 | * rsnd_reg_get() |
255 | * rsnd_gen_probe() | 259 | * rsnd_gen_probe() |
256 | */ | 260 | */ |
257 | for (i = 0; i < RSND_REG_MAX; i++) | 261 | for (i = 0; i < RSND_REG_MAX; i++) |
258 | gen->reg_map[i].index = -1; | 262 | gen->reg_map[i].index = -1; |
259 | 263 | ||
260 | /* | 264 | /* |
261 | * init each module | 265 | * init each module |
262 | */ | 266 | */ |
263 | if (rsnd_is_gen1(priv)) | 267 | if (rsnd_is_gen1(priv)) |
264 | return rsnd_gen1_probe(pdev, info, priv); | 268 | return rsnd_gen1_probe(pdev, info, priv); |
265 | 269 | ||
266 | dev_err(dev, "unknown generation R-Car sound device\n"); | 270 | dev_err(dev, "unknown generation R-Car sound device\n"); |
267 | 271 | ||
268 | return -ENODEV; | 272 | return -ENODEV; |
269 | } | 273 | } |
270 | 274 | ||
271 | void rsnd_gen_remove(struct platform_device *pdev, | 275 | void rsnd_gen_remove(struct platform_device *pdev, |
272 | struct rsnd_priv *priv) | 276 | struct rsnd_priv *priv) |
273 | { | 277 | { |
274 | if (rsnd_is_gen1(priv)) | 278 | if (rsnd_is_gen1(priv)) |
sound/soc/sh/rcar/rsnd.h
1 | /* | 1 | /* |
2 | * Renesas R-Car | 2 | * Renesas R-Car |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Renesas Solutions Corp. | 4 | * Copyright (C) 2013 Renesas Solutions Corp. |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #ifndef RSND_H | 11 | #ifndef RSND_H |
12 | #define RSND_H | 12 | #define RSND_H |
13 | 13 | ||
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/sh_dma.h> | 20 | #include <linux/sh_dma.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <sound/rcar_snd.h> | 22 | #include <sound/rcar_snd.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * pseudo register | 27 | * pseudo register |
28 | * | 28 | * |
29 | * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different. | 29 | * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different. |
30 | * This driver uses pseudo register in order to hide it. | 30 | * This driver uses pseudo register in order to hide it. |
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 */ |
35 | RSND_REG_SRC_ROUTE_SEL, | ||
36 | RSND_REG_SRC_TMG_SEL0, | ||
37 | RSND_REG_SRC_TMG_SEL1, | ||
38 | RSND_REG_SRC_TMG_SEL2, | ||
39 | RSND_REG_SRC_CTRL, | ||
35 | RSND_REG_SSI_MODE0, | 40 | RSND_REG_SSI_MODE0, |
36 | RSND_REG_SSI_MODE1, | 41 | RSND_REG_SSI_MODE1, |
42 | RSND_REG_BUSIF_MODE, | ||
43 | RSND_REG_BUSIF_ADINR, | ||
37 | 44 | ||
38 | /* ADG */ | 45 | /* ADG */ |
39 | RSND_REG_BRRA, | 46 | RSND_REG_BRRA, |
40 | RSND_REG_BRRB, | 47 | RSND_REG_BRRB, |
41 | RSND_REG_SSICKR, | 48 | RSND_REG_SSICKR, |
42 | RSND_REG_AUDIO_CLK_SEL0, | 49 | RSND_REG_AUDIO_CLK_SEL0, |
43 | RSND_REG_AUDIO_CLK_SEL1, | 50 | RSND_REG_AUDIO_CLK_SEL1, |
44 | RSND_REG_AUDIO_CLK_SEL2, | 51 | RSND_REG_AUDIO_CLK_SEL2, |
45 | RSND_REG_AUDIO_CLK_SEL3, | 52 | RSND_REG_AUDIO_CLK_SEL3, |
46 | RSND_REG_AUDIO_CLK_SEL4, | 53 | RSND_REG_AUDIO_CLK_SEL4, |
47 | RSND_REG_AUDIO_CLK_SEL5, | 54 | RSND_REG_AUDIO_CLK_SEL5, |
48 | 55 | ||
49 | /* SSI */ | 56 | /* SSI */ |
50 | RSND_REG_SSICR, | 57 | RSND_REG_SSICR, |
51 | RSND_REG_SSISR, | 58 | RSND_REG_SSISR, |
52 | RSND_REG_SSITDR, | 59 | RSND_REG_SSITDR, |
53 | RSND_REG_SSIRDR, | 60 | RSND_REG_SSIRDR, |
54 | RSND_REG_SSIWSR, | 61 | RSND_REG_SSIWSR, |
55 | 62 | ||
56 | RSND_REG_MAX, | 63 | RSND_REG_MAX, |
57 | }; | 64 | }; |
58 | 65 | ||
59 | struct rsnd_priv; | 66 | struct rsnd_priv; |
60 | struct rsnd_mod; | 67 | struct rsnd_mod; |
61 | struct rsnd_dai; | 68 | struct rsnd_dai; |
62 | struct rsnd_dai_stream; | 69 | struct rsnd_dai_stream; |
63 | 70 | ||
64 | /* | 71 | /* |
65 | * R-Car basic functions | 72 | * R-Car basic functions |
66 | */ | 73 | */ |
67 | #define rsnd_mod_read(m, r) \ | 74 | #define rsnd_mod_read(m, r) \ |
68 | rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) | 75 | rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) |
69 | #define rsnd_mod_write(m, r, d) \ | 76 | #define rsnd_mod_write(m, r, d) \ |
70 | rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) | 77 | rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) |
71 | #define rsnd_mod_bset(m, r, s, d) \ | 78 | #define rsnd_mod_bset(m, r, s, d) \ |
72 | rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) | 79 | rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) |
73 | 80 | ||
74 | #define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r) | 81 | #define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r) |
75 | #define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d) | 82 | #define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d) |
76 | #define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d) | 83 | #define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d) |
77 | 84 | ||
78 | u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); | 85 | u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); |
79 | void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, | 86 | void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, |
80 | enum rsnd_reg reg, u32 data); | 87 | enum rsnd_reg reg, u32 data); |
81 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | 88 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, |
82 | u32 mask, u32 data); | 89 | u32 mask, u32 data); |
83 | 90 | ||
84 | /* | 91 | /* |
85 | * R-Car DMA | 92 | * R-Car DMA |
86 | */ | 93 | */ |
87 | struct rsnd_dma { | 94 | struct rsnd_dma { |
88 | struct rsnd_priv *priv; | 95 | struct rsnd_priv *priv; |
89 | struct sh_dmae_slave slave; | 96 | struct sh_dmae_slave slave; |
90 | struct work_struct work; | 97 | struct work_struct work; |
91 | struct dma_chan *chan; | 98 | struct dma_chan *chan; |
92 | enum dma_data_direction dir; | 99 | enum dma_data_direction dir; |
93 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len); | 100 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len); |
94 | int (*complete)(struct rsnd_dma *dma); | 101 | int (*complete)(struct rsnd_dma *dma); |
95 | 102 | ||
96 | int submit_loop; | 103 | int submit_loop; |
97 | }; | 104 | }; |
98 | 105 | ||
99 | void rsnd_dma_start(struct rsnd_dma *dma); | 106 | void rsnd_dma_start(struct rsnd_dma *dma); |
100 | void rsnd_dma_stop(struct rsnd_dma *dma); | 107 | void rsnd_dma_stop(struct rsnd_dma *dma); |
101 | int rsnd_dma_available(struct rsnd_dma *dma); | 108 | int rsnd_dma_available(struct rsnd_dma *dma); |
102 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | 109 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, |
103 | int is_play, int id, | 110 | int is_play, int id, |
104 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len), | 111 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len), |
105 | int (*complete)(struct rsnd_dma *dma)); | 112 | int (*complete)(struct rsnd_dma *dma)); |
106 | void rsnd_dma_quit(struct rsnd_priv *priv, | 113 | void rsnd_dma_quit(struct rsnd_priv *priv, |
107 | struct rsnd_dma *dma); | 114 | struct rsnd_dma *dma); |
108 | 115 | ||
109 | 116 | ||
110 | /* | 117 | /* |
111 | * R-Car sound mod | 118 | * R-Car sound mod |
112 | */ | 119 | */ |
113 | 120 | ||
114 | struct rsnd_mod_ops { | 121 | struct rsnd_mod_ops { |
115 | char *name; | 122 | char *name; |
116 | int (*init)(struct rsnd_mod *mod, | 123 | int (*init)(struct rsnd_mod *mod, |
117 | struct rsnd_dai *rdai, | 124 | struct rsnd_dai *rdai, |
118 | struct rsnd_dai_stream *io); | 125 | struct rsnd_dai_stream *io); |
119 | int (*quit)(struct rsnd_mod *mod, | 126 | int (*quit)(struct rsnd_mod *mod, |
120 | struct rsnd_dai *rdai, | 127 | struct rsnd_dai *rdai, |
121 | struct rsnd_dai_stream *io); | 128 | struct rsnd_dai_stream *io); |
122 | int (*start)(struct rsnd_mod *mod, | 129 | int (*start)(struct rsnd_mod *mod, |
123 | struct rsnd_dai *rdai, | 130 | struct rsnd_dai *rdai, |
124 | struct rsnd_dai_stream *io); | 131 | struct rsnd_dai_stream *io); |
125 | int (*stop)(struct rsnd_mod *mod, | 132 | int (*stop)(struct rsnd_mod *mod, |
126 | struct rsnd_dai *rdai, | 133 | struct rsnd_dai *rdai, |
127 | struct rsnd_dai_stream *io); | 134 | struct rsnd_dai_stream *io); |
128 | }; | 135 | }; |
129 | 136 | ||
130 | struct rsnd_mod { | 137 | struct rsnd_mod { |
131 | int id; | 138 | int id; |
132 | struct rsnd_priv *priv; | 139 | struct rsnd_priv *priv; |
133 | struct rsnd_mod_ops *ops; | 140 | struct rsnd_mod_ops *ops; |
134 | struct list_head list; /* connect to rsnd_dai playback/capture */ | 141 | struct list_head list; /* connect to rsnd_dai playback/capture */ |
135 | struct rsnd_dma dma; | 142 | struct rsnd_dma dma; |
136 | }; | 143 | }; |
137 | 144 | ||
138 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 145 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
139 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 146 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
140 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) | 147 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) |
141 | #define rsnd_mod_id(mod) ((mod)->id) | 148 | #define rsnd_mod_id(mod) ((mod)->id) |
142 | #define for_each_rsnd_mod(pos, n, io) \ | 149 | #define for_each_rsnd_mod(pos, n, io) \ |
143 | list_for_each_entry_safe(pos, n, &(io)->head, list) | 150 | list_for_each_entry_safe(pos, n, &(io)->head, list) |
144 | #define rsnd_mod_call(mod, func, rdai, io) \ | 151 | #define rsnd_mod_call(mod, func, rdai, io) \ |
145 | (!(mod) ? -ENODEV : \ | 152 | (!(mod) ? -ENODEV : \ |
146 | !((mod)->ops->func) ? 0 : \ | 153 | !((mod)->ops->func) ? 0 : \ |
147 | (mod)->ops->func(mod, rdai, io)) | 154 | (mod)->ops->func(mod, rdai, io)) |
148 | 155 | ||
149 | void rsnd_mod_init(struct rsnd_priv *priv, | 156 | void rsnd_mod_init(struct rsnd_priv *priv, |
150 | struct rsnd_mod *mod, | 157 | struct rsnd_mod *mod, |
151 | struct rsnd_mod_ops *ops, | 158 | struct rsnd_mod_ops *ops, |
152 | int id); | 159 | int id); |
153 | char *rsnd_mod_name(struct rsnd_mod *mod); | 160 | char *rsnd_mod_name(struct rsnd_mod *mod); |
154 | 161 | ||
155 | /* | 162 | /* |
156 | * R-Car sound DAI | 163 | * R-Car sound DAI |
157 | */ | 164 | */ |
158 | #define RSND_DAI_NAME_SIZE 16 | 165 | #define RSND_DAI_NAME_SIZE 16 |
159 | struct rsnd_dai_stream { | 166 | struct rsnd_dai_stream { |
160 | struct list_head head; /* head of rsnd_mod list */ | 167 | struct list_head head; /* head of rsnd_mod list */ |
161 | struct snd_pcm_substream *substream; | 168 | struct snd_pcm_substream *substream; |
162 | int byte_pos; | 169 | int byte_pos; |
163 | int period_pos; | 170 | int period_pos; |
164 | int byte_per_period; | 171 | int byte_per_period; |
165 | int next_period_byte; | 172 | int next_period_byte; |
166 | }; | 173 | }; |
167 | 174 | ||
168 | struct rsnd_dai { | 175 | struct rsnd_dai { |
169 | char name[RSND_DAI_NAME_SIZE]; | 176 | char name[RSND_DAI_NAME_SIZE]; |
170 | struct rsnd_dai_platform_info *info; /* rcar_snd.h */ | 177 | struct rsnd_dai_platform_info *info; /* rcar_snd.h */ |
171 | struct rsnd_dai_stream playback; | 178 | struct rsnd_dai_stream playback; |
172 | struct rsnd_dai_stream capture; | 179 | struct rsnd_dai_stream capture; |
173 | 180 | ||
174 | int clk_master:1; | 181 | int clk_master:1; |
175 | int bit_clk_inv:1; | 182 | int bit_clk_inv:1; |
176 | int frm_clk_inv:1; | 183 | int frm_clk_inv:1; |
177 | int sys_delay:1; | 184 | int sys_delay:1; |
178 | int data_alignment:1; | 185 | int data_alignment:1; |
179 | }; | 186 | }; |
180 | 187 | ||
181 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) | 188 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) |
182 | #define for_each_rsnd_dai(rdai, priv, i) \ | 189 | #define for_each_rsnd_dai(rdai, priv, i) \ |
183 | for (i = 0, (rdai) = rsnd_dai_get(priv, i); \ | 190 | for (i = 0, (rdai) = rsnd_dai_get(priv, i); \ |
184 | i < rsnd_dai_nr(priv); \ | 191 | i < rsnd_dai_nr(priv); \ |
185 | i++, (rdai) = rsnd_dai_get(priv, i)) | 192 | i++, (rdai) = rsnd_dai_get(priv, i)) |
186 | 193 | ||
187 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); | 194 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); |
188 | int rsnd_dai_disconnect(struct rsnd_mod *mod); | 195 | int rsnd_dai_disconnect(struct rsnd_mod *mod); |
189 | int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod, | 196 | int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod, |
190 | struct rsnd_dai_stream *io); | 197 | struct rsnd_dai_stream *io); |
191 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); | 198 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); |
192 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | 199 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); |
193 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) | 200 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) |
194 | #define rsnd_io_to_runtime(io) ((io)->substream->runtime) | 201 | #define rsnd_io_to_runtime(io) ((io)->substream->runtime) |
195 | 202 | ||
196 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 203 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
197 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 204 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
198 | 205 | ||
199 | /* | 206 | /* |
200 | * R-Car Gen1/Gen2 | 207 | * R-Car Gen1/Gen2 |
201 | */ | 208 | */ |
202 | int rsnd_gen_probe(struct platform_device *pdev, | 209 | int rsnd_gen_probe(struct platform_device *pdev, |
203 | struct rcar_snd_info *info, | 210 | struct rcar_snd_info *info, |
204 | struct rsnd_priv *priv); | 211 | struct rsnd_priv *priv); |
205 | void rsnd_gen_remove(struct platform_device *pdev, | 212 | void rsnd_gen_remove(struct platform_device *pdev, |
206 | struct rsnd_priv *priv); | 213 | struct rsnd_priv *priv); |
207 | int rsnd_gen_path_init(struct rsnd_priv *priv, | 214 | int rsnd_gen_path_init(struct rsnd_priv *priv, |
208 | struct rsnd_dai *rdai, | 215 | struct rsnd_dai *rdai, |
209 | struct rsnd_dai_stream *io); | 216 | struct rsnd_dai_stream *io); |
210 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | 217 | int rsnd_gen_path_exit(struct rsnd_priv *priv, |
211 | struct rsnd_dai *rdai, | 218 | struct rsnd_dai *rdai, |
212 | struct rsnd_dai_stream *io); | 219 | struct rsnd_dai_stream *io); |
213 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | 220 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
214 | struct rsnd_mod *mod, | 221 | struct rsnd_mod *mod, |
215 | enum rsnd_reg reg); | 222 | enum rsnd_reg reg); |
223 | #define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1) | ||
224 | #define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2) | ||
216 | 225 | ||
217 | /* | 226 | /* |
218 | * R-Car ADG | 227 | * R-Car ADG |
219 | */ | 228 | */ |
220 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); | 229 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); |
221 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); | 230 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); |
222 | int rsnd_adg_probe(struct platform_device *pdev, | 231 | int rsnd_adg_probe(struct platform_device *pdev, |
223 | struct rcar_snd_info *info, | 232 | struct rcar_snd_info *info, |
224 | struct rsnd_priv *priv); | 233 | struct rsnd_priv *priv); |
225 | void rsnd_adg_remove(struct platform_device *pdev, | 234 | void rsnd_adg_remove(struct platform_device *pdev, |
226 | struct rsnd_priv *priv); | 235 | struct rsnd_priv *priv); |
227 | 236 | ||
228 | /* | 237 | /* |
229 | * R-Car sound priv | 238 | * R-Car sound priv |
230 | */ | 239 | */ |
231 | struct rsnd_priv { | 240 | struct rsnd_priv { |
232 | 241 | ||
233 | struct device *dev; | 242 | struct device *dev; |
234 | struct rcar_snd_info *info; | 243 | struct rcar_snd_info *info; |
235 | spinlock_t lock; | 244 | spinlock_t lock; |
236 | 245 | ||
237 | /* | 246 | /* |
238 | * below value will be filled on rsnd_gen_probe() | 247 | * below value will be filled on rsnd_gen_probe() |
239 | */ | 248 | */ |
240 | void *gen; | 249 | void *gen; |
241 | 250 | ||
242 | /* | 251 | /* |
243 | * below value will be filled on rsnd_scu_probe() | 252 | * below value will be filled on rsnd_scu_probe() |
244 | */ | 253 | */ |
245 | void *scu; | 254 | void *scu; |
246 | int scu_nr; | 255 | int scu_nr; |
247 | 256 | ||
248 | /* | 257 | /* |
249 | * below value will be filled on rsnd_adg_probe() | 258 | * below value will be filled on rsnd_adg_probe() |
250 | */ | 259 | */ |
251 | void *adg; | 260 | void *adg; |
252 | 261 | ||
253 | /* | 262 | /* |
254 | * below value will be filled on rsnd_ssi_probe() | 263 | * below value will be filled on rsnd_ssi_probe() |
255 | */ | 264 | */ |
256 | void *ssiu; | 265 | void *ssiu; |
257 | 266 | ||
258 | /* | 267 | /* |
259 | * below value will be filled on rsnd_dai_probe() | 268 | * below value will be filled on rsnd_dai_probe() |
260 | */ | 269 | */ |
261 | struct snd_soc_dai_driver *daidrv; | 270 | struct snd_soc_dai_driver *daidrv; |
262 | struct rsnd_dai *rdai; | 271 | struct rsnd_dai *rdai; |
263 | int dai_nr; | 272 | int dai_nr; |
264 | }; | 273 | }; |
265 | 274 | ||
266 | #define rsnd_priv_to_dev(priv) ((priv)->dev) | 275 | #define rsnd_priv_to_dev(priv) ((priv)->dev) |
267 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) | 276 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) |
268 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) | 277 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) |
269 | 278 | ||
270 | /* | 279 | /* |
271 | * R-Car SCU | 280 | * R-Car SCU |
272 | */ | 281 | */ |
273 | int rsnd_scu_probe(struct platform_device *pdev, | 282 | int rsnd_scu_probe(struct platform_device *pdev, |
274 | struct rcar_snd_info *info, | 283 | struct rcar_snd_info *info, |
275 | struct rsnd_priv *priv); | 284 | struct rsnd_priv *priv); |
276 | void rsnd_scu_remove(struct platform_device *pdev, | 285 | void rsnd_scu_remove(struct platform_device *pdev, |
277 | struct rsnd_priv *priv); | 286 | struct rsnd_priv *priv); |
278 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); | 287 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); |
279 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) | 288 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) |
280 | 289 | ||
281 | /* | 290 | /* |
282 | * R-Car SSI | 291 | * R-Car SSI |
283 | */ | 292 | */ |
284 | int rsnd_ssi_probe(struct platform_device *pdev, | 293 | int rsnd_ssi_probe(struct platform_device *pdev, |
285 | struct rcar_snd_info *info, | 294 | struct rcar_snd_info *info, |
286 | struct rsnd_priv *priv); | 295 | struct rsnd_priv *priv); |
287 | void rsnd_ssi_remove(struct platform_device *pdev, | 296 | void rsnd_ssi_remove(struct platform_device *pdev, |
288 | struct rsnd_priv *priv); | 297 | struct rsnd_priv *priv); |
289 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 298 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
290 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 299 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
291 | int dai_id, int is_play); | 300 | int dai_id, int is_play); |
292 | 301 | ||
293 | #endif | 302 | #endif |
294 | 303 |
sound/soc/sh/rcar/scu.c
1 | /* | 1 | /* |
2 | * Renesas R-Car SCU support | 2 | * Renesas R-Car SCU support |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Renesas Solutions Corp. | 4 | * Copyright (C) 2013 Renesas Solutions Corp. |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include "rsnd.h" | 11 | #include "rsnd.h" |
12 | 12 | ||
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 | }; | 16 | }; |
17 | 17 | ||
18 | #define rsnd_scu_mode_flags(p) ((p)->info->flags) | ||
19 | |||
20 | /* | ||
21 | * ADINR | ||
22 | */ | ||
23 | #define OTBL_24 (0 << 16) | ||
24 | #define OTBL_22 (2 << 16) | ||
25 | #define OTBL_20 (4 << 16) | ||
26 | #define OTBL_18 (6 << 16) | ||
27 | #define OTBL_16 (8 << 16) | ||
28 | |||
29 | |||
18 | #define rsnd_mod_to_scu(_mod) \ | 30 | #define rsnd_mod_to_scu(_mod) \ |
19 | container_of((_mod), struct rsnd_scu, mod) | 31 | container_of((_mod), struct rsnd_scu, mod) |
20 | 32 | ||
21 | #define for_each_rsnd_scu(pos, priv, i) \ | 33 | #define for_each_rsnd_scu(pos, priv, i) \ |
22 | for ((i) = 0; \ | 34 | for ((i) = 0; \ |
23 | ((i) < rsnd_scu_nr(priv)) && \ | 35 | ((i) < rsnd_scu_nr(priv)) && \ |
24 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ | 36 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ |
25 | i++) | 37 | i++) |
26 | 38 | ||
39 | static int rsnd_scu_set_route(struct rsnd_priv *priv, | ||
40 | struct rsnd_mod *mod, | ||
41 | struct rsnd_dai *rdai, | ||
42 | struct rsnd_dai_stream *io) | ||
43 | { | ||
44 | struct scu_route_config { | ||
45 | u32 mask; | ||
46 | int shift; | ||
47 | } routes[] = { | ||
48 | { 0xF, 0, }, /* 0 */ | ||
49 | { 0xF, 4, }, /* 1 */ | ||
50 | { 0xF, 8, }, /* 2 */ | ||
51 | { 0x7, 12, }, /* 3 */ | ||
52 | { 0x7, 16, }, /* 4 */ | ||
53 | { 0x7, 20, }, /* 5 */ | ||
54 | { 0x7, 24, }, /* 6 */ | ||
55 | { 0x3, 28, }, /* 7 */ | ||
56 | { 0x3, 30, }, /* 8 */ | ||
57 | }; | ||
58 | |||
59 | u32 mask; | ||
60 | u32 val; | ||
61 | int shift; | ||
62 | int id; | ||
63 | |||
64 | /* | ||
65 | * Gen1 only | ||
66 | */ | ||
67 | if (!rsnd_is_gen1(priv)) | ||
68 | return 0; | ||
69 | |||
70 | id = rsnd_mod_id(mod); | ||
71 | if (id < 0 || id > ARRAY_SIZE(routes)) | ||
72 | return -EIO; | ||
73 | |||
74 | /* | ||
75 | * SRC_ROUTE_SELECT | ||
76 | */ | ||
77 | val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | ||
78 | val = val << routes[id].shift; | ||
79 | mask = routes[id].mask << routes[id].shift; | ||
80 | |||
81 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
82 | |||
83 | /* | ||
84 | * SRC_TIMING_SELECT | ||
85 | */ | ||
86 | shift = (id % 4) * 8; | ||
87 | mask = 0x1F << shift; | ||
88 | if (8 == id) /* SRU8 is very special */ | ||
89 | val = id << shift; | ||
90 | else | ||
91 | val = (id + 1) << shift; | ||
92 | |||
93 | switch (id / 4) { | ||
94 | case 0: | ||
95 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | ||
96 | break; | ||
97 | case 1: | ||
98 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | ||
99 | break; | ||
100 | case 2: | ||
101 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int rsnd_scu_set_mode(struct rsnd_priv *priv, | ||
109 | struct rsnd_mod *mod, | ||
110 | struct rsnd_dai *rdai, | ||
111 | struct rsnd_dai_stream *io) | ||
112 | { | ||
113 | int id = rsnd_mod_id(mod); | ||
114 | u32 val; | ||
115 | |||
116 | if (rsnd_is_gen1(priv)) { | ||
117 | val = (1 << id); | ||
118 | rsnd_mod_bset(mod, SRC_CTRL, val, val); | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, | ||
125 | struct rsnd_mod *mod, | ||
126 | struct rsnd_dai *rdai, | ||
127 | struct rsnd_dai_stream *io) | ||
128 | { | ||
129 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
130 | u32 adinr = runtime->channels; | ||
131 | |||
132 | switch (runtime->sample_bits) { | ||
133 | case 16: | ||
134 | adinr |= OTBL_16; | ||
135 | break; | ||
136 | case 32: | ||
137 | adinr |= OTBL_24; | ||
138 | break; | ||
139 | default: | ||
140 | return -EIO; | ||
141 | } | ||
142 | |||
143 | rsnd_mod_write(mod, BUSIF_MODE, 1); | ||
144 | rsnd_mod_write(mod, BUSIF_ADINR, adinr); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
27 | static int rsnd_scu_init(struct rsnd_mod *mod, | 149 | static int rsnd_scu_init(struct rsnd_mod *mod, |
28 | struct rsnd_dai *rdai, | 150 | struct rsnd_dai *rdai, |
29 | struct rsnd_dai_stream *io) | 151 | struct rsnd_dai_stream *io) |
30 | { | 152 | { |
31 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 153 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
32 | struct device *dev = rsnd_priv_to_dev(priv); | 154 | struct device *dev = rsnd_priv_to_dev(priv); |
33 | 155 | ||
34 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 156 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
35 | 157 | ||
36 | return 0; | 158 | return 0; |
37 | } | 159 | } |
38 | 160 | ||
39 | static int rsnd_scu_quit(struct rsnd_mod *mod, | 161 | static int rsnd_scu_quit(struct rsnd_mod *mod, |
40 | struct rsnd_dai *rdai, | 162 | struct rsnd_dai *rdai, |
41 | struct rsnd_dai_stream *io) | 163 | struct rsnd_dai_stream *io) |
42 | { | 164 | { |
43 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 165 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
44 | struct device *dev = rsnd_priv_to_dev(priv); | 166 | struct device *dev = rsnd_priv_to_dev(priv); |
45 | 167 | ||
46 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 168 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
47 | 169 | ||
48 | return 0; | 170 | return 0; |
49 | } | 171 | } |
50 | 172 | ||
51 | static int rsnd_scu_start(struct rsnd_mod *mod, | 173 | static int rsnd_scu_start(struct rsnd_mod *mod, |
52 | struct rsnd_dai *rdai, | 174 | struct rsnd_dai *rdai, |
53 | struct rsnd_dai_stream *io) | 175 | struct rsnd_dai_stream *io) |
54 | { | 176 | { |
55 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 177 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
178 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
56 | struct device *dev = rsnd_priv_to_dev(priv); | 179 | struct device *dev = rsnd_priv_to_dev(priv); |
180 | u32 flags = rsnd_scu_mode_flags(scu); | ||
181 | int ret; | ||
57 | 182 | ||
58 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 183 | /* |
184 | * SCU will be used if it has RSND_SCU_USB_HPBIF flags | ||
185 | */ | ||
186 | if (!(flags & RSND_SCU_USB_HPBIF)) { | ||
187 | /* it use PIO transter */ | ||
188 | dev_dbg(dev, "%s%d is not used\n", | ||
189 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
59 | 190 | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | /* it use DMA transter */ | ||
195 | ret = rsnd_scu_set_route(priv, mod, rdai, io); | ||
196 | if (ret < 0) | ||
197 | return ret; | ||
198 | |||
199 | ret = rsnd_scu_set_mode(priv, mod, rdai, io); | ||
200 | if (ret < 0) | ||
201 | return ret; | ||
202 | |||
203 | ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); | ||
204 | if (ret < 0) | ||
205 | return ret; | ||
206 | |||
207 | dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
208 | |||
60 | return 0; | 209 | return 0; |
61 | } | 210 | } |
62 | 211 | ||
63 | static int rsnd_scu_stop(struct rsnd_mod *mod, | 212 | static int rsnd_scu_stop(struct rsnd_mod *mod, |
64 | struct rsnd_dai *rdai, | 213 | struct rsnd_dai *rdai, |
65 | struct rsnd_dai_stream *io) | 214 | struct rsnd_dai_stream *io) |
66 | { | 215 | { |
67 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 216 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
68 | struct device *dev = rsnd_priv_to_dev(priv); | 217 | struct device *dev = rsnd_priv_to_dev(priv); |
69 | 218 | ||
70 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 219 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
71 | 220 | ||
72 | return 0; | 221 | return 0; |
73 | } | 222 | } |
74 | 223 | ||
75 | static struct rsnd_mod_ops rsnd_scu_ops = { | 224 | static struct rsnd_mod_ops rsnd_scu_ops = { |
76 | .name = "scu", | 225 | .name = "scu", |
77 | .init = rsnd_scu_init, | 226 | .init = rsnd_scu_init, |
78 | .quit = rsnd_scu_quit, | 227 | .quit = rsnd_scu_quit, |
79 | .start = rsnd_scu_start, | 228 | .start = rsnd_scu_start, |
80 | .stop = rsnd_scu_stop, | 229 | .stop = rsnd_scu_stop, |
81 | }; | 230 | }; |
82 | 231 | ||
83 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) | 232 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) |
84 | { | 233 | { |
85 | BUG_ON(id < 0 || id >= rsnd_scu_nr(priv)); | 234 | BUG_ON(id < 0 || id >= rsnd_scu_nr(priv)); |
86 | 235 | ||
87 | return &((struct rsnd_scu *)(priv->scu) + id)->mod; | 236 | return &((struct rsnd_scu *)(priv->scu) + id)->mod; |
88 | } | 237 | } |
89 | 238 | ||
90 | int rsnd_scu_probe(struct platform_device *pdev, | 239 | int rsnd_scu_probe(struct platform_device *pdev, |
91 | struct rcar_snd_info *info, | 240 | struct rcar_snd_info *info, |
92 | struct rsnd_priv *priv) | 241 | struct rsnd_priv *priv) |
93 | { | 242 | { |
94 | struct device *dev = rsnd_priv_to_dev(priv); | 243 | struct device *dev = rsnd_priv_to_dev(priv); |
95 | struct rsnd_scu *scu; | 244 | struct rsnd_scu *scu; |
96 | int i, nr; | 245 | int i, nr; |
97 | 246 | ||
98 | /* | 247 | /* |
99 | * init SCU | 248 | * init SCU |
100 | */ | 249 | */ |
101 | nr = info->scu_info_nr; | 250 | nr = info->scu_info_nr; |
102 | scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL); | 251 | scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL); |
103 | if (!scu) { | 252 | if (!scu) { |
104 | dev_err(dev, "SCU allocate failed\n"); | 253 | dev_err(dev, "SCU allocate failed\n"); |
105 | return -ENOMEM; | 254 | return -ENOMEM; |
106 | } | 255 | } |
107 | 256 | ||
108 | priv->scu_nr = nr; | 257 | priv->scu_nr = nr; |
109 | priv->scu = scu; | 258 | priv->scu = scu; |
110 | 259 | ||
111 | for_each_rsnd_scu(scu, priv, i) { | 260 | for_each_rsnd_scu(scu, priv, i) { |
112 | rsnd_mod_init(priv, &scu->mod, | 261 | rsnd_mod_init(priv, &scu->mod, |
113 | &rsnd_scu_ops, i); | 262 | &rsnd_scu_ops, i); |
114 | scu->info = &info->scu_info[i]; | 263 | scu->info = &info->scu_info[i]; |
115 | } | ||
116 | 264 | ||
265 | dev_dbg(dev, "SCU%d probed\n", i); | ||
266 | } | ||
117 | dev_dbg(dev, "scu probed\n"); | 267 | dev_dbg(dev, "scu probed\n"); |
118 | 268 | ||
119 | return 0; | 269 | return 0; |
120 | } | 270 | } |
121 | 271 | ||
122 | void rsnd_scu_remove(struct platform_device *pdev, | 272 | void rsnd_scu_remove(struct platform_device *pdev, |
123 | struct rsnd_priv *priv) | 273 | struct rsnd_priv *priv) |
124 | { | 274 | { |
125 | } | 275 | } |
sound/soc/sh/rcar/ssi.c
1 | /* | 1 | /* |
2 | * Renesas R-Car SSIU/SSI support | 2 | * Renesas R-Car SSIU/SSI support |
3 | * | 3 | * |
4 | * Copyright (C) 2013 Renesas Solutions Corp. | 4 | * Copyright (C) 2013 Renesas Solutions Corp. |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
6 | * | 6 | * |
7 | * Based on fsi.c | 7 | * Based on fsi.c |
8 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | 8 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include "rsnd.h" | 15 | #include "rsnd.h" |
16 | #define RSND_SSI_NAME_SIZE 16 | 16 | #define RSND_SSI_NAME_SIZE 16 |
17 | 17 | ||
18 | /* | 18 | /* |
19 | * SSICR | 19 | * SSICR |
20 | */ | 20 | */ |
21 | #define FORCE (1 << 31) /* Fixed */ | 21 | #define FORCE (1 << 31) /* Fixed */ |
22 | #define DMEN (1 << 28) /* DMA Enable */ | 22 | #define DMEN (1 << 28) /* DMA Enable */ |
23 | #define UIEN (1 << 27) /* Underflow Interrupt Enable */ | 23 | #define UIEN (1 << 27) /* Underflow Interrupt Enable */ |
24 | #define OIEN (1 << 26) /* Overflow Interrupt Enable */ | 24 | #define OIEN (1 << 26) /* Overflow Interrupt Enable */ |
25 | #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ | 25 | #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ |
26 | #define DIEN (1 << 24) /* Data Interrupt Enable */ | 26 | #define DIEN (1 << 24) /* Data Interrupt Enable */ |
27 | 27 | ||
28 | #define DWL_8 (0 << 19) /* Data Word Length */ | 28 | #define DWL_8 (0 << 19) /* Data Word Length */ |
29 | #define DWL_16 (1 << 19) /* Data Word Length */ | 29 | #define DWL_16 (1 << 19) /* Data Word Length */ |
30 | #define DWL_18 (2 << 19) /* Data Word Length */ | 30 | #define DWL_18 (2 << 19) /* Data Word Length */ |
31 | #define DWL_20 (3 << 19) /* Data Word Length */ | 31 | #define DWL_20 (3 << 19) /* Data Word Length */ |
32 | #define DWL_22 (4 << 19) /* Data Word Length */ | 32 | #define DWL_22 (4 << 19) /* Data Word Length */ |
33 | #define DWL_24 (5 << 19) /* Data Word Length */ | 33 | #define DWL_24 (5 << 19) /* Data Word Length */ |
34 | #define DWL_32 (6 << 19) /* Data Word Length */ | 34 | #define DWL_32 (6 << 19) /* Data Word Length */ |
35 | 35 | ||
36 | #define SWL_32 (3 << 16) /* R/W System Word Length */ | 36 | #define SWL_32 (3 << 16) /* R/W System Word Length */ |
37 | #define SCKD (1 << 15) /* Serial Bit Clock Direction */ | 37 | #define SCKD (1 << 15) /* Serial Bit Clock Direction */ |
38 | #define SWSD (1 << 14) /* Serial WS Direction */ | 38 | #define SWSD (1 << 14) /* Serial WS Direction */ |
39 | #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ | 39 | #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ |
40 | #define SWSP (1 << 12) /* Serial WS Polarity */ | 40 | #define SWSP (1 << 12) /* Serial WS Polarity */ |
41 | #define SDTA (1 << 10) /* Serial Data Alignment */ | 41 | #define SDTA (1 << 10) /* Serial Data Alignment */ |
42 | #define DEL (1 << 8) /* Serial Data Delay */ | 42 | #define DEL (1 << 8) /* Serial Data Delay */ |
43 | #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ | 43 | #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ |
44 | #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ | 44 | #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ |
45 | #define EN (1 << 0) /* SSI Module Enable */ | 45 | #define EN (1 << 0) /* SSI Module Enable */ |
46 | 46 | ||
47 | /* | 47 | /* |
48 | * SSISR | 48 | * SSISR |
49 | */ | 49 | */ |
50 | #define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ | 50 | #define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ |
51 | #define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ | 51 | #define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ |
52 | #define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ | 52 | #define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ |
53 | #define DIRQ (1 << 24) /* Data Interrupt Status Flag */ | 53 | #define DIRQ (1 << 24) /* Data Interrupt Status Flag */ |
54 | 54 | ||
55 | /* | 55 | /* |
56 | * SSIWSR | 56 | * SSIWSR |
57 | */ | 57 | */ |
58 | #define CONT (1 << 8) /* WS Continue Function */ | 58 | #define CONT (1 << 8) /* WS Continue Function */ |
59 | 59 | ||
60 | struct rsnd_ssi { | 60 | struct rsnd_ssi { |
61 | struct clk *clk; | 61 | struct clk *clk; |
62 | struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ | 62 | struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ |
63 | struct rsnd_ssi *parent; | 63 | struct rsnd_ssi *parent; |
64 | struct rsnd_mod mod; | 64 | struct rsnd_mod mod; |
65 | 65 | ||
66 | struct rsnd_dai *rdai; | 66 | struct rsnd_dai *rdai; |
67 | struct rsnd_dai_stream *io; | 67 | struct rsnd_dai_stream *io; |
68 | u32 cr_own; | 68 | u32 cr_own; |
69 | u32 cr_clk; | 69 | u32 cr_clk; |
70 | u32 cr_etc; | 70 | u32 cr_etc; |
71 | int err; | 71 | int err; |
72 | int dma_offset; | 72 | int dma_offset; |
73 | unsigned int usrcnt; | 73 | unsigned int usrcnt; |
74 | unsigned int rate; | 74 | unsigned int rate; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct rsnd_ssiu { | 77 | struct rsnd_ssiu { |
78 | u32 ssi_mode0; | 78 | u32 ssi_mode0; |
79 | u32 ssi_mode1; | 79 | u32 ssi_mode1; |
80 | 80 | ||
81 | int ssi_nr; | 81 | int ssi_nr; |
82 | struct rsnd_ssi *ssi; | 82 | struct rsnd_ssi *ssi; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | #define for_each_rsnd_ssi(pos, priv, i) \ | 85 | #define for_each_rsnd_ssi(pos, priv, i) \ |
86 | for (i = 0; \ | 86 | for (i = 0; \ |
87 | (i < rsnd_ssi_nr(priv)) && \ | 87 | (i < rsnd_ssi_nr(priv)) && \ |
88 | ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \ | 88 | ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \ |
89 | i++) | 89 | i++) |
90 | 90 | ||
91 | #define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) | 91 | #define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) |
92 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 92 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
93 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 93 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
94 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | 94 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) |
95 | #define rsnd_ssi_dma_available(ssi) \ | 95 | #define rsnd_ssi_dma_available(ssi) \ |
96 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | 96 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) |
97 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 97 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) |
98 | #define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) | 98 | #define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) |
99 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 99 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) |
100 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | 100 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) |
101 | #define rsnd_ssi_to_ssiu(ssi)\ | 101 | #define rsnd_ssi_to_ssiu(ssi)\ |
102 | (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) | 102 | (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) |
103 | 103 | ||
104 | static void rsnd_ssi_mode_init(struct rsnd_priv *priv, | 104 | static void rsnd_ssi_mode_init(struct rsnd_priv *priv, |
105 | struct rsnd_ssiu *ssiu) | 105 | struct rsnd_ssiu *ssiu) |
106 | { | 106 | { |
107 | struct device *dev = rsnd_priv_to_dev(priv); | ||
107 | struct rsnd_ssi *ssi; | 108 | struct rsnd_ssi *ssi; |
108 | u32 flags; | 109 | u32 flags; |
109 | u32 val; | 110 | u32 val; |
110 | int i; | 111 | int i; |
111 | 112 | ||
112 | /* | 113 | /* |
113 | * SSI_MODE0 | 114 | * SSI_MODE0 |
114 | */ | 115 | */ |
115 | ssiu->ssi_mode0 = 0; | 116 | ssiu->ssi_mode0 = 0; |
116 | for_each_rsnd_ssi(ssi, priv, i) | 117 | for_each_rsnd_ssi(ssi, priv, i) { |
117 | ssiu->ssi_mode0 |= (1 << i); | 118 | flags = rsnd_ssi_mode_flags(ssi); |
118 | 119 | ||
120 | /* see also BUSIF_MODE */ | ||
121 | if (!(flags & RSND_SSI_DEPENDENT)) { | ||
122 | ssiu->ssi_mode0 |= (1 << i); | ||
123 | dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i); | ||
124 | } else { | ||
125 | dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i); | ||
126 | } | ||
127 | } | ||
128 | |||
119 | /* | 129 | /* |
120 | * SSI_MODE1 | 130 | * SSI_MODE1 |
121 | */ | 131 | */ |
122 | #define ssi_parent_set(p, sync, adg, ext) \ | 132 | #define ssi_parent_set(p, sync, adg, ext) \ |
123 | do { \ | 133 | do { \ |
124 | ssi->parent = ssiu->ssi + p; \ | 134 | ssi->parent = ssiu->ssi + p; \ |
125 | if (flags & RSND_SSI_CLK_FROM_ADG) \ | 135 | if (flags & RSND_SSI_CLK_FROM_ADG) \ |
126 | val = adg; \ | 136 | val = adg; \ |
127 | else \ | 137 | else \ |
128 | val = ext; \ | 138 | val = ext; \ |
129 | if (flags & RSND_SSI_SYNC) \ | 139 | if (flags & RSND_SSI_SYNC) \ |
130 | val |= sync; \ | 140 | val |= sync; \ |
131 | } while (0) | 141 | } while (0) |
132 | 142 | ||
133 | ssiu->ssi_mode1 = 0; | 143 | ssiu->ssi_mode1 = 0; |
134 | for_each_rsnd_ssi(ssi, priv, i) { | 144 | for_each_rsnd_ssi(ssi, priv, i) { |
135 | flags = rsnd_ssi_mode_flags(ssi); | 145 | flags = rsnd_ssi_mode_flags(ssi); |
136 | 146 | ||
137 | if (!(flags & RSND_SSI_CLK_PIN_SHARE)) | 147 | if (!(flags & RSND_SSI_CLK_PIN_SHARE)) |
138 | continue; | 148 | continue; |
139 | 149 | ||
140 | val = 0; | 150 | val = 0; |
141 | switch (i) { | 151 | switch (i) { |
142 | case 1: | 152 | case 1: |
143 | ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); | 153 | ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); |
144 | break; | 154 | break; |
145 | case 2: | 155 | case 2: |
146 | ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2)); | 156 | ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2)); |
147 | break; | 157 | break; |
148 | case 4: | 158 | case 4: |
149 | ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16)); | 159 | ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16)); |
150 | break; | 160 | break; |
151 | case 8: | 161 | case 8: |
152 | ssi_parent_set(7, 0, 0, 0); | 162 | ssi_parent_set(7, 0, 0, 0); |
153 | break; | 163 | break; |
154 | } | 164 | } |
155 | 165 | ||
156 | ssiu->ssi_mode1 |= val; | 166 | ssiu->ssi_mode1 |= val; |
157 | } | 167 | } |
158 | } | 168 | } |
159 | 169 | ||
160 | static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi) | 170 | static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi) |
161 | { | 171 | { |
162 | struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); | 172 | struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); |
163 | 173 | ||
164 | rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); | 174 | rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); |
165 | rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); | 175 | rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); |
166 | } | 176 | } |
167 | 177 | ||
168 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | 178 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, |
169 | u32 bit) | 179 | u32 bit) |
170 | { | 180 | { |
171 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 181 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
172 | struct device *dev = rsnd_priv_to_dev(priv); | 182 | struct device *dev = rsnd_priv_to_dev(priv); |
173 | u32 status; | 183 | u32 status; |
174 | int i; | 184 | int i; |
175 | 185 | ||
176 | for (i = 0; i < 1024; i++) { | 186 | for (i = 0; i < 1024; i++) { |
177 | status = rsnd_mod_read(mod, SSISR); | 187 | status = rsnd_mod_read(mod, SSISR); |
178 | if (status & bit) | 188 | if (status & bit) |
179 | return; | 189 | return; |
180 | 190 | ||
181 | udelay(50); | 191 | udelay(50); |
182 | } | 192 | } |
183 | 193 | ||
184 | dev_warn(dev, "status check failed\n"); | 194 | dev_warn(dev, "status check failed\n"); |
185 | } | 195 | } |
186 | 196 | ||
187 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | 197 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, |
188 | unsigned int rate) | 198 | unsigned int rate) |
189 | { | 199 | { |
190 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 200 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
191 | struct device *dev = rsnd_priv_to_dev(priv); | 201 | struct device *dev = rsnd_priv_to_dev(priv); |
192 | int i, j, ret; | 202 | int i, j, ret; |
193 | int adg_clk_div_table[] = { | 203 | int adg_clk_div_table[] = { |
194 | 1, 6, /* see adg.c */ | 204 | 1, 6, /* see adg.c */ |
195 | }; | 205 | }; |
196 | int ssi_clk_mul_table[] = { | 206 | int ssi_clk_mul_table[] = { |
197 | 1, 2, 4, 8, 16, 6, 12, | 207 | 1, 2, 4, 8, 16, 6, 12, |
198 | }; | 208 | }; |
199 | unsigned int main_rate; | 209 | unsigned int main_rate; |
200 | 210 | ||
201 | /* | 211 | /* |
202 | * Find best clock, and try to start ADG | 212 | * Find best clock, and try to start ADG |
203 | */ | 213 | */ |
204 | for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) { | 214 | for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) { |
205 | for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { | 215 | for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { |
206 | 216 | ||
207 | /* | 217 | /* |
208 | * this driver is assuming that | 218 | * this driver is assuming that |
209 | * system word is 64fs (= 2 x 32bit) | 219 | * system word is 64fs (= 2 x 32bit) |
210 | * see rsnd_ssi_start() | 220 | * see rsnd_ssi_start() |
211 | */ | 221 | */ |
212 | main_rate = rate / adg_clk_div_table[i] | 222 | main_rate = rate / adg_clk_div_table[i] |
213 | * 32 * 2 * ssi_clk_mul_table[j]; | 223 | * 32 * 2 * ssi_clk_mul_table[j]; |
214 | 224 | ||
215 | ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate); | 225 | ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate); |
216 | if (0 == ret) { | 226 | if (0 == ret) { |
217 | ssi->rate = rate; | 227 | ssi->rate = rate; |
218 | ssi->cr_clk = FORCE | SWL_32 | | 228 | ssi->cr_clk = FORCE | SWL_32 | |
219 | SCKD | SWSD | CKDV(j); | 229 | SCKD | SWSD | CKDV(j); |
220 | 230 | ||
221 | dev_dbg(dev, "ssi%d outputs %u Hz\n", | 231 | dev_dbg(dev, "ssi%d outputs %u Hz\n", |
222 | rsnd_mod_id(&ssi->mod), rate); | 232 | rsnd_mod_id(&ssi->mod), rate); |
223 | 233 | ||
224 | return 0; | 234 | return 0; |
225 | } | 235 | } |
226 | } | 236 | } |
227 | } | 237 | } |
228 | 238 | ||
229 | dev_err(dev, "unsupported clock rate\n"); | 239 | dev_err(dev, "unsupported clock rate\n"); |
230 | return -EIO; | 240 | return -EIO; |
231 | } | 241 | } |
232 | 242 | ||
233 | static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) | 243 | static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) |
234 | { | 244 | { |
235 | ssi->rate = 0; | 245 | ssi->rate = 0; |
236 | ssi->cr_clk = 0; | 246 | ssi->cr_clk = 0; |
237 | rsnd_adg_ssi_clk_stop(&ssi->mod); | 247 | rsnd_adg_ssi_clk_stop(&ssi->mod); |
238 | } | 248 | } |
239 | 249 | ||
240 | static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | 250 | static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, |
241 | struct rsnd_dai *rdai, | 251 | struct rsnd_dai *rdai, |
242 | struct rsnd_dai_stream *io) | 252 | struct rsnd_dai_stream *io) |
243 | { | 253 | { |
244 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 254 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
245 | struct device *dev = rsnd_priv_to_dev(priv); | 255 | struct device *dev = rsnd_priv_to_dev(priv); |
246 | u32 cr; | 256 | u32 cr; |
247 | 257 | ||
248 | if (0 == ssi->usrcnt) { | 258 | if (0 == ssi->usrcnt) { |
249 | clk_enable(ssi->clk); | 259 | clk_enable(ssi->clk); |
250 | 260 | ||
251 | if (rsnd_rdai_is_clk_master(rdai)) { | 261 | if (rsnd_rdai_is_clk_master(rdai)) { |
252 | struct snd_pcm_runtime *runtime; | 262 | struct snd_pcm_runtime *runtime; |
253 | 263 | ||
254 | runtime = rsnd_io_to_runtime(io); | 264 | runtime = rsnd_io_to_runtime(io); |
255 | 265 | ||
256 | if (rsnd_ssi_clk_from_parent(ssi)) | 266 | if (rsnd_ssi_clk_from_parent(ssi)) |
257 | rsnd_ssi_hw_start(ssi->parent, rdai, io); | 267 | rsnd_ssi_hw_start(ssi->parent, rdai, io); |
258 | else | 268 | else |
259 | rsnd_ssi_master_clk_start(ssi, runtime->rate); | 269 | rsnd_ssi_master_clk_start(ssi, runtime->rate); |
260 | } | 270 | } |
261 | } | 271 | } |
262 | 272 | ||
263 | cr = ssi->cr_own | | 273 | cr = ssi->cr_own | |
264 | ssi->cr_clk | | 274 | ssi->cr_clk | |
265 | ssi->cr_etc | | 275 | ssi->cr_etc | |
266 | EN; | 276 | EN; |
267 | 277 | ||
268 | rsnd_mod_write(&ssi->mod, SSICR, cr); | 278 | rsnd_mod_write(&ssi->mod, SSICR, cr); |
269 | 279 | ||
270 | ssi->usrcnt++; | 280 | ssi->usrcnt++; |
271 | 281 | ||
272 | dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod)); | 282 | dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod)); |
273 | } | 283 | } |
274 | 284 | ||
275 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | 285 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, |
276 | struct rsnd_dai *rdai) | 286 | struct rsnd_dai *rdai) |
277 | { | 287 | { |
278 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 288 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
279 | struct device *dev = rsnd_priv_to_dev(priv); | 289 | struct device *dev = rsnd_priv_to_dev(priv); |
280 | u32 cr; | 290 | u32 cr; |
281 | 291 | ||
282 | if (0 == ssi->usrcnt) /* stop might be called without start */ | 292 | if (0 == ssi->usrcnt) /* stop might be called without start */ |
283 | return; | 293 | return; |
284 | 294 | ||
285 | ssi->usrcnt--; | 295 | ssi->usrcnt--; |
286 | 296 | ||
287 | if (0 == ssi->usrcnt) { | 297 | if (0 == ssi->usrcnt) { |
288 | /* | 298 | /* |
289 | * disable all IRQ, | 299 | * disable all IRQ, |
290 | * and, wait all data was sent | 300 | * and, wait all data was sent |
291 | */ | 301 | */ |
292 | cr = ssi->cr_own | | 302 | cr = ssi->cr_own | |
293 | ssi->cr_clk; | 303 | ssi->cr_clk; |
294 | 304 | ||
295 | rsnd_mod_write(&ssi->mod, SSICR, cr | EN); | 305 | rsnd_mod_write(&ssi->mod, SSICR, cr | EN); |
296 | rsnd_ssi_status_check(&ssi->mod, DIRQ); | 306 | rsnd_ssi_status_check(&ssi->mod, DIRQ); |
297 | 307 | ||
298 | /* | 308 | /* |
299 | * disable SSI, | 309 | * disable SSI, |
300 | * and, wait idle state | 310 | * and, wait idle state |
301 | */ | 311 | */ |
302 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ | 312 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ |
303 | rsnd_ssi_status_check(&ssi->mod, IIRQ); | 313 | rsnd_ssi_status_check(&ssi->mod, IIRQ); |
304 | 314 | ||
305 | if (rsnd_rdai_is_clk_master(rdai)) { | 315 | if (rsnd_rdai_is_clk_master(rdai)) { |
306 | if (rsnd_ssi_clk_from_parent(ssi)) | 316 | if (rsnd_ssi_clk_from_parent(ssi)) |
307 | rsnd_ssi_hw_stop(ssi->parent, rdai); | 317 | rsnd_ssi_hw_stop(ssi->parent, rdai); |
308 | else | 318 | else |
309 | rsnd_ssi_master_clk_stop(ssi); | 319 | rsnd_ssi_master_clk_stop(ssi); |
310 | } | 320 | } |
311 | 321 | ||
312 | clk_disable(ssi->clk); | 322 | clk_disable(ssi->clk); |
313 | } | 323 | } |
314 | 324 | ||
315 | dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); | 325 | dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); |
316 | } | 326 | } |
317 | 327 | ||
318 | /* | 328 | /* |
319 | * SSI mod common functions | 329 | * SSI mod common functions |
320 | */ | 330 | */ |
321 | static int rsnd_ssi_init(struct rsnd_mod *mod, | 331 | static int rsnd_ssi_init(struct rsnd_mod *mod, |
322 | struct rsnd_dai *rdai, | 332 | struct rsnd_dai *rdai, |
323 | struct rsnd_dai_stream *io) | 333 | struct rsnd_dai_stream *io) |
324 | { | 334 | { |
325 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 335 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
326 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 336 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
327 | struct device *dev = rsnd_priv_to_dev(priv); | 337 | struct device *dev = rsnd_priv_to_dev(priv); |
328 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 338 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
329 | u32 cr; | 339 | u32 cr; |
330 | 340 | ||
331 | cr = FORCE; | 341 | cr = FORCE; |
332 | 342 | ||
333 | /* | 343 | /* |
334 | * always use 32bit system word for easy clock calculation. | 344 | * always use 32bit system word for easy clock calculation. |
335 | * see also rsnd_ssi_master_clk_enable() | 345 | * see also rsnd_ssi_master_clk_enable() |
336 | */ | 346 | */ |
337 | cr |= SWL_32; | 347 | cr |= SWL_32; |
338 | 348 | ||
339 | /* | 349 | /* |
340 | * init clock settings for SSICR | 350 | * init clock settings for SSICR |
341 | */ | 351 | */ |
342 | switch (runtime->sample_bits) { | 352 | switch (runtime->sample_bits) { |
343 | case 16: | 353 | case 16: |
344 | cr |= DWL_16; | 354 | cr |= DWL_16; |
345 | break; | 355 | break; |
346 | case 32: | 356 | case 32: |
347 | cr |= DWL_24; | 357 | cr |= DWL_24; |
348 | break; | 358 | break; |
349 | default: | 359 | default: |
350 | return -EIO; | 360 | return -EIO; |
351 | } | 361 | } |
352 | 362 | ||
353 | if (rdai->bit_clk_inv) | 363 | if (rdai->bit_clk_inv) |
354 | cr |= SCKP; | 364 | cr |= SCKP; |
355 | if (rdai->frm_clk_inv) | 365 | if (rdai->frm_clk_inv) |
356 | cr |= SWSP; | 366 | cr |= SWSP; |
357 | if (rdai->data_alignment) | 367 | if (rdai->data_alignment) |
358 | cr |= SDTA; | 368 | cr |= SDTA; |
359 | if (rdai->sys_delay) | 369 | if (rdai->sys_delay) |
360 | cr |= DEL; | 370 | cr |= DEL; |
361 | if (rsnd_dai_is_play(rdai, io)) | 371 | if (rsnd_dai_is_play(rdai, io)) |
362 | cr |= TRMD; | 372 | cr |= TRMD; |
363 | 373 | ||
364 | /* | 374 | /* |
365 | * set ssi parameter | 375 | * set ssi parameter |
366 | */ | 376 | */ |
367 | ssi->rdai = rdai; | 377 | ssi->rdai = rdai; |
368 | ssi->io = io; | 378 | ssi->io = io; |
369 | ssi->cr_own = cr; | 379 | ssi->cr_own = cr; |
370 | ssi->err = -1; /* ignore 1st error */ | 380 | ssi->err = -1; /* ignore 1st error */ |
371 | 381 | ||
372 | rsnd_ssi_mode_set(ssi); | 382 | rsnd_ssi_mode_set(ssi); |
373 | 383 | ||
374 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 384 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
375 | 385 | ||
376 | return 0; | 386 | return 0; |
377 | } | 387 | } |
378 | 388 | ||
379 | static int rsnd_ssi_quit(struct rsnd_mod *mod, | 389 | static int rsnd_ssi_quit(struct rsnd_mod *mod, |
380 | struct rsnd_dai *rdai, | 390 | struct rsnd_dai *rdai, |
381 | struct rsnd_dai_stream *io) | 391 | struct rsnd_dai_stream *io) |
382 | { | 392 | { |
383 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 393 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
384 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 394 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
385 | struct device *dev = rsnd_priv_to_dev(priv); | 395 | struct device *dev = rsnd_priv_to_dev(priv); |
386 | 396 | ||
387 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 397 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
388 | 398 | ||
389 | if (ssi->err > 0) | 399 | if (ssi->err > 0) |
390 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); | 400 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); |
391 | 401 | ||
392 | ssi->rdai = NULL; | 402 | ssi->rdai = NULL; |
393 | ssi->io = NULL; | 403 | ssi->io = NULL; |
394 | ssi->cr_own = 0; | 404 | ssi->cr_own = 0; |
395 | ssi->err = 0; | 405 | ssi->err = 0; |
396 | 406 | ||
397 | return 0; | 407 | return 0; |
398 | } | 408 | } |
399 | 409 | ||
400 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | 410 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) |
401 | { | 411 | { |
402 | /* under/over flow error */ | 412 | /* under/over flow error */ |
403 | if (status & (UIRQ | OIRQ)) { | 413 | if (status & (UIRQ | OIRQ)) { |
404 | ssi->err++; | 414 | ssi->err++; |
405 | 415 | ||
406 | /* clear error status */ | 416 | /* clear error status */ |
407 | rsnd_mod_write(&ssi->mod, SSISR, 0); | 417 | rsnd_mod_write(&ssi->mod, SSISR, 0); |
408 | } | 418 | } |
409 | } | 419 | } |
410 | 420 | ||
411 | /* | 421 | /* |
412 | * SSI PIO | 422 | * SSI PIO |
413 | */ | 423 | */ |
414 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | 424 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) |
415 | { | 425 | { |
416 | struct rsnd_ssi *ssi = data; | 426 | struct rsnd_ssi *ssi = data; |
417 | struct rsnd_dai_stream *io = ssi->io; | 427 | struct rsnd_dai_stream *io = ssi->io; |
418 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | 428 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); |
419 | irqreturn_t ret = IRQ_NONE; | 429 | irqreturn_t ret = IRQ_NONE; |
420 | 430 | ||
421 | if (io && (status & DIRQ)) { | 431 | if (io && (status & DIRQ)) { |
422 | struct rsnd_dai *rdai = ssi->rdai; | 432 | struct rsnd_dai *rdai = ssi->rdai; |
423 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 433 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
424 | u32 *buf = (u32 *)(runtime->dma_area + | 434 | u32 *buf = (u32 *)(runtime->dma_area + |
425 | rsnd_dai_pointer_offset(io, 0)); | 435 | rsnd_dai_pointer_offset(io, 0)); |
426 | 436 | ||
427 | rsnd_ssi_record_error(ssi, status); | 437 | rsnd_ssi_record_error(ssi, status); |
428 | 438 | ||
429 | /* | 439 | /* |
430 | * 8/16/32 data can be assesse to TDR/RDR register | 440 | * 8/16/32 data can be assesse to TDR/RDR register |
431 | * directly as 32bit data | 441 | * directly as 32bit data |
432 | * see rsnd_ssi_init() | 442 | * see rsnd_ssi_init() |
433 | */ | 443 | */ |
434 | if (rsnd_dai_is_play(rdai, io)) | 444 | if (rsnd_dai_is_play(rdai, io)) |
435 | rsnd_mod_write(&ssi->mod, SSITDR, *buf); | 445 | rsnd_mod_write(&ssi->mod, SSITDR, *buf); |
436 | else | 446 | else |
437 | *buf = rsnd_mod_read(&ssi->mod, SSIRDR); | 447 | *buf = rsnd_mod_read(&ssi->mod, SSIRDR); |
438 | 448 | ||
439 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 449 | rsnd_dai_pointer_update(io, sizeof(*buf)); |
440 | 450 | ||
441 | ret = IRQ_HANDLED; | 451 | ret = IRQ_HANDLED; |
442 | } | 452 | } |
443 | 453 | ||
444 | return ret; | 454 | return ret; |
445 | } | 455 | } |
446 | 456 | ||
447 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | 457 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, |
448 | struct rsnd_dai *rdai, | 458 | struct rsnd_dai *rdai, |
449 | struct rsnd_dai_stream *io) | 459 | struct rsnd_dai_stream *io) |
450 | { | 460 | { |
451 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 461 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
452 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 462 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
453 | struct device *dev = rsnd_priv_to_dev(priv); | 463 | struct device *dev = rsnd_priv_to_dev(priv); |
454 | 464 | ||
455 | /* enable PIO IRQ */ | 465 | /* enable PIO IRQ */ |
456 | ssi->cr_etc = UIEN | OIEN | DIEN; | 466 | ssi->cr_etc = UIEN | OIEN | DIEN; |
457 | 467 | ||
458 | rsnd_ssi_hw_start(ssi, rdai, io); | 468 | rsnd_ssi_hw_start(ssi, rdai, io); |
459 | 469 | ||
460 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 470 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
461 | 471 | ||
462 | return 0; | 472 | return 0; |
463 | } | 473 | } |
464 | 474 | ||
465 | static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | 475 | static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, |
466 | struct rsnd_dai *rdai, | 476 | struct rsnd_dai *rdai, |
467 | struct rsnd_dai_stream *io) | 477 | struct rsnd_dai_stream *io) |
468 | { | 478 | { |
469 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 479 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
470 | struct device *dev = rsnd_priv_to_dev(priv); | 480 | struct device *dev = rsnd_priv_to_dev(priv); |
471 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 481 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
472 | 482 | ||
473 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | 483 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); |
474 | 484 | ||
475 | ssi->cr_etc = 0; | 485 | ssi->cr_etc = 0; |
476 | 486 | ||
477 | rsnd_ssi_hw_stop(ssi, rdai); | 487 | rsnd_ssi_hw_stop(ssi, rdai); |
478 | 488 | ||
479 | return 0; | 489 | return 0; |
480 | } | 490 | } |
481 | 491 | ||
482 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 492 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
483 | .name = "ssi (pio)", | 493 | .name = "ssi (pio)", |
484 | .init = rsnd_ssi_init, | 494 | .init = rsnd_ssi_init, |
485 | .quit = rsnd_ssi_quit, | 495 | .quit = rsnd_ssi_quit, |
486 | .start = rsnd_ssi_pio_start, | 496 | .start = rsnd_ssi_pio_start, |
487 | .stop = rsnd_ssi_pio_stop, | 497 | .stop = rsnd_ssi_pio_stop, |
488 | }; | 498 | }; |
489 | 499 | ||
490 | static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len) | 500 | static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len) |
491 | { | 501 | { |
492 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | 502 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); |
493 | struct rsnd_dai_stream *io = ssi->io; | 503 | struct rsnd_dai_stream *io = ssi->io; |
494 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 504 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
495 | 505 | ||
496 | *len = io->byte_per_period; | 506 | *len = io->byte_per_period; |
497 | *buf = runtime->dma_addr + | 507 | *buf = runtime->dma_addr + |
498 | rsnd_dai_pointer_offset(io, ssi->dma_offset + *len); | 508 | rsnd_dai_pointer_offset(io, ssi->dma_offset + *len); |
499 | ssi->dma_offset = *len; /* it cares A/B plane */ | 509 | ssi->dma_offset = *len; /* it cares A/B plane */ |
500 | 510 | ||
501 | return 0; | 511 | return 0; |
502 | } | 512 | } |
503 | 513 | ||
504 | static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) | 514 | static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) |
505 | { | 515 | { |
506 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | 516 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); |
507 | struct rsnd_dai_stream *io = ssi->io; | 517 | struct rsnd_dai_stream *io = ssi->io; |
508 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | 518 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); |
509 | 519 | ||
510 | rsnd_ssi_record_error(ssi, status); | 520 | rsnd_ssi_record_error(ssi, status); |
511 | 521 | ||
512 | rsnd_dai_pointer_update(ssi->io, io->byte_per_period); | 522 | rsnd_dai_pointer_update(ssi->io, io->byte_per_period); |
513 | 523 | ||
514 | return 0; | 524 | return 0; |
515 | } | 525 | } |
516 | 526 | ||
517 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | 527 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, |
518 | struct rsnd_dai *rdai, | 528 | struct rsnd_dai *rdai, |
519 | struct rsnd_dai_stream *io) | 529 | struct rsnd_dai_stream *io) |
520 | { | 530 | { |
521 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 531 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
522 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | 532 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); |
523 | 533 | ||
524 | /* enable DMA transfer */ | 534 | /* enable DMA transfer */ |
525 | ssi->cr_etc = DMEN; | 535 | ssi->cr_etc = DMEN; |
526 | ssi->dma_offset = 0; | 536 | ssi->dma_offset = 0; |
527 | 537 | ||
528 | rsnd_dma_start(dma); | 538 | rsnd_dma_start(dma); |
529 | 539 | ||
530 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 540 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); |
531 | 541 | ||
532 | /* enable WS continue */ | 542 | /* enable WS continue */ |
533 | if (rsnd_rdai_is_clk_master(rdai)) | 543 | if (rsnd_rdai_is_clk_master(rdai)) |
534 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | 544 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); |
535 | 545 | ||
536 | return 0; | 546 | return 0; |
537 | } | 547 | } |
538 | 548 | ||
539 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | 549 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, |
540 | struct rsnd_dai *rdai, | 550 | struct rsnd_dai *rdai, |
541 | struct rsnd_dai_stream *io) | 551 | struct rsnd_dai_stream *io) |
542 | { | 552 | { |
543 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 553 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
544 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | 554 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); |
545 | 555 | ||
546 | ssi->cr_etc = 0; | 556 | ssi->cr_etc = 0; |
547 | 557 | ||
548 | rsnd_ssi_hw_stop(ssi, rdai); | 558 | rsnd_ssi_hw_stop(ssi, rdai); |
549 | 559 | ||
550 | rsnd_dma_stop(dma); | 560 | rsnd_dma_stop(dma); |
551 | 561 | ||
552 | return 0; | 562 | return 0; |
553 | } | 563 | } |
554 | 564 | ||
555 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | 565 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { |
556 | .name = "ssi (dma)", | 566 | .name = "ssi (dma)", |
557 | .init = rsnd_ssi_init, | 567 | .init = rsnd_ssi_init, |
558 | .quit = rsnd_ssi_quit, | 568 | .quit = rsnd_ssi_quit, |
559 | .start = rsnd_ssi_dma_start, | 569 | .start = rsnd_ssi_dma_start, |
560 | .stop = rsnd_ssi_dma_stop, | 570 | .stop = rsnd_ssi_dma_stop, |
561 | }; | 571 | }; |
562 | 572 | ||
563 | /* | 573 | /* |
564 | * Non SSI | 574 | * Non SSI |
565 | */ | 575 | */ |
566 | static int rsnd_ssi_non(struct rsnd_mod *mod, | 576 | static int rsnd_ssi_non(struct rsnd_mod *mod, |
567 | struct rsnd_dai *rdai, | 577 | struct rsnd_dai *rdai, |
568 | struct rsnd_dai_stream *io) | 578 | struct rsnd_dai_stream *io) |
569 | { | 579 | { |
570 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 580 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
571 | struct device *dev = rsnd_priv_to_dev(priv); | 581 | struct device *dev = rsnd_priv_to_dev(priv); |
572 | 582 | ||
573 | dev_dbg(dev, "%s\n", __func__); | 583 | dev_dbg(dev, "%s\n", __func__); |
574 | 584 | ||
575 | return 0; | 585 | return 0; |
576 | } | 586 | } |
577 | 587 | ||
578 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { | 588 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { |
579 | .name = "ssi (non)", | 589 | .name = "ssi (non)", |
580 | .init = rsnd_ssi_non, | 590 | .init = rsnd_ssi_non, |
581 | .quit = rsnd_ssi_non, | 591 | .quit = rsnd_ssi_non, |
582 | .start = rsnd_ssi_non, | 592 | .start = rsnd_ssi_non, |
583 | .stop = rsnd_ssi_non, | 593 | .stop = rsnd_ssi_non, |
584 | }; | 594 | }; |
585 | 595 | ||
586 | /* | 596 | /* |
587 | * ssi mod function | 597 | * ssi mod function |
588 | */ | 598 | */ |
589 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 599 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
590 | int dai_id, int is_play) | 600 | int dai_id, int is_play) |
591 | { | 601 | { |
592 | struct rsnd_ssi *ssi; | 602 | struct rsnd_ssi *ssi; |
593 | int i, has_play; | 603 | int i, has_play; |
594 | 604 | ||
595 | is_play = !!is_play; | 605 | is_play = !!is_play; |
596 | 606 | ||
597 | for_each_rsnd_ssi(ssi, priv, i) { | 607 | for_each_rsnd_ssi(ssi, priv, i) { |
598 | if (rsnd_ssi_dai_id(ssi) != dai_id) | 608 | if (rsnd_ssi_dai_id(ssi) != dai_id) |
599 | continue; | 609 | continue; |
600 | 610 | ||
601 | has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | 611 | has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); |
602 | 612 | ||
603 | if (is_play == has_play) | 613 | if (is_play == has_play) |
604 | return &ssi->mod; | 614 | return &ssi->mod; |
605 | } | 615 | } |
606 | 616 | ||
607 | return NULL; | 617 | return NULL; |
608 | } | 618 | } |
609 | 619 | ||
610 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | 620 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) |
611 | { | 621 | { |
612 | BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv)); | 622 | BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv)); |
613 | 623 | ||
614 | return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod; | 624 | return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod; |
615 | } | 625 | } |
616 | 626 | ||
617 | int rsnd_ssi_probe(struct platform_device *pdev, | 627 | int rsnd_ssi_probe(struct platform_device *pdev, |
618 | struct rcar_snd_info *info, | 628 | struct rcar_snd_info *info, |
619 | struct rsnd_priv *priv) | 629 | struct rsnd_priv *priv) |
620 | { | 630 | { |
621 | struct rsnd_ssi_platform_info *pinfo; | 631 | struct rsnd_ssi_platform_info *pinfo; |
622 | struct device *dev = rsnd_priv_to_dev(priv); | 632 | struct device *dev = rsnd_priv_to_dev(priv); |
623 | struct rsnd_mod_ops *ops; | 633 | struct rsnd_mod_ops *ops; |
624 | struct clk *clk; | 634 | struct clk *clk; |
625 | struct rsnd_ssiu *ssiu; | 635 | struct rsnd_ssiu *ssiu; |
626 | struct rsnd_ssi *ssi; | 636 | struct rsnd_ssi *ssi; |
627 | char name[RSND_SSI_NAME_SIZE]; | 637 | char name[RSND_SSI_NAME_SIZE]; |
628 | int i, nr, ret; | 638 | int i, nr, ret; |
629 | 639 | ||
630 | /* | 640 | /* |
631 | * init SSI | 641 | * init SSI |
632 | */ | 642 | */ |
633 | nr = info->ssi_info_nr; | 643 | nr = info->ssi_info_nr; |
634 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr), | 644 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr), |
635 | GFP_KERNEL); | 645 | GFP_KERNEL); |
636 | if (!ssiu) { | 646 | if (!ssiu) { |
637 | dev_err(dev, "SSI allocate failed\n"); | 647 | dev_err(dev, "SSI allocate failed\n"); |
638 | return -ENOMEM; | 648 | return -ENOMEM; |
639 | } | 649 | } |
640 | 650 | ||
641 | priv->ssiu = ssiu; | 651 | priv->ssiu = ssiu; |
642 | ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1); | 652 | ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1); |
643 | ssiu->ssi_nr = nr; | 653 | ssiu->ssi_nr = nr; |
644 | 654 | ||
645 | for_each_rsnd_ssi(ssi, priv, i) { | 655 | for_each_rsnd_ssi(ssi, priv, i) { |
646 | pinfo = &info->ssi_info[i]; | 656 | pinfo = &info->ssi_info[i]; |
647 | 657 | ||
648 | snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); | 658 | snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i); |
649 | 659 | ||
650 | clk = clk_get(dev, name); | 660 | clk = clk_get(dev, name); |
651 | if (IS_ERR(clk)) | 661 | if (IS_ERR(clk)) |
652 | return PTR_ERR(clk); | 662 | return PTR_ERR(clk); |
653 | 663 | ||
654 | ssi->info = pinfo; | 664 | ssi->info = pinfo; |
655 | ssi->clk = clk; | 665 | ssi->clk = clk; |
656 | 666 | ||
657 | ops = &rsnd_ssi_non_ops; | 667 | ops = &rsnd_ssi_non_ops; |
658 | 668 | ||
659 | /* | 669 | /* |
660 | * SSI DMA case | 670 | * SSI DMA case |
661 | */ | 671 | */ |
662 | if (pinfo->dma_id > 0) { | 672 | if (pinfo->dma_id > 0) { |
663 | ret = rsnd_dma_init( | 673 | ret = rsnd_dma_init( |
664 | priv, rsnd_mod_to_dma(&ssi->mod), | 674 | priv, rsnd_mod_to_dma(&ssi->mod), |
665 | (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY), | 675 | (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY), |
666 | pinfo->dma_id, | 676 | pinfo->dma_id, |
667 | rsnd_ssi_dma_inquiry, | 677 | rsnd_ssi_dma_inquiry, |
668 | rsnd_ssi_dma_complete); | 678 | rsnd_ssi_dma_complete); |
669 | if (ret < 0) | 679 | if (ret < 0) |
670 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); | 680 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); |
671 | else | 681 | else |
672 | ops = &rsnd_ssi_dma_ops; | 682 | ops = &rsnd_ssi_dma_ops; |
683 | |||
684 | dev_dbg(dev, "SSI%d use DMA transfer\n", i); | ||
673 | } | 685 | } |
674 | 686 | ||
675 | /* | 687 | /* |
676 | * SSI PIO case | 688 | * SSI PIO case |
677 | */ | 689 | */ |
678 | if (!rsnd_ssi_dma_available(ssi) && | 690 | if (!rsnd_ssi_dma_available(ssi) && |
679 | rsnd_ssi_pio_available(ssi)) { | 691 | rsnd_ssi_pio_available(ssi)) { |
680 | ret = devm_request_irq(dev, pinfo->pio_irq, | 692 | ret = devm_request_irq(dev, pinfo->pio_irq, |
681 | &rsnd_ssi_pio_interrupt, | 693 | &rsnd_ssi_pio_interrupt, |
682 | IRQF_SHARED, | 694 | IRQF_SHARED, |
683 | dev_name(dev), ssi); | 695 | dev_name(dev), ssi); |
684 | if (ret) { | 696 | if (ret) { |
685 | dev_err(dev, "SSI request interrupt failed\n"); | 697 | dev_err(dev, "SSI request interrupt failed\n"); |
686 | return ret; | 698 | return ret; |
687 | } | 699 | } |
688 | 700 | ||
689 | ops = &rsnd_ssi_pio_ops; | 701 | ops = &rsnd_ssi_pio_ops; |
702 | |||
703 | dev_dbg(dev, "SSI%d use PIO transfer\n", i); | ||
690 | } | 704 | } |
691 | 705 | ||
692 | rsnd_mod_init(priv, &ssi->mod, ops, i); | 706 | rsnd_mod_init(priv, &ssi->mod, ops, i); |
693 | } | 707 | } |
694 | 708 | ||
695 | rsnd_ssi_mode_init(priv, ssiu); | 709 | rsnd_ssi_mode_init(priv, ssiu); |
696 | 710 | ||
697 | dev_dbg(dev, "ssi probed\n"); | 711 | dev_dbg(dev, "ssi probed\n"); |
698 | 712 | ||
699 | return 0; | 713 | return 0; |
700 | } | 714 | } |
701 | 715 | ||
702 | void rsnd_ssi_remove(struct platform_device *pdev, | 716 | void rsnd_ssi_remove(struct platform_device *pdev, |
703 | struct rsnd_priv *priv) | 717 | struct rsnd_priv *priv) |
704 | { | 718 | { |
705 | struct rsnd_ssi *ssi; | 719 | struct rsnd_ssi *ssi; |
706 | int i; | 720 | int i; |
707 | 721 | ||
708 | for_each_rsnd_ssi(ssi, priv, i) { | 722 | for_each_rsnd_ssi(ssi, priv, i) { |
709 | clk_put(ssi->clk); | 723 | clk_put(ssi->clk); |
710 | if (rsnd_ssi_dma_available(ssi)) | 724 | if (rsnd_ssi_dma_available(ssi)) |
711 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); | 725 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); |
712 | } | 726 | } |
713 | 727 | ||
714 | } | 728 | } |
715 | 729 |