0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/types.h>
0011 #include <linux/gpio/consumer.h>
0012 #include <linux/module.h>
0013
0014 #include <sound/soc.h>
0015 #include <sound/jack.h>
0016
0017 #include "regs-iis.h"
0018 #include "s3c24xx-i2s.h"
0019
0020 static const unsigned int rates[] = {
0021 11025,
0022 22050,
0023 44100,
0024 };
0025
0026 static const struct snd_pcm_hw_constraint_list hw_rates = {
0027 .count = ARRAY_SIZE(rates),
0028 .list = rates,
0029 };
0030
0031 static struct gpio_desc *gpiod_speaker_power;
0032
0033 static struct snd_soc_jack hp_jack;
0034
0035 static struct snd_soc_jack_pin hp_jack_pins[] = {
0036 {
0037 .pin = "Headphone Jack",
0038 .mask = SND_JACK_HEADPHONE,
0039 },
0040 {
0041 .pin = "Speaker",
0042 .mask = SND_JACK_HEADPHONE,
0043 .invert = 1,
0044 },
0045 };
0046
0047 static struct snd_soc_jack_gpio hp_jack_gpios[] = {
0048 {
0049 .name = "hp-gpio",
0050 .report = SND_JACK_HEADPHONE,
0051 .invert = 1,
0052 .debounce_time = 200,
0053 },
0054 };
0055
0056 static int h1940_startup(struct snd_pcm_substream *substream)
0057 {
0058 struct snd_pcm_runtime *runtime = substream->runtime;
0059
0060 return snd_pcm_hw_constraint_list(runtime, 0,
0061 SNDRV_PCM_HW_PARAM_RATE,
0062 &hw_rates);
0063 }
0064
0065 static int h1940_hw_params(struct snd_pcm_substream *substream,
0066 struct snd_pcm_hw_params *params)
0067 {
0068 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0069 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0070 int div;
0071 int ret;
0072 unsigned int rate = params_rate(params);
0073
0074 switch (rate) {
0075 case 11025:
0076 case 22050:
0077 case 44100:
0078 div = s3c24xx_i2s_get_clockrate() / (384 * rate);
0079 if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate))
0080 div++;
0081 break;
0082 default:
0083 dev_err(rtd->dev, "%s: rate %d is not supported\n",
0084 __func__, rate);
0085 return -EINVAL;
0086 }
0087
0088
0089 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
0090 SND_SOC_CLOCK_OUT);
0091 if (ret < 0)
0092 return ret;
0093
0094
0095 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
0096 S3C2410_IISMOD_384FS);
0097 if (ret < 0)
0098 return ret;
0099
0100
0101 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
0102 S3C2410_IISMOD_32FS);
0103 if (ret < 0)
0104 return ret;
0105
0106
0107 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
0108 S3C24XX_PRESCALE(div, div));
0109 if (ret < 0)
0110 return ret;
0111
0112 return 0;
0113 }
0114
0115 static const struct snd_soc_ops h1940_ops = {
0116 .startup = h1940_startup,
0117 .hw_params = h1940_hw_params,
0118 };
0119
0120 static int h1940_spk_power(struct snd_soc_dapm_widget *w,
0121 struct snd_kcontrol *kcontrol, int event)
0122 {
0123 if (SND_SOC_DAPM_EVENT_ON(event))
0124 gpiod_set_value(gpiod_speaker_power, 1);
0125 else
0126 gpiod_set_value(gpiod_speaker_power, 0);
0127
0128 return 0;
0129 }
0130
0131
0132 static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
0133 SND_SOC_DAPM_HP("Headphone Jack", NULL),
0134 SND_SOC_DAPM_MIC("Mic Jack", NULL),
0135 SND_SOC_DAPM_SPK("Speaker", h1940_spk_power),
0136 };
0137
0138
0139 static const struct snd_soc_dapm_route audio_map[] = {
0140
0141 {"Headphone Jack", NULL, "VOUTLHP"},
0142 {"Headphone Jack", NULL, "VOUTRHP"},
0143
0144
0145 {"Speaker", NULL, "VOUTL"},
0146 {"Speaker", NULL, "VOUTR"},
0147
0148
0149 {"VINM", NULL, "Mic Jack"},
0150 };
0151
0152 static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
0153 {
0154 snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
0155 SND_JACK_HEADPHONE,
0156 &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
0157
0158 snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
0159 hp_jack_gpios);
0160
0161 return 0;
0162 }
0163
0164
0165 SND_SOC_DAILINK_DEFS(uda1380,
0166 DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
0167 DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-001a", "uda1380-hifi")),
0168 DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
0169
0170 static struct snd_soc_dai_link h1940_uda1380_dai[] = {
0171 {
0172 .name = "uda1380",
0173 .stream_name = "UDA1380 Duplex",
0174 .init = h1940_uda1380_init,
0175 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0176 SND_SOC_DAIFMT_CBS_CFS,
0177 .ops = &h1940_ops,
0178 SND_SOC_DAILINK_REG(uda1380),
0179 },
0180 };
0181
0182 static struct snd_soc_card h1940_asoc = {
0183 .name = "h1940",
0184 .owner = THIS_MODULE,
0185 .dai_link = h1940_uda1380_dai,
0186 .num_links = ARRAY_SIZE(h1940_uda1380_dai),
0187
0188 .dapm_widgets = uda1380_dapm_widgets,
0189 .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
0190 .dapm_routes = audio_map,
0191 .num_dapm_routes = ARRAY_SIZE(audio_map),
0192 };
0193
0194 static int h1940_probe(struct platform_device *pdev)
0195 {
0196 struct device *dev = &pdev->dev;
0197
0198 h1940_asoc.dev = dev;
0199 hp_jack_gpios[0].gpiod_dev = dev;
0200 gpiod_speaker_power = devm_gpiod_get(&pdev->dev, "speaker-power",
0201 GPIOD_OUT_LOW);
0202
0203 if (IS_ERR(gpiod_speaker_power)) {
0204 dev_err(dev, "Could not get gpio\n");
0205 return PTR_ERR(gpiod_speaker_power);
0206 }
0207
0208 return devm_snd_soc_register_card(dev, &h1940_asoc);
0209 }
0210
0211 static struct platform_driver h1940_audio_driver = {
0212 .driver = {
0213 .name = "h1940-audio",
0214 .pm = &snd_soc_pm_ops,
0215 },
0216 .probe = h1940_probe,
0217 };
0218 module_platform_driver(h1940_audio_driver);
0219
0220
0221 MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick");
0222 MODULE_DESCRIPTION("ALSA SoC H1940");
0223 MODULE_LICENSE("GPL");
0224 MODULE_ALIAS("platform:h1940-audio");