linux/sound/soc/codecs/es7241.c
<<
>>
Prefs
   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
  11struct 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
  21struct es7241_chip {
  22        const struct es7241_clock_mode *modes;
  23        unsigned int mode_num;
  24};
  25
  26struct 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
  36static 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
  49static 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
  65out_ok:
  66        es7241_set_mode(priv, 1, 1);
  67        return 0;
  68}
  69
  70static 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
  86static 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
 112static 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
 125static 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
 155static 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
 161static 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
 175static 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
 206static const struct es7241_chip es7241_chip = {
 207        .modes = es7241_modes,
 208        .mode_num = ARRAY_SIZE(es7241_modes),
 209};
 210
 211static 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
 220static 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
 228static 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
 238static 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
 254static 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
 303static const struct of_device_id es7241_ids[] = {
 304        { .compatible = "everest,es7241", .data = &es7241_chip },
 305        { }
 306};
 307MODULE_DEVICE_TABLE(of, es7241_ids);
 308#endif
 309
 310static 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
 318module_platform_driver(es7241_driver);
 319
 320MODULE_DESCRIPTION("ASoC ES7241 audio codec driver");
 321MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 322MODULE_LICENSE("GPL");
 323