blob: b04a53f2b4f63e56b72ed395faf89cc823f832a2 [file] [log] [blame]
Rongjun Yinga731e212014-03-05 16:34:35 +08001/*
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
16struct 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
22static 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
34static 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
41static 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
58static 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
64static 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
72static 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
103static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = {
104 .trigger = sirf_audio_port_trigger,
105};
106
107static 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
126static const struct snd_soc_component_driver sirf_audio_port_component = {
127 .name = "sirf-audio-port",
128};
129
130static 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
138static 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
175static const struct of_device_id sirf_audio_port_of_match[] = {
176 { .compatible = "sirf,audio-port", },
177 {}
178};
179MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match);
180
181static 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
190module_platform_driver(sirf_audio_port_driver);
191
192MODULE_DESCRIPTION("SiRF Audio Port driver");
193MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
194MODULE_LICENSE("GPL v2");