root/sound/soc/codecs/sti-sas.c

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

DEFINITIONS

This source file includes following definitions.
  1. sti_sas_read_reg
  2. sti_sas_write_reg
  3. sti_sas_init_sas_registers
  4. sti_sas_dac_set_fmt
  5. stih407_sas_dac_mute
  6. sti_sas_spdif_set_fmt
  7. sti_sas_spdif_trigger
  8. sti_sas_volatile_register
  9. sti_sas_set_sysclk
  10. sti_sas_prepare
  11. sti_sas_resume
  12. sti_sas_component_probe
  13. sti_sas_driver_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) STMicroelectronics SA 2015
   4  * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
   5  *          for STMicroelectronics.
   6  */
   7 
   8 #include <linux/io.h>
   9 #include <linux/module.h>
  10 #include <linux/regmap.h>
  11 #include <linux/reset.h>
  12 #include <linux/mfd/syscon.h>
  13 
  14 #include <sound/soc.h>
  15 #include <sound/soc-dapm.h>
  16 
  17 /* DAC definitions */
  18 
  19 /* stih407 DAC registers */
  20 /* sysconf 5041: Audio-Gue-Control */
  21 #define STIH407_AUDIO_GLUE_CTRL 0x000000A4
  22 /* sysconf 5042: Audio-DAC-Control */
  23 #define STIH407_AUDIO_DAC_CTRL 0x000000A8
  24 
  25 /* DAC definitions */
  26 #define STIH407_DAC_SOFTMUTE            0x0
  27 #define STIH407_DAC_STANDBY_ANA         0x1
  28 #define STIH407_DAC_STANDBY             0x2
  29 
  30 #define STIH407_DAC_SOFTMUTE_MASK       BIT(STIH407_DAC_SOFTMUTE)
  31 #define STIH407_DAC_STANDBY_ANA_MASK    BIT(STIH407_DAC_STANDBY_ANA)
  32 #define STIH407_DAC_STANDBY_MASK        BIT(STIH407_DAC_STANDBY)
  33 
  34 /* SPDIF definitions */
  35 #define SPDIF_BIPHASE_ENABLE            0x6
  36 #define SPDIF_BIPHASE_IDLE              0x7
  37 
  38 #define SPDIF_BIPHASE_ENABLE_MASK       BIT(SPDIF_BIPHASE_ENABLE)
  39 #define SPDIF_BIPHASE_IDLE_MASK         BIT(SPDIF_BIPHASE_IDLE)
  40 
  41 enum {
  42         STI_SAS_DAI_SPDIF_OUT,
  43         STI_SAS_DAI_ANALOG_OUT,
  44 };
  45 
  46 static const struct reg_default stih407_sas_reg_defaults[] = {
  47         { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
  48         { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
  49 };
  50 
  51 struct sti_dac_audio {
  52         struct regmap *regmap;
  53         struct regmap *virt_regmap;
  54         struct regmap_field  **field;
  55         struct reset_control *rst;
  56         int mclk;
  57 };
  58 
  59 struct sti_spdif_audio {
  60         struct regmap *regmap;
  61         struct regmap_field  **field;
  62         int mclk;
  63 };
  64 
  65 /* device data structure */
  66 struct sti_sas_dev_data {
  67         const struct regmap_config *regmap;
  68         const struct snd_soc_dai_ops *dac_ops;  /* DAC function callbacks */
  69         const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
  70         const int num_dapm_widgets; /* dapms declaration */
  71         const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
  72         const int num_dapm_routes; /* route declaration */
  73 };
  74 
  75 /* driver data structure */
  76 struct sti_sas_data {
  77         struct device *dev;
  78         const struct sti_sas_dev_data *dev_data;
  79         struct sti_dac_audio dac;
  80         struct sti_spdif_audio spdif;
  81 };
  82 
  83 /* Read a register from the sysconf reg bank */
  84 static int sti_sas_read_reg(void *context, unsigned int reg,
  85                             unsigned int *value)
  86 {
  87         struct sti_sas_data *drvdata = context;
  88         int status;
  89         u32 val;
  90 
  91         status = regmap_read(drvdata->dac.regmap, reg, &val);
  92         *value = (unsigned int)val;
  93 
  94         return status;
  95 }
  96 
  97 /* Read a register from the sysconf reg bank */
  98 static int sti_sas_write_reg(void *context, unsigned int reg,
  99                              unsigned int value)
 100 {
 101         struct sti_sas_data *drvdata = context;
 102         int status;
 103 
 104         status = regmap_write(drvdata->dac.regmap, reg, value);
 105 
 106         return status;
 107 }
 108 
 109 static int  sti_sas_init_sas_registers(struct snd_soc_component *component,
 110                                        struct sti_sas_data *data)
 111 {
 112         int ret;
 113         /*
 114          * DAC and SPDIF are activated by default
 115          * put them in IDLE to save power
 116          */
 117 
 118         /* Initialise bi-phase formatter to disabled */
 119         ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 120                                   SPDIF_BIPHASE_ENABLE_MASK, 0);
 121 
 122         if (!ret)
 123                 /* Initialise bi-phase formatter idle value to 0 */
 124                 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 125                                           SPDIF_BIPHASE_IDLE_MASK, 0);
 126         if (ret < 0) {
 127                 dev_err(component->dev, "Failed to update SPDIF registers\n");
 128                 return ret;
 129         }
 130 
 131         /* Init DAC configuration */
 132         /* init configuration */
 133         ret =  snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 134                                    STIH407_DAC_STANDBY_MASK,
 135                                    STIH407_DAC_STANDBY_MASK);
 136 
 137         if (!ret)
 138                 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 139                                           STIH407_DAC_STANDBY_ANA_MASK,
 140                                           STIH407_DAC_STANDBY_ANA_MASK);
 141         if (!ret)
 142                 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 143                                           STIH407_DAC_SOFTMUTE_MASK,
 144                                           STIH407_DAC_SOFTMUTE_MASK);
 145 
 146         if (ret < 0) {
 147                 dev_err(component->dev, "Failed to update DAC registers\n");
 148                 return ret;
 149         }
 150 
 151         return ret;
 152 }
 153 
 154 /*
 155  * DAC
 156  */
 157 static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 158 {
 159         /* Sanity check only */
 160         if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
 161                 dev_err(dai->component->dev,
 162                         "%s: ERROR: Unsupporter master mask 0x%x\n",
 163                         __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
 164                 return -EINVAL;
 165         }
 166 
 167         return 0;
 168 }
 169 
 170 static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
 171         SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
 172                              STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
 173         SND_SOC_DAPM_DAC("DAC standby",  "dac_p", STIH407_AUDIO_DAC_CTRL,
 174                          STIH407_DAC_STANDBY, 1),
 175         SND_SOC_DAPM_OUTPUT("DAC Output"),
 176 };
 177 
 178 static const struct snd_soc_dapm_route stih407_sas_route[] = {
 179         {"DAC Output", NULL, "DAC standby ana"},
 180         {"DAC standby ana", NULL, "DAC standby"},
 181 };
 182 
 183 
 184 static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
 185 {
 186         struct snd_soc_component *component = dai->component;
 187 
 188         if (mute) {
 189                 return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 190                                             STIH407_DAC_SOFTMUTE_MASK,
 191                                             STIH407_DAC_SOFTMUTE_MASK);
 192         } else {
 193                 return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
 194                                             STIH407_DAC_SOFTMUTE_MASK,
 195                                             0);
 196         }
 197 }
 198 
 199 /*
 200  * SPDIF
 201  */
 202 static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
 203                                  unsigned int fmt)
 204 {
 205         if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
 206                 dev_err(dai->component->dev,
 207                         "%s: ERROR: Unsupporter master mask 0x%x\n",
 208                         __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
 209                 return -EINVAL;
 210         }
 211 
 212         return 0;
 213 }
 214 
 215 /*
 216  * sti_sas_spdif_trigger:
 217  * Trigger function is used to ensure that BiPhase Formater is disabled
 218  * before CPU dai is stopped.
 219  * This is mandatory to avoid that BPF is stalled
 220  */
 221 static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
 222                                  struct snd_soc_dai *dai)
 223 {
 224         struct snd_soc_component *component = dai->component;
 225 
 226         switch (cmd) {
 227         case SNDRV_PCM_TRIGGER_START:
 228         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 229                 return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 230                                             SPDIF_BIPHASE_ENABLE_MASK,
 231                                             SPDIF_BIPHASE_ENABLE_MASK);
 232         case SNDRV_PCM_TRIGGER_RESUME:
 233         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 234         case SNDRV_PCM_TRIGGER_STOP:
 235         case SNDRV_PCM_TRIGGER_SUSPEND:
 236                 return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
 237                                             SPDIF_BIPHASE_ENABLE_MASK,
 238                                             0);
 239         default:
 240                 return -EINVAL;
 241         }
 242 }
 243 
 244 static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
 245 {
 246         if (reg == STIH407_AUDIO_GLUE_CTRL)
 247                 return true;
 248 
 249         return false;
 250 }
 251 
 252 /*
 253  * CODEC DAIS
 254  */
 255 
 256 /*
 257  * sti_sas_set_sysclk:
 258  * get MCLK input frequency to check that MCLK-FS ratio is coherent
 259  */
 260 static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 261                               unsigned int freq, int dir)
 262 {
 263         struct snd_soc_component *component = dai->component;
 264         struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 265 
 266         if (dir == SND_SOC_CLOCK_OUT)
 267                 return 0;
 268 
 269         if (clk_id != 0)
 270                 return -EINVAL;
 271 
 272         switch (dai->id) {
 273         case STI_SAS_DAI_SPDIF_OUT:
 274                 drvdata->spdif.mclk = freq;
 275                 break;
 276 
 277         case STI_SAS_DAI_ANALOG_OUT:
 278                 drvdata->dac.mclk = freq;
 279                 break;
 280         }
 281 
 282         return 0;
 283 }
 284 
 285 static int sti_sas_prepare(struct snd_pcm_substream *substream,
 286                            struct snd_soc_dai *dai)
 287 {
 288         struct snd_soc_component *component = dai->component;
 289         struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 290         struct snd_pcm_runtime *runtime = substream->runtime;
 291 
 292         switch (dai->id) {
 293         case STI_SAS_DAI_SPDIF_OUT:
 294                 if ((drvdata->spdif.mclk / runtime->rate) != 128) {
 295                         dev_err(component->dev, "unexpected mclk-fs ratio\n");
 296                         return -EINVAL;
 297                 }
 298                 break;
 299         case STI_SAS_DAI_ANALOG_OUT:
 300                 if ((drvdata->dac.mclk / runtime->rate) != 256) {
 301                         dev_err(component->dev, "unexpected mclk-fs ratio\n");
 302                         return -EINVAL;
 303                 }
 304                 break;
 305         }
 306 
 307         return 0;
 308 }
 309 
 310 static const struct snd_soc_dai_ops stih407_dac_ops = {
 311         .set_fmt = sti_sas_dac_set_fmt,
 312         .mute_stream = stih407_sas_dac_mute,
 313         .prepare = sti_sas_prepare,
 314         .set_sysclk = sti_sas_set_sysclk,
 315 };
 316 
 317 static const struct regmap_config stih407_sas_regmap = {
 318         .reg_bits = 32,
 319         .val_bits = 32,
 320         .fast_io = true,
 321         .max_register = STIH407_AUDIO_DAC_CTRL,
 322         .reg_defaults = stih407_sas_reg_defaults,
 323         .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
 324         .volatile_reg = sti_sas_volatile_register,
 325         .cache_type = REGCACHE_RBTREE,
 326         .reg_read = sti_sas_read_reg,
 327         .reg_write = sti_sas_write_reg,
 328 };
 329 
 330 static const struct sti_sas_dev_data stih407_data = {
 331         .regmap = &stih407_sas_regmap,
 332         .dac_ops = &stih407_dac_ops,
 333         .dapm_widgets = stih407_sas_dapm_widgets,
 334         .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
 335         .dapm_routes =  stih407_sas_route,
 336         .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
 337 };
 338 
 339 static struct snd_soc_dai_driver sti_sas_dai[] = {
 340         {
 341                 .name = "sas-dai-spdif-out",
 342                 .id = STI_SAS_DAI_SPDIF_OUT,
 343                 .playback = {
 344                         .stream_name = "spdif_p",
 345                         .channels_min = 2,
 346                         .channels_max = 2,
 347                         .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
 348                                  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
 349                                  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
 350                                  SNDRV_PCM_RATE_192000,
 351                         .formats = SNDRV_PCM_FMTBIT_S16_LE |
 352                                    SNDRV_PCM_FMTBIT_S32_LE,
 353                 },
 354                 .ops = (struct snd_soc_dai_ops[]) {
 355                         {
 356                                 .set_fmt = sti_sas_spdif_set_fmt,
 357                                 .trigger = sti_sas_spdif_trigger,
 358                                 .set_sysclk = sti_sas_set_sysclk,
 359                                 .prepare = sti_sas_prepare,
 360                         }
 361                 },
 362         },
 363         {
 364                 .name = "sas-dai-dac",
 365                 .id = STI_SAS_DAI_ANALOG_OUT,
 366                 .playback = {
 367                         .stream_name = "dac_p",
 368                         .channels_min = 2,
 369                         .channels_max = 2,
 370                         .rates = SNDRV_PCM_RATE_8000_48000,
 371                         .formats = SNDRV_PCM_FMTBIT_S16_LE |
 372                                    SNDRV_PCM_FMTBIT_S32_LE,
 373                 },
 374         },
 375 };
 376 
 377 #ifdef CONFIG_PM_SLEEP
 378 static int sti_sas_resume(struct snd_soc_component *component)
 379 {
 380         struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 381 
 382         return sti_sas_init_sas_registers(component, drvdata);
 383 }
 384 #else
 385 #define sti_sas_resume NULL
 386 #endif
 387 
 388 static int sti_sas_component_probe(struct snd_soc_component *component)
 389 {
 390         struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
 391         int ret;
 392 
 393         ret = sti_sas_init_sas_registers(component, drvdata);
 394 
 395         return ret;
 396 }
 397 
 398 static struct snd_soc_component_driver sti_sas_driver = {
 399         .probe                  = sti_sas_component_probe,
 400         .resume                 = sti_sas_resume,
 401         .idle_bias_on           = 1,
 402         .use_pmdown_time        = 1,
 403         .endianness             = 1,
 404         .non_legacy_dai_naming  = 1,
 405 };
 406 
 407 static const struct of_device_id sti_sas_dev_match[] = {
 408         {
 409                 .compatible = "st,stih407-sas-codec",
 410                 .data = &stih407_data,
 411         },
 412         {},
 413 };
 414 
 415 static int sti_sas_driver_probe(struct platform_device *pdev)
 416 {
 417         struct device_node *pnode = pdev->dev.of_node;
 418         struct sti_sas_data *drvdata;
 419         const struct of_device_id *of_id;
 420 
 421         /* Allocate device structure */
 422         drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
 423                                GFP_KERNEL);
 424         if (!drvdata)
 425                 return -ENOMEM;
 426 
 427         /* Populate data structure depending on compatibility */
 428         of_id = of_match_node(sti_sas_dev_match, pnode);
 429         if (!of_id->data) {
 430                 dev_err(&pdev->dev, "data associated to device is missing\n");
 431                 return -EINVAL;
 432         }
 433 
 434         drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
 435 
 436         /* Initialise device structure */
 437         drvdata->dev = &pdev->dev;
 438 
 439         /* Request the DAC & SPDIF registers memory region */
 440         drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
 441                                                     drvdata->dev_data->regmap);
 442         if (IS_ERR(drvdata->dac.virt_regmap)) {
 443                 dev_err(&pdev->dev, "audio registers not enabled\n");
 444                 return PTR_ERR(drvdata->dac.virt_regmap);
 445         }
 446 
 447         /* Request the syscon region */
 448         drvdata->dac.regmap =
 449                 syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
 450         if (IS_ERR(drvdata->dac.regmap)) {
 451                 dev_err(&pdev->dev, "syscon registers not available\n");
 452                 return PTR_ERR(drvdata->dac.regmap);
 453         }
 454         drvdata->spdif.regmap = drvdata->dac.regmap;
 455 
 456         sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
 457 
 458         /* Set dapms*/
 459         sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
 460         sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
 461 
 462         sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
 463         sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
 464 
 465         /* Store context */
 466         dev_set_drvdata(&pdev->dev, drvdata);
 467 
 468         return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
 469                                         sti_sas_dai,
 470                                         ARRAY_SIZE(sti_sas_dai));
 471 }
 472 
 473 static struct platform_driver sti_sas_platform_driver = {
 474         .driver = {
 475                 .name = "sti-sas-codec",
 476                 .of_match_table = sti_sas_dev_match,
 477         },
 478         .probe = sti_sas_driver_probe,
 479 };
 480 
 481 module_platform_driver(sti_sas_platform_driver);
 482 
 483 MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
 484 MODULE_AUTHOR("Arnaud.pouliquen@st.com");
 485 MODULE_LICENSE("GPL v2");

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