0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/module.h>
0032 #include <linux/moduleparam.h>
0033 #include <linux/platform_device.h>
0034
0035 #include <asm/mach-types.h>
0036 #include <linux/platform_data/asoc-pxa.h>
0037
0038 #include <sound/core.h>
0039 #include <sound/pcm.h>
0040 #include <sound/soc.h>
0041 #include <sound/initval.h>
0042 #include <sound/ac97_codec.h>
0043
0044 #include "../codecs/wm9713.h"
0045
0046 #define AC97_GPIO_PULL 0x58
0047
0048
0049 static int rear_amp_power(struct snd_soc_component *component, int power)
0050 {
0051 unsigned short reg;
0052
0053 if (power) {
0054 reg = snd_soc_component_read(component, AC97_GPIO_CFG);
0055 snd_soc_component_write(component, AC97_GPIO_CFG, reg | 0x0100);
0056 reg = snd_soc_component_read(component, AC97_GPIO_PULL);
0057 snd_soc_component_write(component, AC97_GPIO_PULL, reg | (1<<15));
0058 } else {
0059 reg = snd_soc_component_read(component, AC97_GPIO_CFG);
0060 snd_soc_component_write(component, AC97_GPIO_CFG, reg & ~0x0100);
0061 reg = snd_soc_component_read(component, AC97_GPIO_PULL);
0062 snd_soc_component_write(component, AC97_GPIO_PULL, reg & ~(1<<15));
0063 }
0064
0065 return 0;
0066 }
0067
0068 static int rear_amp_event(struct snd_soc_dapm_widget *widget,
0069 struct snd_kcontrol *kctl, int event)
0070 {
0071 struct snd_soc_card *card = widget->dapm->card;
0072 struct snd_soc_pcm_runtime *rtd;
0073 struct snd_soc_component *component;
0074
0075 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]);
0076 component = asoc_rtd_to_codec(rtd, 0)->component;
0077 return rear_amp_power(component, SND_SOC_DAPM_EVENT_ON(event));
0078 }
0079
0080
0081 static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = {
0082 SND_SOC_DAPM_SPK("Front Speaker", NULL),
0083 SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event),
0084 SND_SOC_DAPM_MIC("Headset", NULL),
0085 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
0086 SND_SOC_DAPM_LINE("GSM Line In", NULL),
0087 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0088 SND_SOC_DAPM_MIC("Front Mic", NULL),
0089 };
0090
0091 static const struct snd_soc_dapm_route audio_map[] = {
0092
0093 {"Mic Bias", NULL, "Front Mic"},
0094 {"MIC1", NULL, "Mic Bias"},
0095
0096
0097 {"LINEL", NULL, "Headset Mic"},
0098 {"LINER", NULL, "Headset Mic"},
0099
0100
0101 {"MONOIN", NULL, "GSM Line Out"},
0102 {"PCBEEP", NULL, "GSM Line Out"},
0103 {"GSM Line In", NULL, "MONO"},
0104
0105
0106 {"Headset", NULL, "HPL"},
0107 {"Headset", NULL, "HPR"},
0108
0109
0110 {"Front Speaker", NULL, "HPL"},
0111 {"Front Speaker", NULL, "OUT3"},
0112
0113
0114 {"Rear Speaker", NULL, "SPKL"},
0115 {"Rear Speaker", NULL, "SPKR"},
0116 };
0117
0118 static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
0119 {
0120 struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
0121
0122
0123 snd_soc_component_update_bits(component, AC97_GPIO_CFG, 0x100, 0x100);
0124
0125
0126 snd_soc_component_update_bits(component, AC97_3D_CONTROL, 0xc000, 0xc000);
0127
0128 return 0;
0129 }
0130
0131 static struct snd_soc_ops mioa701_ops;
0132
0133 SND_SOC_DAILINK_DEFS(ac97,
0134 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
0135 DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-hifi")),
0136 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
0137
0138 SND_SOC_DAILINK_DEFS(ac97_aux,
0139 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
0140 DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-aux")),
0141 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
0142
0143 static struct snd_soc_dai_link mioa701_dai[] = {
0144 {
0145 .name = "AC97",
0146 .stream_name = "AC97 HiFi",
0147 .init = mioa701_wm9713_init,
0148 .ops = &mioa701_ops,
0149 SND_SOC_DAILINK_REG(ac97),
0150 },
0151 {
0152 .name = "AC97 Aux",
0153 .stream_name = "AC97 Aux",
0154 .ops = &mioa701_ops,
0155 SND_SOC_DAILINK_REG(ac97_aux),
0156 },
0157 };
0158
0159 static struct snd_soc_card mioa701 = {
0160 .name = "MioA701",
0161 .owner = THIS_MODULE,
0162 .dai_link = mioa701_dai,
0163 .num_links = ARRAY_SIZE(mioa701_dai),
0164
0165 .dapm_widgets = mioa701_dapm_widgets,
0166 .num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets),
0167 .dapm_routes = audio_map,
0168 .num_dapm_routes = ARRAY_SIZE(audio_map),
0169 };
0170
0171 static int mioa701_wm9713_probe(struct platform_device *pdev)
0172 {
0173 int rc;
0174
0175 if (!machine_is_mioa701())
0176 return -ENODEV;
0177
0178 mioa701.dev = &pdev->dev;
0179 rc = devm_snd_soc_register_card(&pdev->dev, &mioa701);
0180 if (!rc)
0181 dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will "
0182 "lead to overheating and possible destruction of your device."
0183 " Do not use without a good knowledge of mio's board design!\n");
0184 return rc;
0185 }
0186
0187 static struct platform_driver mioa701_wm9713_driver = {
0188 .probe = mioa701_wm9713_probe,
0189 .driver = {
0190 .name = "mioa701-wm9713",
0191 .pm = &snd_soc_pm_ops,
0192 },
0193 };
0194
0195 module_platform_driver(mioa701_wm9713_driver);
0196
0197
0198 MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)");
0199 MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701");
0200 MODULE_LICENSE("GPL");
0201 MODULE_ALIAS("platform:mioa701-wm9713");