diff options
-rw-r--r-- | sound/soc/codecs/cx20442.c | 116 | ||||
-rw-r--r-- | sound/soc/codecs/cx20442.h | 1 |
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 */ | ||
214 | static 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 */ | ||
227 | static const char *v253_init = "ate0m0q0+fclass=8\r"; | ||
228 | |||
229 | /* Line discipline .open() */ | ||
230 | static 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; | ||
248 | err: | ||
249 | tty->disc_data = NULL; | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | /* Line discipline .close() */ | ||
254 | static 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() */ | ||
270 | static int v253_hangup(struct tty_struct *tty) | ||
271 | { | ||
272 | v253_close(tty); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* Line discipline .receive_buf() */ | ||
277 | static 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() */ | ||
296 | static void v253_wakeup(struct tty_struct *tty) | ||
297 | { | ||
298 | } | ||
299 | |||
300 | struct 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 | }; | ||
310 | EXPORT_SYMBOL_GPL(v253_ops); | ||
311 | |||
312 | |||
313 | /* | ||
314 | * Codec DAI | ||
315 | */ | ||
316 | |||
211 | struct snd_soc_dai cx20442_dai = { | 317 | struct 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 | }; |
228 | EXPORT_SYMBOL_GPL(cx20442_dai); | 334 | EXPORT_SYMBOL_GPL(cx20442_dai); |
229 | 335 | ||
230 | static struct snd_soc_codec *cx20442_codec; | ||
231 | |||
232 | static int cx20442_codec_probe(struct platform_device *pdev) | 336 | static 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 | ||
16 | extern struct snd_soc_dai cx20442_dai; | 16 | extern struct snd_soc_dai cx20442_dai; |
17 | extern struct snd_soc_codec_device cx20442_codec_dev; | 17 | extern struct snd_soc_codec_device cx20442_codec_dev; |
18 | extern struct tty_ldisc_ops v253_ops; | ||
18 | 19 | ||
19 | #endif | 20 | #endif |