0001
0002
0003
0004
0005
0006
0007 #include <linux/of_platform.h>
0008 #include <linux/module.h>
0009 #include <sound/soc.h>
0010
0011
0012
0013
0014
0015 struct es7134_clock_mode {
0016 unsigned int rate_min;
0017 unsigned int rate_max;
0018 unsigned int *mclk_fs;
0019 unsigned int mclk_fs_num;
0020 };
0021
0022 struct es7134_chip {
0023 struct snd_soc_dai_driver *dai_drv;
0024 const struct es7134_clock_mode *modes;
0025 unsigned int mode_num;
0026 const struct snd_soc_dapm_widget *extra_widgets;
0027 unsigned int extra_widget_num;
0028 const struct snd_soc_dapm_route *extra_routes;
0029 unsigned int extra_route_num;
0030 };
0031
0032 struct es7134_data {
0033 unsigned int mclk;
0034 const struct es7134_chip *chip;
0035 };
0036
0037 static int es7134_check_mclk(struct snd_soc_dai *dai,
0038 struct es7134_data *priv,
0039 unsigned int rate)
0040 {
0041 unsigned int mfs = priv->mclk / rate;
0042 int i, j;
0043
0044 for (i = 0; i < priv->chip->mode_num; i++) {
0045 const struct es7134_clock_mode *mode = &priv->chip->modes[i];
0046
0047 if (rate < mode->rate_min || rate > mode->rate_max)
0048 continue;
0049
0050 for (j = 0; j < mode->mclk_fs_num; j++) {
0051 if (mode->mclk_fs[j] == mfs)
0052 return 0;
0053 }
0054
0055 dev_err(dai->dev, "unsupported mclk_fs %u for rate %u\n",
0056 mfs, rate);
0057 return -EINVAL;
0058 }
0059
0060
0061 dev_err(dai->dev, "unsupported rate: %u\n", rate);
0062 return -EINVAL;
0063 }
0064
0065 static int es7134_hw_params(struct snd_pcm_substream *substream,
0066 struct snd_pcm_hw_params *params,
0067 struct snd_soc_dai *dai)
0068 {
0069 struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
0070
0071
0072 if (!priv->mclk)
0073 return 0;
0074
0075 return es7134_check_mclk(dai, priv, params_rate(params));
0076 }
0077
0078 static int es7134_set_sysclk(struct snd_soc_dai *dai, int clk_id,
0079 unsigned int freq, int dir)
0080 {
0081 struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
0082
0083 if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
0084 priv->mclk = freq;
0085 return 0;
0086 }
0087
0088 return -ENOTSUPP;
0089 }
0090
0091 static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
0092 {
0093 fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
0094 SND_SOC_DAIFMT_MASTER_MASK);
0095
0096 if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0097 SND_SOC_DAIFMT_CBC_CFC)) {
0098 dev_err(codec_dai->dev, "Invalid DAI format\n");
0099 return -EINVAL;
0100 }
0101
0102 return 0;
0103 }
0104
0105 static int es7134_component_probe(struct snd_soc_component *c)
0106 {
0107 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(c);
0108 struct es7134_data *priv = snd_soc_component_get_drvdata(c);
0109 const struct es7134_chip *chip = priv->chip;
0110 int ret;
0111
0112 if (chip->extra_widget_num) {
0113 ret = snd_soc_dapm_new_controls(dapm, chip->extra_widgets,
0114 chip->extra_widget_num);
0115 if (ret) {
0116 dev_err(c->dev, "failed to add extra widgets\n");
0117 return ret;
0118 }
0119 }
0120
0121 if (chip->extra_route_num) {
0122 ret = snd_soc_dapm_add_routes(dapm, chip->extra_routes,
0123 chip->extra_route_num);
0124 if (ret) {
0125 dev_err(c->dev, "failed to add extra routes\n");
0126 return ret;
0127 }
0128 }
0129
0130 return 0;
0131 }
0132
0133 static const struct snd_soc_dai_ops es7134_dai_ops = {
0134 .set_fmt = es7134_set_fmt,
0135 .hw_params = es7134_hw_params,
0136 .set_sysclk = es7134_set_sysclk,
0137 };
0138
0139 static struct snd_soc_dai_driver es7134_dai = {
0140 .name = "es7134-hifi",
0141 .playback = {
0142 .stream_name = "Playback",
0143 .channels_min = 2,
0144 .channels_max = 2,
0145 .rates = (SNDRV_PCM_RATE_8000_48000 |
0146 SNDRV_PCM_RATE_88200 |
0147 SNDRV_PCM_RATE_96000 |
0148 SNDRV_PCM_RATE_176400 |
0149 SNDRV_PCM_RATE_192000),
0150 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
0151 SNDRV_PCM_FMTBIT_S18_3LE |
0152 SNDRV_PCM_FMTBIT_S20_3LE |
0153 SNDRV_PCM_FMTBIT_S24_3LE |
0154 SNDRV_PCM_FMTBIT_S24_LE),
0155 },
0156 .ops = &es7134_dai_ops,
0157 };
0158
0159 static const struct es7134_clock_mode es7134_modes[] = {
0160 {
0161
0162 .rate_min = 8000,
0163 .rate_max = 50000,
0164 .mclk_fs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
0165 .mclk_fs_num = 5,
0166 }, {
0167
0168 .rate_min = 84000,
0169 .rate_max = 100000,
0170 .mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512 },
0171 .mclk_fs_num = 5,
0172 }, {
0173
0174 .rate_min = 167000,
0175 .rate_max = 192000,
0176 .mclk_fs = (unsigned int[]) { 128, 192, 256 },
0177 .mclk_fs_num = 3,
0178 },
0179 };
0180
0181
0182 static const struct snd_soc_dapm_route es7134_extra_routes[] = {
0183 { "Playback", NULL, "VDD", }
0184 };
0185
0186 static const struct es7134_chip es7134_chip __maybe_unused = {
0187 .dai_drv = &es7134_dai,
0188 .modes = es7134_modes,
0189 .mode_num = ARRAY_SIZE(es7134_modes),
0190 .extra_routes = es7134_extra_routes,
0191 .extra_route_num = ARRAY_SIZE(es7134_extra_routes),
0192 };
0193
0194 static const struct snd_soc_dapm_widget es7134_dapm_widgets[] = {
0195 SND_SOC_DAPM_OUTPUT("AOUTL"),
0196 SND_SOC_DAPM_OUTPUT("AOUTR"),
0197 SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
0198 SND_SOC_DAPM_REGULATOR_SUPPLY("VDD", 0, 0),
0199 };
0200
0201 static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
0202 { "AOUTL", NULL, "DAC" },
0203 { "AOUTR", NULL, "DAC" },
0204 { "DAC", NULL, "VDD" },
0205 };
0206
0207 static const struct snd_soc_component_driver es7134_component_driver = {
0208 .probe = es7134_component_probe,
0209 .dapm_widgets = es7134_dapm_widgets,
0210 .num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets),
0211 .dapm_routes = es7134_dapm_routes,
0212 .num_dapm_routes = ARRAY_SIZE(es7134_dapm_routes),
0213 .idle_bias_on = 1,
0214 .use_pmdown_time = 1,
0215 .endianness = 1,
0216 };
0217
0218 static struct snd_soc_dai_driver es7154_dai = {
0219 .name = "es7154-hifi",
0220 .playback = {
0221 .stream_name = "Playback",
0222 .channels_min = 2,
0223 .channels_max = 2,
0224 .rates = (SNDRV_PCM_RATE_8000_48000 |
0225 SNDRV_PCM_RATE_88200 |
0226 SNDRV_PCM_RATE_96000),
0227 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
0228 SNDRV_PCM_FMTBIT_S18_3LE |
0229 SNDRV_PCM_FMTBIT_S20_3LE |
0230 SNDRV_PCM_FMTBIT_S24_3LE |
0231 SNDRV_PCM_FMTBIT_S24_LE),
0232 },
0233 .ops = &es7134_dai_ops,
0234 };
0235
0236 static const struct es7134_clock_mode es7154_modes[] = {
0237 {
0238
0239 .rate_min = 8000,
0240 .rate_max = 50000,
0241 .mclk_fs = (unsigned int[]) { 32, 64, 128, 192, 256,
0242 384, 512, 768, 1024 },
0243 .mclk_fs_num = 9,
0244 }, {
0245
0246 .rate_min = 84000,
0247 .rate_max = 100000,
0248 .mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512,
0249 768, 1024},
0250 .mclk_fs_num = 7,
0251 }
0252 };
0253
0254
0255 static const struct snd_soc_dapm_widget es7154_extra_widgets[] = {
0256 SND_SOC_DAPM_REGULATOR_SUPPLY("PVDD", 0, 0),
0257 };
0258
0259 static const struct snd_soc_dapm_route es7154_extra_routes[] = {
0260 { "Playback", NULL, "PVDD", }
0261 };
0262
0263 static const struct es7134_chip es7154_chip __maybe_unused = {
0264 .dai_drv = &es7154_dai,
0265 .modes = es7154_modes,
0266 .mode_num = ARRAY_SIZE(es7154_modes),
0267 .extra_routes = es7154_extra_routes,
0268 .extra_route_num = ARRAY_SIZE(es7154_extra_routes),
0269 .extra_widgets = es7154_extra_widgets,
0270 .extra_widget_num = ARRAY_SIZE(es7154_extra_widgets),
0271 };
0272
0273 static int es7134_probe(struct platform_device *pdev)
0274 {
0275 struct device *dev = &pdev->dev;
0276 struct es7134_data *priv;
0277
0278 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0279 if (!priv)
0280 return -ENOMEM;
0281 platform_set_drvdata(pdev, priv);
0282
0283 priv->chip = of_device_get_match_data(dev);
0284 if (!priv->chip) {
0285 dev_err(dev, "failed to match device\n");
0286 return -ENODEV;
0287 }
0288
0289 return devm_snd_soc_register_component(&pdev->dev,
0290 &es7134_component_driver,
0291 priv->chip->dai_drv, 1);
0292 }
0293
0294 #ifdef CONFIG_OF
0295 static const struct of_device_id es7134_ids[] = {
0296 { .compatible = "everest,es7134", .data = &es7134_chip },
0297 { .compatible = "everest,es7144", .data = &es7134_chip },
0298 { .compatible = "everest,es7154", .data = &es7154_chip },
0299 { }
0300 };
0301 MODULE_DEVICE_TABLE(of, es7134_ids);
0302 #endif
0303
0304 static struct platform_driver es7134_driver = {
0305 .driver = {
0306 .name = "es7134",
0307 .of_match_table = of_match_ptr(es7134_ids),
0308 },
0309 .probe = es7134_probe,
0310 };
0311
0312 module_platform_driver(es7134_driver);
0313
0314 MODULE_DESCRIPTION("ASoC ES7134 audio codec driver");
0315 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0316 MODULE_LICENSE("GPL");