1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // PCM3060 codec driver 4 // 5 // Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.tech> 6 7 #include <linux/module.h> 8 #include <sound/pcm_params.h> 9 #include <sound/soc.h> 10 #include <sound/tlv.h> 11 12 #include "pcm3060.h" 13 14 /* dai */ 15 16 static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id, 17 unsigned int freq, int dir) 18 { 19 struct snd_soc_component *comp = dai->component; 20 struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); 21 22 if (dir != SND_SOC_CLOCK_IN) { 23 dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir); 24 return -EINVAL; 25 } 26 27 priv->dai[dai->id].sclk_freq = freq; 28 29 return 0; 30 } 31 32 static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 33 { 34 struct snd_soc_component *comp = dai->component; 35 struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); 36 unsigned int reg; 37 unsigned int val; 38 39 if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { 40 dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt); 41 return -EINVAL; 42 } 43 44 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 45 case SND_SOC_DAIFMT_CBM_CFM: 46 priv->dai[dai->id].is_master = true; 47 break; 48 case SND_SOC_DAIFMT_CBS_CFS: 49 priv->dai[dai->id].is_master = false; 50 break; 51 default: 52 dev_err(comp->dev, "unsupported DAI master mode: 0x%x\n", fmt); 53 return -EINVAL; 54 } 55 56 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 57 case SND_SOC_DAIFMT_I2S: 58 val = PCM3060_REG_FMT_I2S; 59 break; 60 case SND_SOC_DAIFMT_RIGHT_J: 61 val = PCM3060_REG_FMT_RJ; 62 break; 63 case SND_SOC_DAIFMT_LEFT_J: 64 val = PCM3060_REG_FMT_LJ; 65 break; 66 default: 67 dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt); 68 return -EINVAL; 69 } 70 71 if (dai->id == PCM3060_DAI_ID_DAC) 72 reg = PCM3060_REG67; 73 else 74 reg = PCM3060_REG72; 75 76 regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val); 77 78 return 0; 79 } 80 81 static int pcm3060_hw_params(struct snd_pcm_substream *substream, 82 struct snd_pcm_hw_params *params, 83 struct snd_soc_dai *dai) 84 { 85 struct snd_soc_component *comp = dai->component; 86 struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); 87 unsigned int rate; 88 unsigned int ratio; 89 unsigned int reg; 90 unsigned int val; 91 92 if (!priv->dai[dai->id].is_master) { 93 val = PCM3060_REG_MS_S; 94 goto val_ready; 95 } 96 97 rate = params_rate(params); 98 if (!rate) { 99 dev_err(comp->dev, "rate is not configured\n"); 100 return -EINVAL; 101 } 102 103 ratio = priv->dai[dai->id].sclk_freq / rate; 104 105 switch (ratio) { 106 case 768: 107 val = PCM3060_REG_MS_M768; 108 break; 109 case 512: 110 val = PCM3060_REG_MS_M512; 111 break; 112 case 384: 113 val = PCM3060_REG_MS_M384; 114 break; 115 case 256: 116 val = PCM3060_REG_MS_M256; 117 break; 118 case 192: 119 val = PCM3060_REG_MS_M192; 120 break; 121 case 128: 122 val = PCM3060_REG_MS_M128; 123 break; 124 default: 125 dev_err(comp->dev, "unsupported ratio: %d\n", ratio); 126 return -EINVAL; 127 } 128 129 val_ready: 130 if (dai->id == PCM3060_DAI_ID_DAC) 131 reg = PCM3060_REG67; 132 else 133 reg = PCM3060_REG72; 134 135 regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val); 136 137 return 0; 138 } 139 140 static const struct snd_soc_dai_ops pcm3060_dai_ops = { 141 .set_sysclk = pcm3060_set_sysclk, 142 .set_fmt = pcm3060_set_fmt, 143 .hw_params = pcm3060_hw_params, 144 }; 145 146 #define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \ 147 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ 148 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 149 150 #define PCM3060_DAI_RATES_DAC (PCM3060_DAI_RATES_ADC | \ 151 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) 152 153 static struct snd_soc_dai_driver pcm3060_dai[] = { 154 { 155 .name = "pcm3060-dac", 156 .id = PCM3060_DAI_ID_DAC, 157 .playback = { 158 .stream_name = "Playback", 159 .channels_min = 2, 160 .channels_max = 2, 161 .rates = PCM3060_DAI_RATES_DAC, 162 .formats = SNDRV_PCM_FMTBIT_S24_LE, 163 }, 164 .ops = &pcm3060_dai_ops, 165 }, 166 { 167 .name = "pcm3060-adc", 168 .id = PCM3060_DAI_ID_ADC, 169 .capture = { 170 .stream_name = "Capture", 171 .channels_min = 2, 172 .channels_max = 2, 173 .rates = PCM3060_DAI_RATES_ADC, 174 .formats = SNDRV_PCM_FMTBIT_S24_LE, 175 }, 176 .ops = &pcm3060_dai_ops, 177 }, 178 }; 179 180 /* dapm */ 181 182 static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1); 183 184 static const struct snd_kcontrol_new pcm3060_dapm_controls[] = { 185 SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume", 186 PCM3060_REG65, PCM3060_REG66, 0, 187 PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX, 188 0, pcm3060_dapm_tlv), 189 SOC_DOUBLE("Master Playback Switch", PCM3060_REG68, 190 PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1), 191 192 SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume", 193 PCM3060_REG70, PCM3060_REG71, 0, 194 PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX, 195 0, pcm3060_dapm_tlv), 196 SOC_DOUBLE("Master Capture Switch", PCM3060_REG73, 197 PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1), 198 }; 199 200 static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = { 201 SND_SOC_DAPM_OUTPUT("OUTL"), 202 SND_SOC_DAPM_OUTPUT("OUTR"), 203 204 SND_SOC_DAPM_INPUT("INL"), 205 SND_SOC_DAPM_INPUT("INR"), 206 }; 207 208 static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { 209 { "OUTL", NULL, "Playback" }, 210 { "OUTR", NULL, "Playback" }, 211 212 { "Capture", NULL, "INL" }, 213 { "Capture", NULL, "INR" }, 214 }; 215 216 /* soc component */ 217 218 static const struct snd_soc_component_driver pcm3060_soc_comp_driver = { 219 .controls = pcm3060_dapm_controls, 220 .num_controls = ARRAY_SIZE(pcm3060_dapm_controls), 221 .dapm_widgets = pcm3060_dapm_widgets, 222 .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets), 223 .dapm_routes = pcm3060_dapm_map, 224 .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map), 225 }; 226 227 /* regmap */ 228 229 static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg) 230 { 231 return (reg >= PCM3060_REG64); 232 } 233 234 static bool pcm3060_reg_readable(struct device *dev, unsigned int reg) 235 { 236 return (reg >= PCM3060_REG64); 237 } 238 239 static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg) 240 { 241 /* PCM3060_REG64 is volatile */ 242 return (reg == PCM3060_REG64); 243 } 244 245 static const struct reg_default pcm3060_reg_defaults[] = { 246 { PCM3060_REG64, 0xF0 }, 247 { PCM3060_REG65, 0xFF }, 248 { PCM3060_REG66, 0xFF }, 249 { PCM3060_REG67, 0x00 }, 250 { PCM3060_REG68, 0x00 }, 251 { PCM3060_REG69, 0x00 }, 252 { PCM3060_REG70, 0xD7 }, 253 { PCM3060_REG71, 0xD7 }, 254 { PCM3060_REG72, 0x00 }, 255 { PCM3060_REG73, 0x00 }, 256 }; 257 258 const struct regmap_config pcm3060_regmap = { 259 .reg_bits = 8, 260 .val_bits = 8, 261 .writeable_reg = pcm3060_reg_writeable, 262 .readable_reg = pcm3060_reg_readable, 263 .volatile_reg = pcm3060_reg_volatile, 264 .max_register = PCM3060_REG73, 265 .reg_defaults = pcm3060_reg_defaults, 266 .num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults), 267 .cache_type = REGCACHE_RBTREE, 268 }; 269 EXPORT_SYMBOL(pcm3060_regmap); 270 271 /* device */ 272 273 int pcm3060_probe(struct device *dev) 274 { 275 int rc; 276 277 rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, 278 pcm3060_dai, 279 ARRAY_SIZE(pcm3060_dai)); 280 if (rc) { 281 dev_err(dev, "failed to register component, rc=%d\n", rc); 282 return rc; 283 } 284 285 return 0; 286 } 287 EXPORT_SYMBOL(pcm3060_probe); 288 289 MODULE_DESCRIPTION("PCM3060 codec driver"); 290 MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>"); 291 MODULE_LICENSE("GPL v2"); 292