ASoC: sirf: Add SiRF audio port driver is used by SiRF internal audio codec
[deliverable/linux.git] / sound / soc / sirf / sirf-audio-port.c
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");
This page took 0.050844 seconds and 5 git commands to generate.