aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/cx20442.c116
-rw-r--r--sound/soc/codecs/cx20442.h1
2 files changed, 111 insertions, 6 deletions
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 7bbb77baa231..f33245510c3b 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -13,6 +13,8 @@
13 * option) any later version. 13 * option) any later version.
14 */ 14 */
15 15
16#include <linux/tty.h>
17
16#include <sound/core.h> 18#include <sound/core.h>
17#include <sound/initval.h> 19#include <sound/initval.h>
18#include <sound/soc-dapm.h> 20#include <sound/soc-dapm.h>
@@ -172,8 +174,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
172 return -EINVAL; 174 return -EINVAL;
173 175
174 /* hw_write and control_data pointers required for talking to the modem 176 /* hw_write and control_data pointers required for talking to the modem
175 * are expected to be set by the machine driver's line discipline 177 * are expected to be set by the line discipline initialization code */
176 * initialization code */
177 if (!codec->hw_write || !codec->control_data) 178 if (!codec->hw_write || !codec->control_data)
178 return -EIO; 179 return -EIO;
179 180
@@ -208,6 +209,111 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
208 return 0; 209 return 0;
209} 210}
210 211
212
213/* Moved up here as line discipline referres it during initialization */
214static struct snd_soc_codec *cx20442_codec;
215
216
217/*
218 * Line discpline related code
219 *
220 * Any of the callback functions below can be used in two ways:
221 * 1) registerd by a machine driver as one of line discipline operations,
222 * 2) called from a machine's provided line discipline callback function
223 * in case when extra machine specific code must be run as well.
224 */
225
226/* Modem init: echo off, digital speaker off, quiet off, voice mode */
227static const char *v253_init = "ate0m0q0+fclass=8\r";
228
229/* Line discipline .open() */
230static int v253_open(struct tty_struct *tty)
231{
232 struct snd_soc_codec *codec = cx20442_codec;
233 int ret, len = strlen(v253_init);
234
235 /* Doesn't make sense without write callback */
236 if (!tty->ops->write)
237 return -EINVAL;
238
239 /* Pass the codec structure address for use by other ldisc callbacks */
240 tty->disc_data = codec;
241
242 if (tty->ops->write(tty, v253_init, len) != len) {
243 ret = -EIO;
244 goto err;
245 }
246 /* Actual setup will be performed after the modem responds. */
247 return 0;
248err:
249 tty->disc_data = NULL;
250 return ret;
251}
252
253/* Line discipline .close() */
254static void v253_close(struct tty_struct *tty)
255{
256 struct snd_soc_codec *codec = tty->disc_data;
257
258 tty->disc_data = NULL;
259
260 if (!codec)
261 return;
262
263 /* Prevent the codec driver from further accessing the modem */
264 codec->hw_write = NULL;
265 codec->control_data = NULL;
266 codec->pop_time = 0;
267}
268
269/* Line discipline .hangup() */
270static int v253_hangup(struct tty_struct *tty)
271{
272 v253_close(tty);
273 return 0;
274}
275
276/* Line discipline .receive_buf() */
277static void v253_receive(struct tty_struct *tty,
278 const unsigned char *cp, char *fp, int count)
279{
280 struct snd_soc_codec *codec = tty->disc_data;
281
282 if (!codec)
283 return;
284
285 if (!codec->control_data) {
286 /* First modem response, complete setup procedure */
287
288 /* Set up codec driver access to modem controls */
289 codec->control_data = tty;
290 codec->hw_write = (hw_write_t)tty->ops->write;
291 codec->pop_time = 1;
292 }
293}
294
295/* Line discipline .write_wakeup() */
296static void v253_wakeup(struct tty_struct *tty)
297{
298}
299
300struct tty_ldisc_ops v253_ops = {
301 .magic = TTY_LDISC_MAGIC,
302 .name = "cx20442",
303 .owner = THIS_MODULE,
304 .open = v253_open,
305 .close = v253_close,
306 .hangup = v253_hangup,
307 .receive_buf = v253_receive,
308 .write_wakeup = v253_wakeup,
309};
310EXPORT_SYMBOL_GPL(v253_ops);
311
312
313/*
314 * Codec DAI
315 */
316
211struct snd_soc_dai cx20442_dai = { 317struct snd_soc_dai cx20442_dai = {
212 .name = "CX20442", 318 .name = "CX20442",
213 .playback = { 319 .playback = {
@@ -227,8 +333,6 @@ struct snd_soc_dai cx20442_dai = {
227}; 333};
228EXPORT_SYMBOL_GPL(cx20442_dai); 334EXPORT_SYMBOL_GPL(cx20442_dai);
229 335
230static struct snd_soc_codec *cx20442_codec;
231
232static int cx20442_codec_probe(struct platform_device *pdev) 336static int cx20442_codec_probe(struct platform_device *pdev)
233{ 337{
234 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 338 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@@ -313,13 +417,13 @@ static int cx20442_register(struct cx20442_priv *cx20442)
313 417
314 ret = snd_soc_register_codec(codec); 418 ret = snd_soc_register_codec(codec);
315 if (ret != 0) { 419 if (ret != 0) {
316 dev_err(&codec->dev, "Failed to register codec: %d\n", ret); 420 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
317 goto err; 421 goto err;
318 } 422 }
319 423
320 ret = snd_soc_register_dai(&cx20442_dai); 424 ret = snd_soc_register_dai(&cx20442_dai);
321 if (ret != 0) { 425 if (ret != 0) {
322 dev_err(&codec->dev, "Failed to register DAI: %d\n", ret); 426 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
323 goto err_codec; 427 goto err_codec;
324 } 428 }
325 429
diff --git a/sound/soc/codecs/cx20442.h b/sound/soc/codecs/cx20442.h
index d0a4f297aef4..688a5eb62e17 100644
--- a/sound/soc/codecs/cx20442.h
+++ b/sound/soc/codecs/cx20442.h
@@ -15,5 +15,6 @@
15 15
16extern struct snd_soc_dai cx20442_dai; 16extern struct snd_soc_dai cx20442_dai;
17extern struct snd_soc_codec_device cx20442_codec_dev; 17extern struct snd_soc_codec_device cx20442_codec_dev;
18extern struct tty_ldisc_ops v253_ops;
18 19
19#endif 20#endif