Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // h1940_uda1380.c - ALSA SoC Audio Layer
0004 //
0005 // Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
0006 // Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
0007 //
0008 // Based on version from Arnaud Patard <arnaud.patard@rtp-net.org>
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     /* select clock source */
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     /* set MCLK division for sample rate */
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     /* set BCLK division for sample rate */
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     /* set prescaler division for sample rate */
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 /* h1940 machine dapm widgets */
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 /* h1940 machine audio_map */
0139 static const struct snd_soc_dapm_route audio_map[] = {
0140     /* headphone connected to VOUTLHP, VOUTRHP */
0141     {"Headphone Jack", NULL, "VOUTLHP"},
0142     {"Headphone Jack", NULL, "VOUTRHP"},
0143 
0144     /* ext speaker connected to VOUTL, VOUTR  */
0145     {"Speaker", NULL, "VOUTL"},
0146     {"Speaker", NULL, "VOUTR"},
0147 
0148     /* mic is connected to VINM */
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 /* s3c24xx digital audio interface glue - connects codec <--> CPU */
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 /* Module information */
0221 MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick");
0222 MODULE_DESCRIPTION("ALSA SoC H1940");
0223 MODULE_LICENSE("GPL");
0224 MODULE_ALIAS("platform:h1940-audio");