Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // PCM3060 codec driver
0004 //
0005 // Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
0006 
0007 #include <linux/module.h>
0008 #include <sound/pcm_params.h>
0009 #include <sound/soc.h>
0010 #include <sound/tlv.h>
0011 
0012 #include "pcm3060.h"
0013 
0014 /* dai */
0015 
0016 static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id,
0017                   unsigned int freq, int dir)
0018 {
0019     struct snd_soc_component *comp = dai->component;
0020     struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
0021     unsigned int reg;
0022     unsigned int val;
0023 
0024     if (dir != SND_SOC_CLOCK_IN) {
0025         dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir);
0026         return -EINVAL;
0027     }
0028 
0029     switch (clk_id) {
0030     case PCM3060_CLK_DEF:
0031         val = 0;
0032         break;
0033 
0034     case PCM3060_CLK1:
0035         val = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG_CSEL : 0);
0036         break;
0037 
0038     case PCM3060_CLK2:
0039         val = (dai->id == PCM3060_DAI_ID_DAC ? 0 : PCM3060_REG_CSEL);
0040         break;
0041 
0042     default:
0043         dev_err(comp->dev, "unsupported sysclock id: %d\n", clk_id);
0044         return -EINVAL;
0045     }
0046 
0047     if (dai->id == PCM3060_DAI_ID_DAC)
0048         reg = PCM3060_REG67;
0049     else
0050         reg = PCM3060_REG72;
0051 
0052     regmap_update_bits(priv->regmap, reg, PCM3060_REG_CSEL, val);
0053 
0054     priv->dai[dai->id].sclk_freq = freq;
0055 
0056     return 0;
0057 }
0058 
0059 static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0060 {
0061     struct snd_soc_component *comp = dai->component;
0062     struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
0063     unsigned int reg;
0064     unsigned int val;
0065 
0066     if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
0067         dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt);
0068         return -EINVAL;
0069     }
0070 
0071     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0072     case SND_SOC_DAIFMT_CBP_CFP:
0073         priv->dai[dai->id].is_provider = true;
0074         break;
0075     case SND_SOC_DAIFMT_CBC_CFC:
0076         priv->dai[dai->id].is_provider = false;
0077         break;
0078     default:
0079         dev_err(comp->dev, "unsupported DAI mode: 0x%x\n", fmt);
0080         return -EINVAL;
0081     }
0082 
0083     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0084     case SND_SOC_DAIFMT_I2S:
0085         val = PCM3060_REG_FMT_I2S;
0086         break;
0087     case SND_SOC_DAIFMT_RIGHT_J:
0088         val = PCM3060_REG_FMT_RJ;
0089         break;
0090     case SND_SOC_DAIFMT_LEFT_J:
0091         val = PCM3060_REG_FMT_LJ;
0092         break;
0093     default:
0094         dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt);
0095         return -EINVAL;
0096     }
0097 
0098     if (dai->id == PCM3060_DAI_ID_DAC)
0099         reg = PCM3060_REG67;
0100     else
0101         reg = PCM3060_REG72;
0102 
0103     regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val);
0104 
0105     return 0;
0106 }
0107 
0108 static int pcm3060_hw_params(struct snd_pcm_substream *substream,
0109                  struct snd_pcm_hw_params *params,
0110                  struct snd_soc_dai *dai)
0111 {
0112     struct snd_soc_component *comp = dai->component;
0113     struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
0114     unsigned int rate;
0115     unsigned int ratio;
0116     unsigned int reg;
0117     unsigned int val;
0118 
0119     if (!priv->dai[dai->id].is_provider) {
0120         val = PCM3060_REG_MS_S;
0121         goto val_ready;
0122     }
0123 
0124     rate = params_rate(params);
0125     if (!rate) {
0126         dev_err(comp->dev, "rate is not configured\n");
0127         return -EINVAL;
0128     }
0129 
0130     ratio = priv->dai[dai->id].sclk_freq / rate;
0131 
0132     switch (ratio) {
0133     case 768:
0134         val = PCM3060_REG_MS_M768;
0135         break;
0136     case 512:
0137         val = PCM3060_REG_MS_M512;
0138         break;
0139     case 384:
0140         val = PCM3060_REG_MS_M384;
0141         break;
0142     case 256:
0143         val = PCM3060_REG_MS_M256;
0144         break;
0145     case 192:
0146         val = PCM3060_REG_MS_M192;
0147         break;
0148     case 128:
0149         val = PCM3060_REG_MS_M128;
0150         break;
0151     default:
0152         dev_err(comp->dev, "unsupported ratio: %d\n", ratio);
0153         return -EINVAL;
0154     }
0155 
0156 val_ready:
0157     if (dai->id == PCM3060_DAI_ID_DAC)
0158         reg = PCM3060_REG67;
0159     else
0160         reg = PCM3060_REG72;
0161 
0162     regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val);
0163 
0164     return 0;
0165 }
0166 
0167 static const struct snd_soc_dai_ops pcm3060_dai_ops = {
0168     .set_sysclk = pcm3060_set_sysclk,
0169     .set_fmt = pcm3060_set_fmt,
0170     .hw_params = pcm3060_hw_params,
0171 };
0172 
0173 #define PCM3060_DAI_RATES_ADC   (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
0174                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
0175                  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
0176 
0177 #define PCM3060_DAI_RATES_DAC   (PCM3060_DAI_RATES_ADC | \
0178                  SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
0179 
0180 static struct snd_soc_dai_driver pcm3060_dai[] = {
0181     {
0182         .name = "pcm3060-dac",
0183         .id = PCM3060_DAI_ID_DAC,
0184         .playback = {
0185             .stream_name = "Playback",
0186             .channels_min = 2,
0187             .channels_max = 2,
0188             .rates = PCM3060_DAI_RATES_DAC,
0189             .formats = SNDRV_PCM_FMTBIT_S24_LE,
0190         },
0191         .ops = &pcm3060_dai_ops,
0192     },
0193     {
0194         .name = "pcm3060-adc",
0195         .id = PCM3060_DAI_ID_ADC,
0196         .capture = {
0197             .stream_name = "Capture",
0198             .channels_min = 2,
0199             .channels_max = 2,
0200             .rates = PCM3060_DAI_RATES_ADC,
0201             .formats = SNDRV_PCM_FMTBIT_S24_LE,
0202         },
0203         .ops = &pcm3060_dai_ops,
0204     },
0205 };
0206 
0207 /* dapm */
0208 
0209 static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1);
0210 
0211 static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
0212     SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume",
0213                    PCM3060_REG65, PCM3060_REG66, 0,
0214                    PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX,
0215                    0, pcm3060_dapm_tlv),
0216     SOC_DOUBLE("Master Playback Switch", PCM3060_REG68,
0217            PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1),
0218 
0219     SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume",
0220                    PCM3060_REG70, PCM3060_REG71, 0,
0221                    PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX,
0222                    0, pcm3060_dapm_tlv),
0223     SOC_DOUBLE("Master Capture Switch", PCM3060_REG73,
0224            PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1),
0225 };
0226 
0227 static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
0228     SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
0229              PCM3060_REG_SHIFT_DAPSV, 1),
0230 
0231     SND_SOC_DAPM_OUTPUT("OUTL"),
0232     SND_SOC_DAPM_OUTPUT("OUTR"),
0233 
0234     SND_SOC_DAPM_INPUT("INL"),
0235     SND_SOC_DAPM_INPUT("INR"),
0236 
0237     SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
0238              PCM3060_REG_SHIFT_ADPSV, 1),
0239 };
0240 
0241 static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
0242     { "OUTL", NULL, "DAC" },
0243     { "OUTR", NULL, "DAC" },
0244 
0245     { "ADC", NULL, "INL" },
0246     { "ADC", NULL, "INR" },
0247 };
0248 
0249 /* soc component */
0250 
0251 static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {
0252     .controls = pcm3060_dapm_controls,
0253     .num_controls = ARRAY_SIZE(pcm3060_dapm_controls),
0254     .dapm_widgets = pcm3060_dapm_widgets,
0255     .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),
0256     .dapm_routes = pcm3060_dapm_map,
0257     .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),
0258     .endianness = 1,
0259 };
0260 
0261 /* regmap */
0262 
0263 static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg)
0264 {
0265     return (reg >= PCM3060_REG64);
0266 }
0267 
0268 static bool pcm3060_reg_readable(struct device *dev, unsigned int reg)
0269 {
0270     return (reg >= PCM3060_REG64);
0271 }
0272 
0273 static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg)
0274 {
0275     /* PCM3060_REG64 is volatile */
0276     return (reg == PCM3060_REG64);
0277 }
0278 
0279 static const struct reg_default pcm3060_reg_defaults[] = {
0280     { PCM3060_REG64,  0xF0 },
0281     { PCM3060_REG65,  0xFF },
0282     { PCM3060_REG66,  0xFF },
0283     { PCM3060_REG67,  0x00 },
0284     { PCM3060_REG68,  0x00 },
0285     { PCM3060_REG69,  0x00 },
0286     { PCM3060_REG70,  0xD7 },
0287     { PCM3060_REG71,  0xD7 },
0288     { PCM3060_REG72,  0x00 },
0289     { PCM3060_REG73,  0x00 },
0290 };
0291 
0292 const struct regmap_config pcm3060_regmap = {
0293     .reg_bits = 8,
0294     .val_bits = 8,
0295     .writeable_reg = pcm3060_reg_writeable,
0296     .readable_reg = pcm3060_reg_readable,
0297     .volatile_reg = pcm3060_reg_volatile,
0298     .max_register = PCM3060_REG73,
0299     .reg_defaults = pcm3060_reg_defaults,
0300     .num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults),
0301     .cache_type = REGCACHE_RBTREE,
0302 };
0303 EXPORT_SYMBOL(pcm3060_regmap);
0304 
0305 /* device */
0306 
0307 static void pcm3060_parse_dt(const struct device_node *np,
0308                  struct pcm3060_priv *priv)
0309 {
0310     priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
0311 }
0312 
0313 int pcm3060_probe(struct device *dev)
0314 {
0315     int rc;
0316     struct pcm3060_priv *priv = dev_get_drvdata(dev);
0317 
0318     /* soft reset */
0319     rc = regmap_update_bits(priv->regmap, PCM3060_REG64,
0320                 PCM3060_REG_MRST, 0);
0321     if (rc) {
0322         dev_err(dev, "failed to reset component, rc=%d\n", rc);
0323         return rc;
0324     }
0325 
0326     if (dev->of_node)
0327         pcm3060_parse_dt(dev->of_node, priv);
0328 
0329     if (priv->out_se)
0330         regmap_update_bits(priv->regmap, PCM3060_REG64,
0331                    PCM3060_REG_SE, PCM3060_REG_SE);
0332 
0333     rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
0334                          pcm3060_dai,
0335                          ARRAY_SIZE(pcm3060_dai));
0336     if (rc) {
0337         dev_err(dev, "failed to register component, rc=%d\n", rc);
0338         return rc;
0339     }
0340 
0341     return 0;
0342 }
0343 EXPORT_SYMBOL(pcm3060_probe);
0344 
0345 MODULE_DESCRIPTION("PCM3060 codec driver");
0346 MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
0347 MODULE_LICENSE("GPL v2");