Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) ST-Ericsson SA 2012
0004  *
0005  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
0006  *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
0007  *         for ST-Ericsson.
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/device.h>
0012 #include <linux/io.h>
0013 #include <linux/clk.h>
0014 #include <linux/mutex.h>
0015 
0016 #include <sound/soc.h>
0017 #include <sound/soc-dapm.h>
0018 #include <sound/pcm.h>
0019 #include <sound/pcm_params.h>
0020 
0021 #include "ux500_pcm.h"
0022 #include "ux500_msp_dai.h"
0023 #include "mop500_ab8500.h"
0024 #include "../codecs/ab8500-codec.h"
0025 
0026 #define TX_SLOT_MONO    0x0008
0027 #define TX_SLOT_STEREO  0x000a
0028 #define RX_SLOT_MONO    0x0001
0029 #define RX_SLOT_STEREO  0x0003
0030 #define TX_SLOT_8CH 0x00FF
0031 #define RX_SLOT_8CH 0x00FF
0032 
0033 #define DEF_TX_SLOTS    TX_SLOT_STEREO
0034 #define DEF_RX_SLOTS    RX_SLOT_MONO
0035 
0036 #define DRIVERMODE_NORMAL   0
0037 #define DRIVERMODE_CODEC_ONLY   1
0038 
0039 /* Slot configuration */
0040 static unsigned int tx_slots = DEF_TX_SLOTS;
0041 static unsigned int rx_slots = DEF_RX_SLOTS;
0042 
0043 /* Configuration consistency parameters */
0044 static DEFINE_MUTEX(mop500_ab8500_params_lock);
0045 static unsigned long mop500_ab8500_usage;
0046 static int mop500_ab8500_rate;
0047 static int mop500_ab8500_channels;
0048 
0049 /* Clocks */
0050 static const char * const enum_mclk[] = {
0051     "SYSCLK",
0052     "ULPCLK"
0053 };
0054 enum mclk {
0055     MCLK_SYSCLK,
0056     MCLK_ULPCLK,
0057 };
0058 
0059 static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk);
0060 
0061 /* Private data for machine-part MOP500<->AB8500 */
0062 struct mop500_ab8500_drvdata {
0063     /* Clocks */
0064     enum mclk mclk_sel;
0065     struct clk *clk_ptr_intclk;
0066     struct clk *clk_ptr_sysclk;
0067     struct clk *clk_ptr_ulpclk;
0068 };
0069 
0070 static inline const char *get_mclk_str(enum mclk mclk_sel)
0071 {
0072     switch (mclk_sel) {
0073     case MCLK_SYSCLK:
0074         return "SYSCLK";
0075     case MCLK_ULPCLK:
0076         return "ULPCLK";
0077     default:
0078         return "Unknown";
0079     }
0080 }
0081 
0082 static int mop500_ab8500_set_mclk(struct device *dev,
0083                 struct mop500_ab8500_drvdata *drvdata)
0084 {
0085     int status;
0086     struct clk *clk_ptr;
0087 
0088     if (IS_ERR(drvdata->clk_ptr_intclk)) {
0089         dev_err(dev,
0090             "%s: ERROR: intclk not initialized!\n", __func__);
0091         return -EIO;
0092     }
0093 
0094     switch (drvdata->mclk_sel) {
0095     case MCLK_SYSCLK:
0096         clk_ptr = drvdata->clk_ptr_sysclk;
0097         break;
0098     case MCLK_ULPCLK:
0099         clk_ptr = drvdata->clk_ptr_ulpclk;
0100         break;
0101     default:
0102         return -EINVAL;
0103     }
0104 
0105     if (IS_ERR(clk_ptr)) {
0106         dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__,
0107             get_mclk_str(drvdata->mclk_sel));
0108         return -EIO;
0109     }
0110 
0111     status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr);
0112     if (status)
0113         dev_err(dev,
0114             "%s: ERROR: Setting intclk parent to %s failed (ret = %d)!",
0115             __func__, get_mclk_str(drvdata->mclk_sel), status);
0116     else
0117         dev_dbg(dev,
0118             "%s: intclk parent changed to %s.\n",
0119             __func__, get_mclk_str(drvdata->mclk_sel));
0120 
0121     return status;
0122 }
0123 
0124 /*
0125  * Control-events
0126  */
0127 
0128 static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
0129                 struct snd_ctl_elem_value *ucontrol)
0130 {
0131     struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0132     struct mop500_ab8500_drvdata *drvdata =
0133                 snd_soc_card_get_drvdata(card);
0134 
0135     ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
0136 
0137     return 0;
0138 }
0139 
0140 static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
0141                 struct snd_ctl_elem_value *ucontrol)
0142 {
0143     struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0144     struct mop500_ab8500_drvdata *drvdata =
0145                 snd_soc_card_get_drvdata(card);
0146     unsigned int val = ucontrol->value.enumerated.item[0];
0147 
0148     if (val > (unsigned int)MCLK_ULPCLK)
0149         return -EINVAL;
0150     if (drvdata->mclk_sel == val)
0151         return 0;
0152 
0153     drvdata->mclk_sel = val;
0154 
0155     return 1;
0156 }
0157 
0158 /*
0159  * Controls
0160  */
0161 
0162 static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
0163     SOC_ENUM_EXT("Master Clock Select",
0164         soc_enum_mclk,
0165         mclk_input_control_get, mclk_input_control_put),
0166     SOC_DAPM_PIN_SWITCH("Headset Left"),
0167     SOC_DAPM_PIN_SWITCH("Headset Right"),
0168     SOC_DAPM_PIN_SWITCH("Earpiece"),
0169     SOC_DAPM_PIN_SWITCH("Speaker Left"),
0170     SOC_DAPM_PIN_SWITCH("Speaker Right"),
0171     SOC_DAPM_PIN_SWITCH("LineOut Left"),
0172     SOC_DAPM_PIN_SWITCH("LineOut Right"),
0173     SOC_DAPM_PIN_SWITCH("Vibra 1"),
0174     SOC_DAPM_PIN_SWITCH("Vibra 2"),
0175     SOC_DAPM_PIN_SWITCH("Mic 1"),
0176     SOC_DAPM_PIN_SWITCH("Mic 2"),
0177     SOC_DAPM_PIN_SWITCH("LineIn Left"),
0178     SOC_DAPM_PIN_SWITCH("LineIn Right"),
0179     SOC_DAPM_PIN_SWITCH("DMic 1"),
0180     SOC_DAPM_PIN_SWITCH("DMic 2"),
0181     SOC_DAPM_PIN_SWITCH("DMic 3"),
0182     SOC_DAPM_PIN_SWITCH("DMic 4"),
0183     SOC_DAPM_PIN_SWITCH("DMic 5"),
0184     SOC_DAPM_PIN_SWITCH("DMic 6"),
0185 };
0186 
0187 /* ASoC */
0188 
0189 static int mop500_ab8500_startup(struct snd_pcm_substream *substream)
0190 {
0191     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0192 
0193     /* Set audio-clock source */
0194     return mop500_ab8500_set_mclk(rtd->card->dev,
0195                 snd_soc_card_get_drvdata(rtd->card));
0196 }
0197 
0198 static void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
0199 {
0200     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0201     struct device *dev = rtd->card->dev;
0202 
0203     dev_dbg(dev, "%s: Enter\n", __func__);
0204 
0205     /* Reset slots configuration to default(s) */
0206     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0207         tx_slots = DEF_TX_SLOTS;
0208     else
0209         rx_slots = DEF_RX_SLOTS;
0210 }
0211 
0212 static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
0213             struct snd_pcm_hw_params *params)
0214 {
0215     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0216     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0217     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0218     struct device *dev = rtd->card->dev;
0219     unsigned int fmt;
0220     int channels, ret = 0, driver_mode, slots;
0221     unsigned int sw_codec, sw_cpu;
0222     bool is_playback;
0223 
0224     dev_dbg(dev, "%s: Enter\n", __func__);
0225 
0226     dev_dbg(dev, "%s: substream->pcm->name = %s\n"
0227         "substream->pcm->id = %s.\n"
0228         "substream->name = %s.\n"
0229         "substream->number = %d.\n",
0230         __func__,
0231         substream->pcm->name,
0232         substream->pcm->id,
0233         substream->name,
0234         substream->number);
0235 
0236     /* Ensure configuration consistency between DAIs */
0237     mutex_lock(&mop500_ab8500_params_lock);
0238     if (mop500_ab8500_usage) {
0239         if (mop500_ab8500_rate != params_rate(params) ||
0240             mop500_ab8500_channels != params_channels(params)) {
0241             mutex_unlock(&mop500_ab8500_params_lock);
0242             return -EBUSY;
0243         }
0244     } else {
0245         mop500_ab8500_rate = params_rate(params);
0246         mop500_ab8500_channels = params_channels(params);
0247     }
0248     __set_bit(cpu_dai->id, &mop500_ab8500_usage);
0249     mutex_unlock(&mop500_ab8500_params_lock);
0250 
0251     channels = params_channels(params);
0252 
0253     switch (params_format(params)) {
0254     case SNDRV_PCM_FORMAT_S32_LE:
0255         sw_cpu = 32;
0256         break;
0257 
0258     case SNDRV_PCM_FORMAT_S16_LE:
0259         sw_cpu = 16;
0260         break;
0261 
0262     default:
0263         return -EINVAL;
0264     }
0265 
0266     /* Setup codec depending on driver-mode */
0267     if (channels == 8)
0268         driver_mode = DRIVERMODE_CODEC_ONLY;
0269     else
0270         driver_mode = DRIVERMODE_NORMAL;
0271     dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__,
0272         (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");
0273 
0274     /* Setup format */
0275 
0276     if (driver_mode == DRIVERMODE_NORMAL) {
0277         fmt = SND_SOC_DAIFMT_DSP_A |
0278             SND_SOC_DAIFMT_CBM_CFM |
0279             SND_SOC_DAIFMT_NB_NF |
0280             SND_SOC_DAIFMT_CONT;
0281     } else {
0282         fmt = SND_SOC_DAIFMT_DSP_A |
0283             SND_SOC_DAIFMT_CBM_CFM |
0284             SND_SOC_DAIFMT_NB_NF |
0285             SND_SOC_DAIFMT_GATED;
0286     }
0287 
0288     ret = snd_soc_runtime_set_dai_fmt(rtd, fmt);
0289     if (ret)
0290         return ret;
0291 
0292     /* Setup TDM-slots */
0293 
0294     is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
0295     switch (channels) {
0296     case 1:
0297         slots = 16;
0298         tx_slots = (is_playback) ? TX_SLOT_MONO : 0;
0299         rx_slots = (is_playback) ? 0 : RX_SLOT_MONO;
0300         break;
0301     case 2:
0302         slots = 16;
0303         tx_slots = (is_playback) ? TX_SLOT_STEREO : 0;
0304         rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO;
0305         break;
0306     case 8:
0307         slots = 16;
0308         tx_slots = (is_playback) ? TX_SLOT_8CH : 0;
0309         rx_slots = (is_playback) ? 0 : RX_SLOT_8CH;
0310         break;
0311     default:
0312         return -EINVAL;
0313     }
0314 
0315     if (driver_mode == DRIVERMODE_NORMAL)
0316         sw_codec = sw_cpu;
0317     else
0318         sw_codec = 20;
0319 
0320     dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
0321         tx_slots, rx_slots);
0322     ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots,
0323                 sw_cpu);
0324     if (ret)
0325         return ret;
0326 
0327     dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__,
0328         tx_slots, rx_slots);
0329     ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots,
0330                 sw_codec);
0331     if (ret)
0332         return ret;
0333 
0334     return 0;
0335 }
0336 
0337 static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream)
0338 {
0339     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0340     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0341 
0342     mutex_lock(&mop500_ab8500_params_lock);
0343     __clear_bit(cpu_dai->id, &mop500_ab8500_usage);
0344     mutex_unlock(&mop500_ab8500_params_lock);
0345 
0346     return 0;
0347 }
0348 
0349 const struct snd_soc_ops mop500_ab8500_ops[] = {
0350     {
0351         .hw_params = mop500_ab8500_hw_params,
0352         .hw_free = mop500_ab8500_hw_free,
0353         .startup = mop500_ab8500_startup,
0354         .shutdown = mop500_ab8500_shutdown,
0355     }
0356 };
0357 
0358 int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
0359 {
0360     struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
0361     struct device *dev = rtd->card->dev;
0362     struct mop500_ab8500_drvdata *drvdata;
0363     int ret;
0364 
0365     dev_dbg(dev, "%s Enter.\n", __func__);
0366 
0367     /* Create driver private-data struct */
0368     drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata),
0369             GFP_KERNEL);
0370 
0371     if (!drvdata)
0372         return -ENOMEM;
0373 
0374     snd_soc_card_set_drvdata(rtd->card, drvdata);
0375 
0376     /* Setup clocks */
0377 
0378     drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk");
0379     if (IS_ERR(drvdata->clk_ptr_sysclk))
0380         dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n",
0381             __func__);
0382     drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk");
0383     if (IS_ERR(drvdata->clk_ptr_ulpclk))
0384         dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n",
0385             __func__);
0386     drvdata->clk_ptr_intclk = clk_get(dev, "intclk");
0387     if (IS_ERR(drvdata->clk_ptr_intclk))
0388         dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n",
0389             __func__);
0390 
0391     /* Set intclk default parent to ulpclk */
0392     drvdata->mclk_sel = MCLK_ULPCLK;
0393     ret = mop500_ab8500_set_mclk(dev, drvdata);
0394     if (ret < 0)
0395         dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n",
0396             __func__);
0397 
0398     drvdata->mclk_sel = MCLK_ULPCLK;
0399 
0400     /* Add controls */
0401     ret = snd_soc_add_card_controls(rtd->card, mop500_ab8500_ctrls,
0402             ARRAY_SIZE(mop500_ab8500_ctrls));
0403     if (ret < 0) {
0404         pr_err("%s: Failed to add machine-controls (%d)!\n",
0405                 __func__, ret);
0406         return ret;
0407     }
0408 
0409     ret = snd_soc_dapm_disable_pin(dapm, "Earpiece");
0410     ret |= snd_soc_dapm_disable_pin(dapm, "Speaker Left");
0411     ret |= snd_soc_dapm_disable_pin(dapm, "Speaker Right");
0412     ret |= snd_soc_dapm_disable_pin(dapm, "LineOut Left");
0413     ret |= snd_soc_dapm_disable_pin(dapm, "LineOut Right");
0414     ret |= snd_soc_dapm_disable_pin(dapm, "Vibra 1");
0415     ret |= snd_soc_dapm_disable_pin(dapm, "Vibra 2");
0416     ret |= snd_soc_dapm_disable_pin(dapm, "Mic 1");
0417     ret |= snd_soc_dapm_disable_pin(dapm, "Mic 2");
0418     ret |= snd_soc_dapm_disable_pin(dapm, "LineIn Left");
0419     ret |= snd_soc_dapm_disable_pin(dapm, "LineIn Right");
0420     ret |= snd_soc_dapm_disable_pin(dapm, "DMic 1");
0421     ret |= snd_soc_dapm_disable_pin(dapm, "DMic 2");
0422     ret |= snd_soc_dapm_disable_pin(dapm, "DMic 3");
0423     ret |= snd_soc_dapm_disable_pin(dapm, "DMic 4");
0424     ret |= snd_soc_dapm_disable_pin(dapm, "DMic 5");
0425     ret |= snd_soc_dapm_disable_pin(dapm, "DMic 6");
0426 
0427     return ret;
0428 }
0429 
0430 void mop500_ab8500_remove(struct snd_soc_card *card)
0431 {
0432     struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card);
0433 
0434     clk_put(drvdata->clk_ptr_sysclk);
0435     clk_put(drvdata->clk_ptr_ulpclk);
0436     clk_put(drvdata->clk_ptr_intclk);
0437 
0438     snd_soc_card_set_drvdata(card, drvdata);
0439 }