0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/timer.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/delay.h>
0013 #include <linux/gpio/consumer.h>
0014
0015 #include <sound/core.h>
0016 #include <sound/jack.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020
0021 #include <asm/mach-types.h>
0022 #include "pxa2xx-i2s.h"
0023
0024 static struct gpio_desc *gpiod_hp_driver, *gpiod_spk_sd;
0025 static struct snd_soc_jack hs_jack;
0026
0027
0028 static struct snd_soc_jack_pin hs_jack_pin[] = {
0029 {
0030 .pin = "Headphone Jack",
0031 .mask = SND_JACK_HEADPHONE,
0032 .invert = 1,
0033 },
0034 {
0035 .pin = "Speaker",
0036
0037 .mask = SND_JACK_HEADPHONE,
0038 },
0039 };
0040
0041
0042 static struct snd_soc_jack_gpio hs_jack_gpio = {
0043 .name = "earphone-det",
0044 .report = SND_JACK_HEADPHONE,
0045 .debounce_time = 200,
0046 };
0047
0048
0049
0050
0051 static int hx4700_hw_params(struct snd_pcm_substream *substream,
0052 struct snd_pcm_hw_params *params)
0053 {
0054 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0055 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0056 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0057 int ret = 0;
0058
0059
0060 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
0061 SND_SOC_CLOCK_OUT);
0062 if (ret < 0)
0063 return ret;
0064
0065
0066
0067 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params),
0068 SND_SOC_CLOCK_IN);
0069 if (ret < 0)
0070 return ret;
0071
0072 return 0;
0073 }
0074
0075 static const struct snd_soc_ops hx4700_ops = {
0076 .hw_params = hx4700_hw_params,
0077 };
0078
0079 static int hx4700_spk_power(struct snd_soc_dapm_widget *w,
0080 struct snd_kcontrol *k, int event)
0081 {
0082 gpiod_set_value(gpiod_spk_sd, !SND_SOC_DAPM_EVENT_ON(event));
0083 return 0;
0084 }
0085
0086 static int hx4700_hp_power(struct snd_soc_dapm_widget *w,
0087 struct snd_kcontrol *k, int event)
0088 {
0089 gpiod_set_value(gpiod_hp_driver, !!SND_SOC_DAPM_EVENT_ON(event));
0090 return 0;
0091 }
0092
0093
0094 static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = {
0095 SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power),
0096 SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power),
0097 SND_SOC_DAPM_MIC("Built-in Microphone", NULL),
0098 };
0099
0100
0101 static const struct snd_soc_dapm_route hx4700_audio_map[] = {
0102
0103
0104 {"Headphone Jack", NULL, "LOUT"},
0105 {"Headphone Jack", NULL, "ROUT"},
0106
0107
0108 {"Speaker", NULL, "MOUT2"},
0109
0110
0111 {"MICIN", NULL, "Built-in Microphone"},
0112 {"AIN", NULL, "MICOUT"},
0113 };
0114
0115
0116
0117
0118 static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
0119 {
0120 int err;
0121
0122
0123 err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
0124 SND_JACK_HEADPHONE, &hs_jack,
0125 hs_jack_pin, ARRAY_SIZE(hs_jack_pin));
0126 if (err)
0127 return err;
0128
0129 err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio);
0130
0131 return err;
0132 }
0133
0134
0135 SND_SOC_DAILINK_DEFS(ak4641,
0136 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
0137 DAILINK_COMP_ARRAY(COMP_CODEC("ak4641.0-0012", "ak4641-hifi")),
0138 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
0139
0140 static struct snd_soc_dai_link hx4700_dai = {
0141 .name = "ak4641",
0142 .stream_name = "AK4641",
0143 .init = hx4700_ak4641_init,
0144 .dai_fmt = SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
0145 SND_SOC_DAIFMT_CBS_CFS,
0146 .ops = &hx4700_ops,
0147 SND_SOC_DAILINK_REG(ak4641),
0148 };
0149
0150
0151 static struct snd_soc_card snd_soc_card_hx4700 = {
0152 .name = "iPAQ hx4700",
0153 .owner = THIS_MODULE,
0154 .dai_link = &hx4700_dai,
0155 .num_links = 1,
0156 .dapm_widgets = hx4700_dapm_widgets,
0157 .num_dapm_widgets = ARRAY_SIZE(hx4700_dapm_widgets),
0158 .dapm_routes = hx4700_audio_map,
0159 .num_dapm_routes = ARRAY_SIZE(hx4700_audio_map),
0160 .fully_routed = true,
0161 };
0162
0163 static int hx4700_audio_probe(struct platform_device *pdev)
0164 {
0165 int ret;
0166
0167 if (!machine_is_h4700())
0168 return -ENODEV;
0169
0170 gpiod_hp_driver = devm_gpiod_get(&pdev->dev, "hp-driver", GPIOD_ASIS);
0171 ret = PTR_ERR_OR_ZERO(gpiod_hp_driver);
0172 if (ret)
0173 return ret;
0174 gpiod_spk_sd = devm_gpiod_get(&pdev->dev, "spk-sd", GPIOD_ASIS);
0175 ret = PTR_ERR_OR_ZERO(gpiod_spk_sd);
0176 if (ret)
0177 return ret;
0178
0179 hs_jack_gpio.gpiod_dev = &pdev->dev;
0180 snd_soc_card_hx4700.dev = &pdev->dev;
0181 ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_hx4700);
0182
0183 return ret;
0184 }
0185
0186 static int hx4700_audio_remove(struct platform_device *pdev)
0187 {
0188 gpiod_set_value(gpiod_hp_driver, 0);
0189 gpiod_set_value(gpiod_spk_sd, 0);
0190 return 0;
0191 }
0192
0193 static struct platform_driver hx4700_audio_driver = {
0194 .driver = {
0195 .name = "hx4700-audio",
0196 .pm = &snd_soc_pm_ops,
0197 },
0198 .probe = hx4700_audio_probe,
0199 .remove = hx4700_audio_remove,
0200 };
0201
0202 module_platform_driver(hx4700_audio_driver);
0203
0204 MODULE_AUTHOR("Philipp Zabel");
0205 MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
0206 MODULE_LICENSE("GPL");
0207 MODULE_ALIAS("platform:hx4700-audio");