0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/gpio/consumer.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/tty.h>
0014 #include <linux/module.h>
0015
0016 #include <sound/soc.h>
0017 #include <sound/jack.h>
0018
0019 #include <asm/mach-types.h>
0020
0021 #include <linux/platform_data/asoc-ti-mcbsp.h>
0022
0023 #include "omap-mcbsp.h"
0024 #include "../codecs/cx20442.h"
0025
0026 static struct gpio_desc *handset_mute;
0027 static struct gpio_desc *handsfree_mute;
0028
0029 static int ams_delta_event_handset(struct snd_soc_dapm_widget *w,
0030 struct snd_kcontrol *k, int event)
0031 {
0032 gpiod_set_value_cansleep(handset_mute, !SND_SOC_DAPM_EVENT_ON(event));
0033 return 0;
0034 }
0035
0036 static int ams_delta_event_handsfree(struct snd_soc_dapm_widget *w,
0037 struct snd_kcontrol *k, int event)
0038 {
0039 gpiod_set_value_cansleep(handsfree_mute, !SND_SOC_DAPM_EVENT_ON(event));
0040 return 0;
0041 }
0042
0043
0044 static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = {
0045
0046 SND_SOC_DAPM_MIC("Mouthpiece", NULL),
0047 SND_SOC_DAPM_HP("Earpiece", ams_delta_event_handset),
0048
0049 SND_SOC_DAPM_MIC("Microphone", NULL),
0050 SND_SOC_DAPM_SPK("Speaker", ams_delta_event_handsfree),
0051 };
0052
0053
0054 static const struct snd_soc_dapm_route ams_delta_audio_map[] = {
0055 {"TELIN", NULL, "Mouthpiece"},
0056 {"Earpiece", NULL, "TELOUT"},
0057
0058 {"MIC", NULL, "Microphone"},
0059 {"Speaker", NULL, "SPKOUT"},
0060 };
0061
0062
0063
0064
0065
0066
0067 static const char *ams_delta_audio_mode[] =
0068 {"Mixed", "Handset", "Handsfree", "Speakerphone"};
0069
0070
0071 #define AMS_DELTA_MOUTHPIECE 0
0072 #define AMS_DELTA_EARPIECE 1
0073 #define AMS_DELTA_MICROPHONE 2
0074 #define AMS_DELTA_SPEAKER 3
0075 #define AMS_DELTA_AGC 4
0076
0077 #define AMS_DELTA_MIXED ((1 << AMS_DELTA_EARPIECE) | \
0078 (1 << AMS_DELTA_MICROPHONE))
0079 #define AMS_DELTA_HANDSET ((1 << AMS_DELTA_MOUTHPIECE) | \
0080 (1 << AMS_DELTA_EARPIECE))
0081 #define AMS_DELTA_HANDSFREE ((1 << AMS_DELTA_MICROPHONE) | \
0082 (1 << AMS_DELTA_SPEAKER))
0083 #define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC))
0084
0085 static const unsigned short ams_delta_audio_mode_pins[] = {
0086 AMS_DELTA_MIXED,
0087 AMS_DELTA_HANDSET,
0088 AMS_DELTA_HANDSFREE,
0089 AMS_DELTA_SPEAKERPHONE,
0090 };
0091
0092 static unsigned short ams_delta_audio_agc;
0093
0094
0095
0096
0097
0098 static struct snd_soc_component *cx20442_codec;
0099
0100 static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
0101 struct snd_ctl_elem_value *ucontrol)
0102 {
0103 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0104 struct snd_soc_dapm_context *dapm = &card->dapm;
0105 struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
0106 unsigned short pins;
0107 int pin, changed = 0;
0108
0109
0110 if (!cx20442_codec->card->pop_time)
0111 return -EUNATCH;
0112
0113 if (ucontrol->value.enumerated.item[0] >= control->items)
0114 return -EINVAL;
0115
0116 snd_soc_dapm_mutex_lock(dapm);
0117
0118
0119 pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]];
0120
0121
0122 pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
0123
0124 if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) {
0125 changed = 1;
0126 if (pin)
0127 snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece");
0128 else
0129 snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
0130 }
0131 pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
0132 if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) {
0133 changed = 1;
0134 if (pin)
0135 snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
0136 else
0137 snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece");
0138 }
0139 pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
0140 if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) {
0141 changed = 1;
0142 if (pin)
0143 snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
0144 else
0145 snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone");
0146 }
0147 pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
0148 if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) {
0149 changed = 1;
0150 if (pin)
0151 snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
0152 else
0153 snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
0154 }
0155 pin = !!(pins & (1 << AMS_DELTA_AGC));
0156 if (pin != ams_delta_audio_agc) {
0157 ams_delta_audio_agc = pin;
0158 changed = 1;
0159 if (pin)
0160 snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN");
0161 else
0162 snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
0163 }
0164
0165 if (changed)
0166 snd_soc_dapm_sync_unlocked(dapm);
0167
0168 snd_soc_dapm_mutex_unlock(dapm);
0169
0170 return changed;
0171 }
0172
0173 static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
0174 struct snd_ctl_elem_value *ucontrol)
0175 {
0176 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0177 struct snd_soc_dapm_context *dapm = &card->dapm;
0178 unsigned short pins, mode;
0179
0180 pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
0181 AMS_DELTA_MOUTHPIECE) |
0182 (snd_soc_dapm_get_pin_status(dapm, "Earpiece") <<
0183 AMS_DELTA_EARPIECE));
0184 if (pins)
0185 pins |= (snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
0186 AMS_DELTA_MICROPHONE);
0187 else
0188 pins = ((snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
0189 AMS_DELTA_MICROPHONE) |
0190 (snd_soc_dapm_get_pin_status(dapm, "Speaker") <<
0191 AMS_DELTA_SPEAKER) |
0192 (ams_delta_audio_agc << AMS_DELTA_AGC));
0193
0194 for (mode = 0; mode < ARRAY_SIZE(ams_delta_audio_mode); mode++)
0195 if (pins == ams_delta_audio_mode_pins[mode])
0196 break;
0197
0198 if (mode >= ARRAY_SIZE(ams_delta_audio_mode))
0199 return -EINVAL;
0200
0201 ucontrol->value.enumerated.item[0] = mode;
0202
0203 return 0;
0204 }
0205
0206 static SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
0207 ams_delta_audio_mode);
0208
0209 static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
0210 SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum,
0211 ams_delta_get_audio_mode, ams_delta_set_audio_mode),
0212 };
0213
0214
0215 static struct snd_soc_jack ams_delta_hook_switch;
0216 static struct snd_soc_jack_gpio ams_delta_hook_switch_gpios[] = {
0217 {
0218 .name = "hook_switch",
0219 .report = SND_JACK_HEADSET,
0220 .invert = 1,
0221 .debounce_time = 150,
0222 }
0223 };
0224
0225
0226
0227 static struct snd_soc_jack_pin ams_delta_hook_switch_pins[] = {
0228
0229 {
0230 .pin = "Mouthpiece",
0231 .mask = SND_JACK_MICROPHONE,
0232 },
0233 {
0234 .pin = "Earpiece",
0235 .mask = SND_JACK_HEADPHONE,
0236 },
0237
0238 {
0239 .pin = "Microphone",
0240 .mask = SND_JACK_MICROPHONE,
0241 .invert = 1,
0242 },
0243 {
0244 .pin = "Speaker",
0245 .mask = SND_JACK_HEADPHONE,
0246 .invert = 1,
0247 },
0248 };
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259 static struct timer_list cx81801_timer;
0260 static bool cx81801_cmd_pending;
0261 static bool ams_delta_muted;
0262 static DEFINE_SPINLOCK(ams_delta_lock);
0263 static struct gpio_desc *gpiod_modem_codec;
0264
0265 static void cx81801_timeout(struct timer_list *unused)
0266 {
0267 int muted;
0268
0269 spin_lock(&ams_delta_lock);
0270 cx81801_cmd_pending = 0;
0271 muted = ams_delta_muted;
0272 spin_unlock(&ams_delta_lock);
0273
0274
0275
0276 if (!muted)
0277 gpiod_set_value(gpiod_modem_codec, 0);
0278 }
0279
0280
0281 static int cx81801_open(struct tty_struct *tty)
0282 {
0283 int ret;
0284
0285 if (!cx20442_codec)
0286 return -ENODEV;
0287
0288
0289
0290
0291
0292 tty->disc_data = cx20442_codec;
0293
0294 ret = v253_ops.open(tty);
0295
0296 if (ret < 0)
0297 tty->disc_data = NULL;
0298
0299 return ret;
0300 }
0301
0302
0303 static void cx81801_close(struct tty_struct *tty)
0304 {
0305 struct snd_soc_component *component = tty->disc_data;
0306 struct snd_soc_dapm_context *dapm = &component->card->dapm;
0307
0308 del_timer_sync(&cx81801_timer);
0309
0310
0311 INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
0312
0313 if (!component)
0314 return;
0315
0316 v253_ops.close(tty);
0317
0318
0319 snd_soc_dapm_mutex_lock(dapm);
0320
0321 snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece");
0322 snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece");
0323 snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone");
0324 snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
0325 snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN");
0326
0327 snd_soc_dapm_sync_unlocked(dapm);
0328
0329 snd_soc_dapm_mutex_unlock(dapm);
0330 }
0331
0332
0333 static void cx81801_hangup(struct tty_struct *tty)
0334 {
0335 cx81801_close(tty);
0336 }
0337
0338
0339 static void cx81801_receive(struct tty_struct *tty, const unsigned char *cp,
0340 const char *fp, int count)
0341 {
0342 struct snd_soc_component *component = tty->disc_data;
0343 const unsigned char *c;
0344 int apply, ret;
0345
0346 if (!component)
0347 return;
0348
0349 if (!component->card->pop_time) {
0350
0351
0352
0353 timer_setup(&cx81801_timer, cx81801_timeout, 0);
0354
0355 v253_ops.receive_buf(tty, cp, fp, count);
0356
0357
0358 ret = snd_soc_jack_add_pins(&ams_delta_hook_switch,
0359 ARRAY_SIZE(ams_delta_hook_switch_pins),
0360 ams_delta_hook_switch_pins);
0361 if (ret)
0362 dev_warn(component->dev,
0363 "Failed to link hook switch to DAPM pins, "
0364 "will continue with hook switch unlinked.\n");
0365
0366 return;
0367 }
0368
0369 v253_ops.receive_buf(tty, cp, fp, count);
0370
0371 for (c = &cp[count - 1]; c >= cp; c--) {
0372 if (*c != '\r')
0373 continue;
0374
0375
0376 spin_lock_bh(&ams_delta_lock);
0377 mod_timer(&cx81801_timer, jiffies + msecs_to_jiffies(150));
0378 apply = !ams_delta_muted && !cx81801_cmd_pending;
0379 cx81801_cmd_pending = 1;
0380 spin_unlock_bh(&ams_delta_lock);
0381
0382
0383
0384 if (apply)
0385 gpiod_set_value(gpiod_modem_codec, 1);
0386 break;
0387 }
0388 }
0389
0390
0391 static void cx81801_wakeup(struct tty_struct *tty)
0392 {
0393 v253_ops.write_wakeup(tty);
0394 }
0395
0396 static struct tty_ldisc_ops cx81801_ops = {
0397 .name = "cx81801",
0398 .num = N_V253,
0399 .owner = THIS_MODULE,
0400 .open = cx81801_open,
0401 .close = cx81801_close,
0402 .hangup = cx81801_hangup,
0403 .receive_buf = cx81801_receive,
0404 .write_wakeup = cx81801_wakeup,
0405 };
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415 static struct snd_soc_ops ams_delta_ops;
0416
0417
0418
0419
0420 static bool ams_delta_muted = 1;
0421
0422 static int ams_delta_mute(struct snd_soc_dai *dai, int mute, int direction)
0423 {
0424 int apply;
0425
0426 if (ams_delta_muted == mute)
0427 return 0;
0428
0429 spin_lock_bh(&ams_delta_lock);
0430 ams_delta_muted = mute;
0431 apply = !cx81801_cmd_pending;
0432 spin_unlock_bh(&ams_delta_lock);
0433
0434 if (apply)
0435 gpiod_set_value(gpiod_modem_codec, !!mute);
0436 return 0;
0437 }
0438
0439
0440 static const struct snd_soc_dai_ops ams_delta_dai_ops = {
0441 .mute_stream = ams_delta_mute,
0442 .no_capture_mute = 1,
0443 };
0444
0445
0446 static int ams_delta_startup(struct snd_pcm_substream *substream)
0447 {
0448 return ams_delta_mute(NULL, 0, substream->stream);
0449 }
0450
0451 static void ams_delta_shutdown(struct snd_pcm_substream *substream)
0452 {
0453 ams_delta_mute(NULL, 1, substream->stream);
0454 }
0455
0456
0457
0458
0459
0460
0461 static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
0462 {
0463 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0464 struct snd_soc_card *card = rtd->card;
0465 struct snd_soc_dapm_context *dapm = &card->dapm;
0466 int ret;
0467
0468
0469
0470 cx20442_codec = asoc_rtd_to_codec(rtd, 0)->component;
0471
0472
0473
0474 ret = snd_soc_card_jack_new_pins(card, "hook_switch", SND_JACK_HEADSET,
0475 &ams_delta_hook_switch, NULL, 0);
0476 if (ret)
0477 dev_warn(card->dev,
0478 "Failed to allocate resources for hook switch, "
0479 "will continue without one.\n");
0480 else {
0481 ret = snd_soc_jack_add_gpiods(card->dev, &ams_delta_hook_switch,
0482 ARRAY_SIZE(ams_delta_hook_switch_gpios),
0483 ams_delta_hook_switch_gpios);
0484 if (ret)
0485 dev_warn(card->dev,
0486 "Failed to set up hook switch GPIO line, "
0487 "will continue with hook switch inactive.\n");
0488 }
0489
0490 gpiod_modem_codec = devm_gpiod_get(card->dev, "modem_codec",
0491 GPIOD_OUT_HIGH);
0492 if (IS_ERR(gpiod_modem_codec)) {
0493 dev_warn(card->dev, "Failed to obtain modem_codec GPIO\n");
0494 return 0;
0495 }
0496
0497
0498 if (!codec_dai->driver->ops) {
0499 codec_dai->driver->ops = &ams_delta_dai_ops;
0500 } else {
0501 ams_delta_ops.startup = ams_delta_startup;
0502 ams_delta_ops.shutdown = ams_delta_shutdown;
0503 }
0504
0505
0506 ret = tty_register_ldisc(&cx81801_ops);
0507 if (ret) {
0508 dev_warn(card->dev,
0509 "Failed to register line discipline, "
0510 "will continue without any controls.\n");
0511 return 0;
0512 }
0513
0514
0515 snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
0516 snd_soc_dapm_disable_pin(dapm, "Speaker");
0517 snd_soc_dapm_disable_pin(dapm, "AGCIN");
0518 snd_soc_dapm_disable_pin(dapm, "AGCOUT");
0519
0520 return 0;
0521 }
0522
0523
0524 SND_SOC_DAILINK_DEFS(cx20442,
0525 DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.1")),
0526 DAILINK_COMP_ARRAY(COMP_CODEC("cx20442-codec", "cx20442-voice")),
0527 DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.1")));
0528
0529 static struct snd_soc_dai_link ams_delta_dai_link = {
0530 .name = "CX20442",
0531 .stream_name = "CX20442",
0532 .init = ams_delta_cx20442_init,
0533 .ops = &ams_delta_ops,
0534 .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
0535 SND_SOC_DAIFMT_CBM_CFM,
0536 SND_SOC_DAILINK_REG(cx20442),
0537 };
0538
0539
0540 static struct snd_soc_card ams_delta_audio_card = {
0541 .name = "AMS_DELTA",
0542 .owner = THIS_MODULE,
0543 .dai_link = &ams_delta_dai_link,
0544 .num_links = 1,
0545
0546 .controls = ams_delta_audio_controls,
0547 .num_controls = ARRAY_SIZE(ams_delta_audio_controls),
0548 .dapm_widgets = ams_delta_dapm_widgets,
0549 .num_dapm_widgets = ARRAY_SIZE(ams_delta_dapm_widgets),
0550 .dapm_routes = ams_delta_audio_map,
0551 .num_dapm_routes = ARRAY_SIZE(ams_delta_audio_map),
0552 };
0553
0554
0555 static int ams_delta_probe(struct platform_device *pdev)
0556 {
0557 struct snd_soc_card *card = &ams_delta_audio_card;
0558 int ret;
0559
0560 card->dev = &pdev->dev;
0561
0562 handset_mute = devm_gpiod_get(card->dev, "handset_mute",
0563 GPIOD_OUT_HIGH);
0564 if (IS_ERR(handset_mute))
0565 return PTR_ERR(handset_mute);
0566
0567 handsfree_mute = devm_gpiod_get(card->dev, "handsfree_mute",
0568 GPIOD_OUT_HIGH);
0569 if (IS_ERR(handsfree_mute))
0570 return PTR_ERR(handsfree_mute);
0571
0572 ret = snd_soc_register_card(card);
0573 if (ret) {
0574 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
0575 card->dev = NULL;
0576 return ret;
0577 }
0578 return 0;
0579 }
0580
0581 static int ams_delta_remove(struct platform_device *pdev)
0582 {
0583 struct snd_soc_card *card = platform_get_drvdata(pdev);
0584
0585 tty_unregister_ldisc(&cx81801_ops);
0586
0587 snd_soc_unregister_card(card);
0588 card->dev = NULL;
0589 return 0;
0590 }
0591
0592 #define DRV_NAME "ams-delta-audio"
0593
0594 static struct platform_driver ams_delta_driver = {
0595 .driver = {
0596 .name = DRV_NAME,
0597 },
0598 .probe = ams_delta_probe,
0599 .remove = ams_delta_remove,
0600 };
0601
0602 module_platform_driver(ams_delta_driver);
0603
0604 MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
0605 MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone");
0606 MODULE_LICENSE("GPL");
0607 MODULE_ALIAS("platform:" DRV_NAME);