Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // Copyright (c) 2009 Samsung Electronics Co. Ltd
0004 // Author: Jaswinder Singh <jassisinghbrar@gmail.com>
0005 
0006 #include <linux/module.h>
0007 #include <sound/soc.h>
0008 #include <sound/pcm_params.h>
0009 
0010 #include "../codecs/wm8580.h"
0011 #include "i2s.h"
0012 
0013 /*
0014  * Default CFG switch settings to use this driver:
0015  *
0016  *   SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
0017  */
0018 
0019 /* SMDK has a 12MHZ crystal attached to WM8580 */
0020 #define SMDK_WM8580_FREQ 12000000
0021 
0022 static int smdk_hw_params(struct snd_pcm_substream *substream,
0023     struct snd_pcm_hw_params *params)
0024 {
0025     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0026     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0027     unsigned int pll_out;
0028     int rfs, ret;
0029 
0030     switch (params_width(params)) {
0031     case 8:
0032     case 16:
0033         break;
0034     default:
0035         return -EINVAL;
0036     }
0037 
0038     /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
0039      * This criterion can't be met if we request PLL output
0040      * as {8000x256, 64000x256, 11025x256}Hz.
0041      * As a wayout, we rather change rfs to a minimum value that
0042      * results in (params_rate(params) * rfs), and itself, acceptable
0043      * to both - the CODEC and the CPU.
0044      */
0045     switch (params_rate(params)) {
0046     case 16000:
0047     case 22050:
0048     case 32000:
0049     case 44100:
0050     case 48000:
0051     case 88200:
0052     case 96000:
0053         rfs = 256;
0054         break;
0055     case 64000:
0056         rfs = 384;
0057         break;
0058     case 8000:
0059     case 11025:
0060         rfs = 512;
0061         break;
0062     default:
0063         return -EINVAL;
0064     }
0065     pll_out = params_rate(params) * rfs;
0066 
0067     /* Set WM8580 to drive MCLK from its PLLA */
0068     ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
0069                     WM8580_CLKSRC_PLLA);
0070     if (ret < 0)
0071         return ret;
0072 
0073     ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
0074                     SMDK_WM8580_FREQ, pll_out);
0075     if (ret < 0)
0076         return ret;
0077 
0078     ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
0079                      pll_out, SND_SOC_CLOCK_IN);
0080     if (ret < 0)
0081         return ret;
0082 
0083     return 0;
0084 }
0085 
0086 /*
0087  * SMDK WM8580 DAI operations.
0088  */
0089 static const struct snd_soc_ops smdk_ops = {
0090     .hw_params = smdk_hw_params,
0091 };
0092 
0093 /* SMDK Playback widgets */
0094 static const struct snd_soc_dapm_widget smdk_wm8580_dapm_widgets[] = {
0095     SND_SOC_DAPM_HP("Front", NULL),
0096     SND_SOC_DAPM_HP("Center+Sub", NULL),
0097     SND_SOC_DAPM_HP("Rear", NULL),
0098 
0099     SND_SOC_DAPM_MIC("MicIn", NULL),
0100     SND_SOC_DAPM_LINE("LineIn", NULL),
0101 };
0102 
0103 /* SMDK-PAIFTX connections */
0104 static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
0105     /* MicIn feeds AINL */
0106     {"AINL", NULL, "MicIn"},
0107 
0108     /* LineIn feeds AINL/R */
0109     {"AINL", NULL, "LineIn"},
0110     {"AINR", NULL, "LineIn"},
0111 
0112     /* Front Left/Right are fed VOUT1L/R */
0113     {"Front", NULL, "VOUT1L"},
0114     {"Front", NULL, "VOUT1R"},
0115 
0116     /* Center/Sub are fed VOUT2L/R */
0117     {"Center+Sub", NULL, "VOUT2L"},
0118     {"Center+Sub", NULL, "VOUT2R"},
0119 
0120     /* Rear Left/Right are fed VOUT3L/R */
0121     {"Rear", NULL, "VOUT3L"},
0122     {"Rear", NULL, "VOUT3R"},
0123 };
0124 
0125 static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
0126 {
0127     /* Enabling the microphone requires the fitting of a 0R
0128      * resistor to connect the line from the microphone jack.
0129      */
0130     snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn");
0131 
0132     return 0;
0133 }
0134 
0135 enum {
0136     PRI_PLAYBACK = 0,
0137     PRI_CAPTURE,
0138 };
0139 
0140 #define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
0141     SND_SOC_DAIFMT_CBM_CFM)
0142 
0143 SND_SOC_DAILINK_DEFS(paif_rx,
0144     DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.2")),
0145     DAILINK_COMP_ARRAY(COMP_CODEC("wm8580.0-001b", "wm8580-hifi-playback")),
0146     DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
0147 
0148 SND_SOC_DAILINK_DEFS(paif_tx,
0149     DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.2")),
0150     DAILINK_COMP_ARRAY(COMP_CODEC("wm8580.0-001b", "wm8580-hifi-capture")),
0151     DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0")));
0152 
0153 static struct snd_soc_dai_link smdk_dai[] = {
0154     [PRI_PLAYBACK] = { /* Primary Playback i/f */
0155         .name = "WM8580 PAIF RX",
0156         .stream_name = "Playback",
0157         .dai_fmt = SMDK_DAI_FMT,
0158         .ops = &smdk_ops,
0159         SND_SOC_DAILINK_REG(paif_rx),
0160     },
0161     [PRI_CAPTURE] = { /* Primary Capture i/f */
0162         .name = "WM8580 PAIF TX",
0163         .stream_name = "Capture",
0164         .dai_fmt = SMDK_DAI_FMT,
0165         .init = smdk_wm8580_init_paiftx,
0166         .ops = &smdk_ops,
0167         SND_SOC_DAILINK_REG(paif_tx),
0168     },
0169 };
0170 
0171 static struct snd_soc_card smdk = {
0172     .name = "SMDK-I2S",
0173     .owner = THIS_MODULE,
0174     .dai_link = smdk_dai,
0175     .num_links = ARRAY_SIZE(smdk_dai),
0176 
0177     .dapm_widgets = smdk_wm8580_dapm_widgets,
0178     .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets),
0179     .dapm_routes = smdk_wm8580_audio_map,
0180     .num_dapm_routes = ARRAY_SIZE(smdk_wm8580_audio_map),
0181 };
0182 
0183 static struct platform_device *smdk_snd_device;
0184 
0185 static int __init smdk_audio_init(void)
0186 {
0187     int ret;
0188 
0189     smdk_snd_device = platform_device_alloc("soc-audio", -1);
0190     if (!smdk_snd_device)
0191         return -ENOMEM;
0192 
0193     platform_set_drvdata(smdk_snd_device, &smdk);
0194     ret = platform_device_add(smdk_snd_device);
0195 
0196     if (ret)
0197         platform_device_put(smdk_snd_device);
0198 
0199     return ret;
0200 }
0201 module_init(smdk_audio_init);
0202 
0203 static void __exit smdk_audio_exit(void)
0204 {
0205     platform_device_unregister(smdk_snd_device);
0206 }
0207 module_exit(smdk_audio_exit);
0208 
0209 MODULE_AUTHOR("Jaswinder Singh, jassisinghbrar@gmail.com");
0210 MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
0211 MODULE_LICENSE("GPL");