diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/sirf-audio-port.txt | 20 | ||||
-rw-r--r-- | sound/soc/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/Makefile | 1 | ||||
-rw-r--r-- | sound/soc/sirf/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/sirf/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/sirf/sirf-audio-port.c | 194 | ||||
-rw-r--r-- | sound/soc/sirf/sirf-audio-port.h | 62 |
7 files changed, 289 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-port.txt b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt new file mode 100644 index 000000000000..1f66de3c8f00 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt | |||
@@ -0,0 +1,20 @@ | |||
1 | * SiRF SoC audio port | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: "sirf,audio-port" | ||
5 | - reg: Base address and size entries: | ||
6 | - dmas: List of DMA controller phandle and DMA request line ordered pairs. | ||
7 | - dma-names: Identifier string for each DMA request line in the dmas property. | ||
8 | These strings correspond 1:1 with the ordered pairs in dmas. | ||
9 | |||
10 | One of the DMA channels will be responsible for transmission (should be | ||
11 | named "tx") and one for reception (should be named "rx"). | ||
12 | |||
13 | Example: | ||
14 | |||
15 | audioport: audioport@b0040000 { | ||
16 | compatible = "sirf,audio-port"; | ||
17 | reg = <0xb0040000 0x10000>; | ||
18 | dmas = <&dmac1 3>, <&dmac1 8>; | ||
19 | dma-names = "rx", "tx"; | ||
20 | }; | ||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index d62ce483a443..0060b31cc3f3 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -50,6 +50,7 @@ source "sound/soc/pxa/Kconfig" | |||
50 | source "sound/soc/samsung/Kconfig" | 50 | source "sound/soc/samsung/Kconfig" |
51 | source "sound/soc/s6000/Kconfig" | 51 | source "sound/soc/s6000/Kconfig" |
52 | source "sound/soc/sh/Kconfig" | 52 | source "sound/soc/sh/Kconfig" |
53 | source "sound/soc/sirf/Kconfig" | ||
53 | source "sound/soc/spear/Kconfig" | 54 | source "sound/soc/spear/Kconfig" |
54 | source "sound/soc/tegra/Kconfig" | 55 | source "sound/soc/tegra/Kconfig" |
55 | source "sound/soc/txx9/Kconfig" | 56 | source "sound/soc/txx9/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 62a1822e77bf..5f1df02984f8 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC) += pxa/ | |||
27 | obj-$(CONFIG_SND_SOC) += samsung/ | 27 | obj-$(CONFIG_SND_SOC) += samsung/ |
28 | obj-$(CONFIG_SND_SOC) += s6000/ | 28 | obj-$(CONFIG_SND_SOC) += s6000/ |
29 | obj-$(CONFIG_SND_SOC) += sh/ | 29 | obj-$(CONFIG_SND_SOC) += sh/ |
30 | obj-$(CONFIG_SND_SOC) += sirf/ | ||
30 | obj-$(CONFIG_SND_SOC) += spear/ | 31 | obj-$(CONFIG_SND_SOC) += spear/ |
31 | obj-$(CONFIG_SND_SOC) += tegra/ | 32 | obj-$(CONFIG_SND_SOC) += tegra/ |
32 | obj-$(CONFIG_SND_SOC) += txx9/ | 33 | obj-$(CONFIG_SND_SOC) += txx9/ |
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig new file mode 100644 index 000000000000..75b0344d2151 --- /dev/null +++ b/sound/soc/sirf/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | config SND_SOC_SIRF | ||
2 | tristate "SoC Audio for the SiRF SoC chips" | ||
3 | depends on ARCH_SIRF || COMPILE_TEST | ||
4 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
5 | |||
6 | config SND_SOC_SIRF_AUDIO_PORT | ||
7 | select REGMAP_MMIO | ||
8 | tristate | ||
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile new file mode 100644 index 000000000000..fb012c852b28 --- /dev/null +++ b/sound/soc/sirf/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | snd-soc-sirf-audio-port-objs := sirf-audio-port.o | ||
2 | |||
3 | obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o | ||
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c new file mode 100644 index 000000000000..b04a53f2b4f6 --- /dev/null +++ b/sound/soc/sirf/sirf-audio-port.c | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * SiRF Audio port driver | ||
3 | * | ||
4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/io.h> | ||
10 | #include <linux/regmap.h> | ||
11 | #include <sound/soc.h> | ||
12 | #include <sound/dmaengine_pcm.h> | ||
13 | |||
14 | #include "sirf-audio-port.h" | ||
15 | |||
16 | struct sirf_audio_port { | ||
17 | struct regmap *regmap; | ||
18 | struct snd_dmaengine_dai_dma_data playback_dma_data; | ||
19 | struct snd_dmaengine_dai_dma_data capture_dma_data; | ||
20 | }; | ||
21 | |||
22 | static void sirf_audio_port_tx_enable(struct sirf_audio_port *port) | ||
23 | { | ||
24 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, | ||
25 | AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); | ||
26 | regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0); | ||
27 | regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); | ||
28 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, | ||
29 | AUDIO_FIFO_START, AUDIO_FIFO_START); | ||
30 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL, | ||
31 | IC_TX_ENABLE, IC_TX_ENABLE); | ||
32 | } | ||
33 | |||
34 | static void sirf_audio_port_tx_disable(struct sirf_audio_port *port) | ||
35 | { | ||
36 | regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); | ||
37 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL, | ||
38 | IC_TX_ENABLE, ~IC_TX_ENABLE); | ||
39 | } | ||
40 | |||
41 | static void sirf_audio_port_rx_enable(struct sirf_audio_port *port, | ||
42 | int channels) | ||
43 | { | ||
44 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, | ||
45 | AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); | ||
46 | regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_INT_MSK, 0); | ||
47 | regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0); | ||
48 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, | ||
49 | AUDIO_FIFO_START, AUDIO_FIFO_START); | ||
50 | if (channels == 1) | ||
51 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL, | ||
52 | IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO); | ||
53 | else | ||
54 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL, | ||
55 | IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO); | ||
56 | } | ||
57 | |||
58 | static void sirf_audio_port_rx_disable(struct sirf_audio_port *port) | ||
59 | { | ||
60 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL, | ||
61 | IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO); | ||
62 | } | ||
63 | |||
64 | static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai) | ||
65 | { | ||
66 | struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai); | ||
67 | snd_soc_dai_init_dma_data(dai, &port->playback_dma_data, | ||
68 | &port->capture_dma_data); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int sirf_audio_port_trigger(struct snd_pcm_substream *substream, int cmd, | ||
73 | struct snd_soc_dai *dai) | ||
74 | { | ||
75 | struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai); | ||
76 | int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
77 | |||
78 | switch (cmd) { | ||
79 | case SNDRV_PCM_TRIGGER_STOP: | ||
80 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
81 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
82 | if (playback) | ||
83 | sirf_audio_port_tx_disable(port); | ||
84 | else | ||
85 | sirf_audio_port_rx_disable(port); | ||
86 | break; | ||
87 | case SNDRV_PCM_TRIGGER_START: | ||
88 | case SNDRV_PCM_TRIGGER_RESUME: | ||
89 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
90 | if (playback) | ||
91 | sirf_audio_port_tx_enable(port); | ||
92 | else | ||
93 | sirf_audio_port_rx_enable(port, | ||
94 | substream->runtime->channels); | ||
95 | break; | ||
96 | default: | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = { | ||
104 | .trigger = sirf_audio_port_trigger, | ||
105 | }; | ||
106 | |||
107 | static struct snd_soc_dai_driver sirf_audio_port_dai = { | ||
108 | .probe = sirf_audio_port_dai_probe, | ||
109 | .name = "sirf-audio-port", | ||
110 | .id = 0, | ||
111 | .playback = { | ||
112 | .channels_min = 2, | ||
113 | .channels_max = 2, | ||
114 | .rates = SNDRV_PCM_RATE_48000, | ||
115 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
116 | }, | ||
117 | .capture = { | ||
118 | .channels_min = 1, | ||
119 | .channels_max = 2, | ||
120 | .rates = SNDRV_PCM_RATE_48000, | ||
121 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
122 | }, | ||
123 | .ops = &sirf_audio_port_dai_ops, | ||
124 | }; | ||
125 | |||
126 | static const struct snd_soc_component_driver sirf_audio_port_component = { | ||
127 | .name = "sirf-audio-port", | ||
128 | }; | ||
129 | |||
130 | static const struct regmap_config sirf_audio_port_regmap_config = { | ||
131 | .reg_bits = 32, | ||
132 | .reg_stride = 4, | ||
133 | .val_bits = 32, | ||
134 | .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK, | ||
135 | .cache_type = REGCACHE_NONE, | ||
136 | }; | ||
137 | |||
138 | static int sirf_audio_port_probe(struct platform_device *pdev) | ||
139 | { | ||
140 | int ret; | ||
141 | struct sirf_audio_port *port; | ||
142 | void __iomem *base; | ||
143 | struct resource *mem_res; | ||
144 | |||
145 | port = devm_kzalloc(&pdev->dev, | ||
146 | sizeof(struct sirf_audio_port), GFP_KERNEL); | ||
147 | if (!port) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
151 | if (!mem_res) { | ||
152 | dev_err(&pdev->dev, "no mem resource?\n"); | ||
153 | return -ENODEV; | ||
154 | } | ||
155 | |||
156 | base = devm_ioremap(&pdev->dev, mem_res->start, | ||
157 | resource_size(mem_res)); | ||
158 | if (base == NULL) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | port->regmap = devm_regmap_init_mmio(&pdev->dev, base, | ||
162 | &sirf_audio_port_regmap_config); | ||
163 | if (IS_ERR(port->regmap)) | ||
164 | return PTR_ERR(port->regmap); | ||
165 | |||
166 | ret = devm_snd_soc_register_component(&pdev->dev, | ||
167 | &sirf_audio_port_component, &sirf_audio_port_dai, 1); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | |||
171 | platform_set_drvdata(pdev, port); | ||
172 | return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | ||
173 | } | ||
174 | |||
175 | static const struct of_device_id sirf_audio_port_of_match[] = { | ||
176 | { .compatible = "sirf,audio-port", }, | ||
177 | {} | ||
178 | }; | ||
179 | MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match); | ||
180 | |||
181 | static struct platform_driver sirf_audio_port_driver = { | ||
182 | .driver = { | ||
183 | .name = "sirf-audio-port", | ||
184 | .owner = THIS_MODULE, | ||
185 | .of_match_table = sirf_audio_port_of_match, | ||
186 | }, | ||
187 | .probe = sirf_audio_port_probe, | ||
188 | }; | ||
189 | |||
190 | module_platform_driver(sirf_audio_port_driver); | ||
191 | |||
192 | MODULE_DESCRIPTION("SiRF Audio Port driver"); | ||
193 | MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>"); | ||
194 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/sirf/sirf-audio-port.h b/sound/soc/sirf/sirf-audio-port.h new file mode 100644 index 000000000000..f32dc54f4499 --- /dev/null +++ b/sound/soc/sirf/sirf-audio-port.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * SiRF Audio port controllers define | ||
3 | * | ||
4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #ifndef _SIRF_AUDIO_PORT_H | ||
10 | #define _SIRF_AUDIO_PORT_H | ||
11 | |||
12 | #define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F | ||
13 | #define AUDIO_PORT_TX_FIFO_SC_OFFSET 0 | ||
14 | #define AUDIO_PORT_TX_FIFO_LC_OFFSET 10 | ||
15 | #define AUDIO_PORT_TX_FIFO_HC_OFFSET 20 | ||
16 | |||
17 | #define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ | ||
18 | << AUDIO_PORT_TX_FIFO_SC_OFFSET) | ||
19 | #define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ | ||
20 | << AUDIO_PORT_TX_FIFO_LC_OFFSET) | ||
21 | #define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ | ||
22 | << AUDIO_PORT_TX_FIFO_HC_OFFSET) | ||
23 | |||
24 | #define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F | ||
25 | #define AUDIO_PORT_RX_FIFO_SC_OFFSET 0 | ||
26 | #define AUDIO_PORT_RX_FIFO_LC_OFFSET 10 | ||
27 | #define AUDIO_PORT_RX_FIFO_HC_OFFSET 20 | ||
28 | |||
29 | #define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ | ||
30 | << AUDIO_PORT_RX_FIFO_SC_OFFSET) | ||
31 | #define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ | ||
32 | << AUDIO_PORT_RX_FIFO_LC_OFFSET) | ||
33 | #define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ | ||
34 | << AUDIO_PORT_RX_FIFO_HC_OFFSET) | ||
35 | #define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4) | ||
36 | #define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8) | ||
37 | |||
38 | #define AUDIO_PORT_IC_TXFIFO_OP (0x00FC) | ||
39 | #define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100) | ||
40 | #define AUDIO_PORT_IC_TXFIFO_STS (0x0104) | ||
41 | #define AUDIO_PORT_IC_TXFIFO_INT (0x0108) | ||
42 | #define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C) | ||
43 | |||
44 | #define AUDIO_PORT_IC_RXFIFO_OP (0x0110) | ||
45 | #define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114) | ||
46 | #define AUDIO_PORT_IC_RXFIFO_STS (0x0118) | ||
47 | #define AUDIO_PORT_IC_RXFIFO_INT (0x011C) | ||
48 | #define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120) | ||
49 | |||
50 | #define AUDIO_FIFO_START (1 << 0) | ||
51 | #define AUDIO_FIFO_RESET (1 << 1) | ||
52 | |||
53 | #define AUDIO_FIFO_FULL (1 << 0) | ||
54 | #define AUDIO_FIFO_EMPTY (1 << 1) | ||
55 | #define AUDIO_FIFO_OFLOW (1 << 2) | ||
56 | #define AUDIO_FIFO_UFLOW (1 << 3) | ||
57 | |||
58 | #define IC_TX_ENABLE (0x03) | ||
59 | #define IC_RX_ENABLE_MONO (0x01) | ||
60 | #define IC_RX_ENABLE_STEREO (0x03) | ||
61 | |||
62 | #endif /*__SIRF_AUDIO_PORT_H*/ | ||