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 SND_SOC_DAPM_OUTPUT("OUTL-"), 204 SND_SOC_DAPM_OUTPUT("OUTR-"), 205 206 SND_SOC_DAPM_INPUT("INL"), 207 SND_SOC_DAPM_INPUT("INR"), 208 }; 209 210 static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { 211 { "OUTL+", NULL, "Playback" }, 212 { "OUTR+", NULL, "Playback" }, 213 { "OUTL-", NULL, "Playback" }, 214 { "OUTR-", NULL, "Playback" }, 215 216 { "Capture", NULL, "INL" }, 217 { "Capture", NULL, "INR" }, 218 }; 219 220 /* soc component */ 221 222 static const struct snd_soc_component_driver pcm3060_soc_comp_driver = { 223 .controls = pcm3060_dapm_controls, 224 .num_controls = ARRAY_SIZE(pcm3060_dapm_controls), 225 .dapm_widgets = pcm3060_dapm_widgets, 226 .num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets), 227 .dapm_routes = pcm3060_dapm_map, 228 .num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map), 229 }; 230 231 /* regmap */ 232 233 static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg) 234 { 235 return (reg >= PCM3060_REG64); 236 } 237 238 static bool pcm3060_reg_readable(struct device *dev, unsigned int reg) 239 { 240 return (reg >= PCM3060_REG64); 241 } 242 243 static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg) 244 { 245 /* PCM3060_REG64 is volatile */ 246 return (reg == PCM3060_REG64); 247 } 248 249 static const struct reg_default pcm3060_reg_defaults[] = { 250 { PCM3060_REG64, 0xF0 }, 251 { PCM3060_REG65, 0xFF }, 252 { PCM3060_REG66, 0xFF }, 253 { PCM3060_REG67, 0x00 }, 254 { PCM3060_REG68, 0x00 }, 255 { PCM3060_REG69, 0x00 }, 256 { PCM3060_REG70, 0xD7 }, 257 { PCM3060_REG71, 0xD7 }, 258 { PCM3060_REG72, 0x00 }, 259 { PCM3060_REG73, 0x00 }, 260 }; 261 262 const struct regmap_config pcm3060_regmap = { 263 .reg_bits = 8, 264 .val_bits = 8, 265 .writeable_reg = pcm3060_reg_writeable, 266 .readable_reg = pcm3060_reg_readable, 267 .volatile_reg = pcm3060_reg_volatile, 268 .max_register = PCM3060_REG73, 269 .reg_defaults = pcm3060_reg_defaults, 270 .num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults), 271 .cache_type = REGCACHE_RBTREE, 272 }; 273 EXPORT_SYMBOL(pcm3060_regmap); 274 275 /* device */ 276 277 int pcm3060_probe(struct device *dev) 278 { 279 int rc; 280 281 rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, 282 pcm3060_dai, 283 ARRAY_SIZE(pcm3060_dai)); 284 if (rc) { 285 dev_err(dev, "failed to register component, rc=%d\n", rc); 286 return rc; 287 } 288 289 return 0; 290 } 291 EXPORT_SYMBOL(pcm3060_probe); 292 293 MODULE_DESCRIPTION("PCM3060 codec driver"); 294 MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.tech>"); 295 MODULE_LICENSE("GPL v2"); 296