root/sound/soc/codecs/es7241.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. es7241_set_mode
  2. es7241_set_slave_mode
  3. es7241_set_master_mode
  4. es7241_hw_params
  5. es7241_set_sysclk
  6. es7241_set_fmt
  7. es7241_parse_fmt
  8. es7241_probe

   1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2 //
   3 // Copyright (c) 2018 BayLibre, SAS.
   4 // Author: Jerome Brunet <jbrunet@baylibre.com>
   5 
   6 #include <linux/gpio/consumer.h>
   7 #include <linux/of_platform.h>
   8 #include <linux/module.h>
   9 #include <sound/soc.h>
  10 
  11 struct es7241_clock_mode {
  12         unsigned int rate_min;
  13         unsigned int rate_max;
  14         unsigned int *slv_mfs;
  15         unsigned int slv_mfs_num;
  16         unsigned int mst_mfs;
  17         unsigned int mst_m0:1;
  18         unsigned int mst_m1:1;
  19 };
  20 
  21 struct es7241_chip {
  22         const struct es7241_clock_mode *modes;
  23         unsigned int mode_num;
  24 };
  25 
  26 struct es7241_data {
  27         struct gpio_desc *reset;
  28         struct gpio_desc *m0;
  29         struct gpio_desc *m1;
  30         unsigned int fmt;
  31         unsigned int mclk;
  32         bool is_slave;
  33         const struct es7241_chip *chip;
  34 };
  35 
  36 static void es7241_set_mode(struct es7241_data *priv,  int m0, int m1)
  37 {
  38         /* put the device in reset */
  39         gpiod_set_value_cansleep(priv->reset, 0);
  40 
  41         /* set the mode */
  42         gpiod_set_value_cansleep(priv->m0, m0);
  43         gpiod_set_value_cansleep(priv->m1, m1);
  44 
  45         /* take the device out of reset - datasheet does not specify a delay */
  46         gpiod_set_value_cansleep(priv->reset, 1);
  47 }
  48 
  49 static int es7241_set_slave_mode(struct es7241_data *priv,
  50                                  const struct es7241_clock_mode *mode,
  51                                  unsigned int mfs)
  52 {
  53         int j;
  54 
  55         if (!mfs)
  56                 goto out_ok;
  57 
  58         for (j = 0; j < mode->slv_mfs_num; j++) {
  59                 if (mode->slv_mfs[j] == mfs)
  60                         goto out_ok;
  61         }
  62 
  63         return -EINVAL;
  64 
  65 out_ok:
  66         es7241_set_mode(priv, 1, 1);
  67         return 0;
  68 }
  69 
  70 static int es7241_set_master_mode(struct es7241_data *priv,
  71                                   const struct es7241_clock_mode *mode,
  72                                   unsigned int mfs)
  73 {
  74         /*
  75          * We can't really set clock ratio, if the mclk/lrclk is different
  76          * from what we provide, then error out
  77          */
  78         if (mfs && mfs != mode->mst_mfs)
  79                 return -EINVAL;
  80 
  81         es7241_set_mode(priv, mode->mst_m0, mode->mst_m1);
  82 
  83         return 0;
  84 }
  85 
  86 static int es7241_hw_params(struct snd_pcm_substream *substream,
  87                             struct snd_pcm_hw_params *params,
  88                             struct snd_soc_dai *dai)
  89 {
  90         struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
  91         unsigned int rate = params_rate(params);
  92         unsigned int mfs = priv->mclk / rate;
  93         int i;
  94 
  95         for (i = 0; i < priv->chip->mode_num; i++) {
  96                 const struct es7241_clock_mode *mode = &priv->chip->modes[i];
  97 
  98                 if (rate < mode->rate_min || rate >= mode->rate_max)
  99                         continue;
 100 
 101                 if (priv->is_slave)
 102                         return es7241_set_slave_mode(priv, mode, mfs);
 103                 else
 104                         return es7241_set_master_mode(priv, mode, mfs);
 105         }
 106 
 107         /* should not happen */
 108         dev_err(dai->dev, "unsupported rate: %u\n", rate);
 109         return -EINVAL;
 110 }
 111 
 112 static int es7241_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 113                              unsigned int freq, int dir)
 114 {
 115         struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
 116 
 117         if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
 118                 priv->mclk = freq;
 119                 return 0;
 120         }
 121 
 122         return -ENOTSUPP;
 123 }
 124 
 125 static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 126 {
 127         struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
 128 
 129         if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
 130                 dev_err(dai->dev, "Unsupported dai clock inversion\n");
 131                 return -EINVAL;
 132         }
 133 
 134         if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != priv->fmt) {
 135                 dev_err(dai->dev, "Invalid dai format\n");
 136                 return -EINVAL;
 137         }
 138 
 139         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 140         case SND_SOC_DAIFMT_CBS_CFS:
 141                 priv->is_slave = true;
 142                 break;
 143         case SND_SOC_DAIFMT_CBM_CFM:
 144                 priv->is_slave = false;
 145                 break;
 146 
 147         default:
 148                 dev_err(dai->dev, "Unsupported clock configuration\n");
 149                 return -EINVAL;
 150         }
 151 
 152         return 0;
 153 }
 154 
 155 static const struct snd_soc_dai_ops es7241_dai_ops = {
 156         .set_fmt        = es7241_set_fmt,
 157         .hw_params      = es7241_hw_params,
 158         .set_sysclk     = es7241_set_sysclk,
 159 };
 160 
 161 static struct snd_soc_dai_driver es7241_dai = {
 162         .name = "es7241-hifi",
 163         .capture = {
 164                 .stream_name = "Capture",
 165                 .channels_min = 2,
 166                 .channels_max = 2,
 167                 .rates = SNDRV_PCM_RATE_8000_192000,
 168                 .formats = (SNDRV_PCM_FMTBIT_S16_LE  |
 169                             SNDRV_PCM_FMTBIT_S24_3LE |
 170                             SNDRV_PCM_FMTBIT_S24_LE),
 171         },
 172         .ops = &es7241_dai_ops,
 173 };
 174 
 175 static const struct es7241_clock_mode es7241_modes[] = {
 176         {
 177                 /* Single speed mode */
 178                 .rate_min = 8000,
 179                 .rate_max = 50000,
 180                 .slv_mfs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
 181                 .slv_mfs_num = 5,
 182                 .mst_mfs = 256,
 183                 .mst_m0 = 0,
 184                 .mst_m1 = 0,
 185         }, {
 186                 /* Double speed mode */
 187                 .rate_min = 50000,
 188                 .rate_max = 100000,
 189                 .slv_mfs = (unsigned int[]) { 128, 192 },
 190                 .slv_mfs_num = 2,
 191                 .mst_mfs = 128,
 192                 .mst_m0 = 1,
 193                 .mst_m1 = 0,
 194         }, {
 195                 /* Quad speed mode */
 196                 .rate_min = 100000,
 197                 .rate_max = 200000,
 198                 .slv_mfs = (unsigned int[]) { 64 },
 199                 .slv_mfs_num = 1,
 200                 .mst_mfs = 64,
 201                 .mst_m0 = 0,
 202                 .mst_m1 = 1,
 203         },
 204 };
 205 
 206 static const struct es7241_chip es7241_chip = {
 207         .modes = es7241_modes,
 208         .mode_num = ARRAY_SIZE(es7241_modes),
 209 };
 210 
 211 static const struct snd_soc_dapm_widget es7241_dapm_widgets[] = {
 212         SND_SOC_DAPM_INPUT("AINL"),
 213         SND_SOC_DAPM_INPUT("AINR"),
 214         SND_SOC_DAPM_DAC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
 215         SND_SOC_DAPM_REGULATOR_SUPPLY("VDDP", 0, 0),
 216         SND_SOC_DAPM_REGULATOR_SUPPLY("VDDD", 0, 0),
 217         SND_SOC_DAPM_REGULATOR_SUPPLY("VDDA", 0, 0),
 218 };
 219 
 220 static const struct snd_soc_dapm_route es7241_dapm_routes[] = {
 221         { "ADC", NULL, "AINL", },
 222         { "ADC", NULL, "AINR", },
 223         { "ADC", NULL, "VDDA", },
 224         { "Capture", NULL, "VDDP", },
 225         { "Capture", NULL, "VDDD", },
 226 };
 227 
 228 static const struct snd_soc_component_driver es7241_component_driver = {
 229         .dapm_widgets           = es7241_dapm_widgets,
 230         .num_dapm_widgets       = ARRAY_SIZE(es7241_dapm_widgets),
 231         .dapm_routes            = es7241_dapm_routes,
 232         .num_dapm_routes        = ARRAY_SIZE(es7241_dapm_routes),
 233         .idle_bias_on           = 1,
 234         .endianness             = 1,
 235         .non_legacy_dai_naming  = 1,
 236 };
 237 
 238 static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv)
 239 {
 240         bool is_leftj;
 241 
 242         /*
 243          * The format is given by a pull resistor on the SDOUT pin:
 244          * pull-up for i2s, pull-down for left justified.
 245          */
 246         is_leftj = of_property_read_bool(dev->of_node,
 247                                          "everest,sdout-pull-down");
 248         if (is_leftj)
 249                 priv->fmt = SND_SOC_DAIFMT_LEFT_J;
 250         else
 251                 priv->fmt = SND_SOC_DAIFMT_I2S;
 252 }
 253 
 254 static int es7241_probe(struct platform_device *pdev)
 255 {
 256         struct device *dev = &pdev->dev;
 257         struct es7241_data *priv;
 258         int err;
 259 
 260         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 261         if (!priv)
 262                 return -ENOMEM;
 263         platform_set_drvdata(pdev, priv);
 264 
 265         priv->chip = of_device_get_match_data(dev);
 266         if (!priv->chip) {
 267                 dev_err(dev, "failed to match device\n");
 268                 return -ENODEV;
 269         }
 270 
 271         es7241_parse_fmt(dev, priv);
 272 
 273         priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 274         if (IS_ERR(priv->reset)) {
 275                 err = PTR_ERR(priv->reset);
 276                 if (err != -EPROBE_DEFER)
 277                         dev_err(dev, "Failed to get 'reset' gpio: %d", err);
 278                 return err;
 279         }
 280 
 281         priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW);
 282         if (IS_ERR(priv->m0)) {
 283                 err = PTR_ERR(priv->m0);
 284                 if (err != -EPROBE_DEFER)
 285                         dev_err(dev, "Failed to get 'm0' gpio: %d", err);
 286                 return err;
 287         }
 288 
 289         priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW);
 290         if (IS_ERR(priv->m1)) {
 291                 err = PTR_ERR(priv->m1);
 292                 if (err != -EPROBE_DEFER)
 293                         dev_err(dev, "Failed to get 'm1' gpio: %d", err);
 294                 return err;
 295         }
 296 
 297         return devm_snd_soc_register_component(&pdev->dev,
 298                                       &es7241_component_driver,
 299                                       &es7241_dai, 1);
 300 }
 301 
 302 #ifdef CONFIG_OF
 303 static const struct of_device_id es7241_ids[] = {
 304         { .compatible = "everest,es7241", .data = &es7241_chip },
 305         { }
 306 };
 307 MODULE_DEVICE_TABLE(of, es7241_ids);
 308 #endif
 309 
 310 static struct platform_driver es7241_driver = {
 311         .driver = {
 312                 .name = "es7241",
 313                 .of_match_table = of_match_ptr(es7241_ids),
 314         },
 315         .probe = es7241_probe,
 316 };
 317 
 318 module_platform_driver(es7241_driver);
 319 
 320 MODULE_DESCRIPTION("ASoC ES7241 audio codec driver");
 321 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 322 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */