linux/sound/soc/codecs/pcm186x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Texas Instruments PCM186x Universal Audio ADC
   4 *
   5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com
   6 *      Andreas Dannenberg <dannenberg@ti.com>
   7 *      Andrew F. Davis <afd@ti.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/moduleparam.h>
  12#include <linux/init.h>
  13#include <linux/delay.h>
  14#include <linux/pm.h>
  15#include <linux/pm_runtime.h>
  16#include <linux/regulator/consumer.h>
  17#include <linux/regmap.h>
  18#include <linux/slab.h>
  19#include <sound/core.h>
  20#include <sound/pcm.h>
  21#include <sound/pcm_params.h>
  22#include <sound/soc.h>
  23#include <sound/jack.h>
  24#include <sound/initval.h>
  25#include <sound/tlv.h>
  26
  27#include "pcm186x.h"
  28
  29static const char * const pcm186x_supply_names[] = {
  30        "avdd",         /* Analog power supply. Connect to 3.3-V supply. */
  31        "dvdd",         /* Digital power supply. Connect to 3.3-V supply. */
  32        "iovdd",        /* I/O power supply. Connect to 3.3-V or 1.8-V. */
  33};
  34#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
  35
  36struct pcm186x_priv {
  37        struct regmap *regmap;
  38        struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES];
  39        unsigned int sysclk;
  40        unsigned int tdm_offset;
  41        bool is_tdm_mode;
  42        bool is_master_mode;
  43};
  44
  45static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 50, 0);
  46
  47static const struct snd_kcontrol_new pcm1863_snd_controls[] = {
  48        SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L,
  49                           PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
  50                           pcm186x_pga_tlv),
  51};
  52
  53static const struct snd_kcontrol_new pcm1865_snd_controls[] = {
  54        SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L,
  55                           PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
  56                           pcm186x_pga_tlv),
  57        SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L,
  58                           PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0,
  59                           pcm186x_pga_tlv),
  60};
  61
  62static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
  63        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  64        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  65        0x10, 0x20, 0x30
  66};
  67
  68static const char * const pcm186x_adcl_input_channel_sel_text[] = {
  69        "No Select",
  70        "VINL1[SE]",                                    /* Default for ADC1L */
  71        "VINL2[SE]",                                    /* Default for ADC2L */
  72        "VINL2[SE] + VINL1[SE]",
  73        "VINL3[SE]",
  74        "VINL3[SE] + VINL1[SE]",
  75        "VINL3[SE] + VINL2[SE]",
  76        "VINL3[SE] + VINL2[SE] + VINL1[SE]",
  77        "VINL4[SE]",
  78        "VINL4[SE] + VINL1[SE]",
  79        "VINL4[SE] + VINL2[SE]",
  80        "VINL4[SE] + VINL2[SE] + VINL1[SE]",
  81        "VINL4[SE] + VINL3[SE]",
  82        "VINL4[SE] + VINL3[SE] + VINL1[SE]",
  83        "VINL4[SE] + VINL3[SE] + VINL2[SE]",
  84        "VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]",
  85        "{VIN1P, VIN1M}[DIFF]",
  86        "{VIN4P, VIN4M}[DIFF]",
  87        "{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
  88};
  89
  90static const char * const pcm186x_adcr_input_channel_sel_text[] = {
  91        "No Select",
  92        "VINR1[SE]",                                    /* Default for ADC1R */
  93        "VINR2[SE]",                                    /* Default for ADC2R */
  94        "VINR2[SE] + VINR1[SE]",
  95        "VINR3[SE]",
  96        "VINR3[SE] + VINR1[SE]",
  97        "VINR3[SE] + VINR2[SE]",
  98        "VINR3[SE] + VINR2[SE] + VINR1[SE]",
  99        "VINR4[SE]",
 100        "VINR4[SE] + VINR1[SE]",
 101        "VINR4[SE] + VINR2[SE]",
 102        "VINR4[SE] + VINR2[SE] + VINR1[SE]",
 103        "VINR4[SE] + VINR3[SE]",
 104        "VINR4[SE] + VINR3[SE] + VINR1[SE]",
 105        "VINR4[SE] + VINR3[SE] + VINR2[SE]",
 106        "VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]",
 107        "{VIN2P, VIN2M}[DIFF]",
 108        "{VIN3P, VIN3M}[DIFF]",
 109        "{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
 110};
 111
 112static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
 113        SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
 114                              PCM186X_ADC_INPUT_SEL_MASK,
 115                              ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
 116                              pcm186x_adcl_input_channel_sel_text,
 117                              pcm186x_adc_input_channel_sel_value),
 118        SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
 119                              PCM186X_ADC_INPUT_SEL_MASK,
 120                              ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
 121                              pcm186x_adcr_input_channel_sel_text,
 122                              pcm186x_adc_input_channel_sel_value),
 123        SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0,
 124                              PCM186X_ADC_INPUT_SEL_MASK,
 125                              ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
 126                              pcm186x_adcl_input_channel_sel_text,
 127                              pcm186x_adc_input_channel_sel_value),
 128        SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0,
 129                              PCM186X_ADC_INPUT_SEL_MASK,
 130                              ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
 131                              pcm186x_adcr_input_channel_sel_text,
 132                              pcm186x_adc_input_channel_sel_value),
 133};
 134
 135static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = {
 136        SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]),
 137        SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]),
 138        SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]),
 139        SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]),
 140};
 141
 142static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = {
 143        SND_SOC_DAPM_INPUT("VINL1"),
 144        SND_SOC_DAPM_INPUT("VINR1"),
 145        SND_SOC_DAPM_INPUT("VINL2"),
 146        SND_SOC_DAPM_INPUT("VINR2"),
 147        SND_SOC_DAPM_INPUT("VINL3"),
 148        SND_SOC_DAPM_INPUT("VINR3"),
 149        SND_SOC_DAPM_INPUT("VINL4"),
 150        SND_SOC_DAPM_INPUT("VINR4"),
 151
 152        SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0,
 153                         &pcm186x_adc_mux_controls[0]),
 154        SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0,
 155                         &pcm186x_adc_mux_controls[1]),
 156
 157        /*
 158         * Put the codec into SLEEP mode when not in use, allowing the
 159         * Energysense mechanism to operate.
 160         */
 161        SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1,  1),
 162};
 163
 164static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = {
 165        SND_SOC_DAPM_INPUT("VINL1"),
 166        SND_SOC_DAPM_INPUT("VINR1"),
 167        SND_SOC_DAPM_INPUT("VINL2"),
 168        SND_SOC_DAPM_INPUT("VINR2"),
 169        SND_SOC_DAPM_INPUT("VINL3"),
 170        SND_SOC_DAPM_INPUT("VINR3"),
 171        SND_SOC_DAPM_INPUT("VINL4"),
 172        SND_SOC_DAPM_INPUT("VINR4"),
 173
 174        SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0,
 175                         &pcm186x_adc_mux_controls[0]),
 176        SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0,
 177                         &pcm186x_adc_mux_controls[1]),
 178        SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0,
 179                         &pcm186x_adc_mux_controls[2]),
 180        SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0,
 181                         &pcm186x_adc_mux_controls[3]),
 182
 183        /*
 184         * Put the codec into SLEEP mode when not in use, allowing the
 185         * Energysense mechanism to operate.
 186         */
 187        SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1,  1),
 188        SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1,  1),
 189};
 190
 191static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = {
 192        { "ADC Left Capture Source", NULL, "VINL1" },
 193        { "ADC Left Capture Source", NULL, "VINR1" },
 194        { "ADC Left Capture Source", NULL, "VINL2" },
 195        { "ADC Left Capture Source", NULL, "VINR2" },
 196        { "ADC Left Capture Source", NULL, "VINL3" },
 197        { "ADC Left Capture Source", NULL, "VINR3" },
 198        { "ADC Left Capture Source", NULL, "VINL4" },
 199        { "ADC Left Capture Source", NULL, "VINR4" },
 200
 201        { "ADC", NULL, "ADC Left Capture Source" },
 202
 203        { "ADC Right Capture Source", NULL, "VINL1" },
 204        { "ADC Right Capture Source", NULL, "VINR1" },
 205        { "ADC Right Capture Source", NULL, "VINL2" },
 206        { "ADC Right Capture Source", NULL, "VINR2" },
 207        { "ADC Right Capture Source", NULL, "VINL3" },
 208        { "ADC Right Capture Source", NULL, "VINR3" },
 209        { "ADC Right Capture Source", NULL, "VINL4" },
 210        { "ADC Right Capture Source", NULL, "VINR4" },
 211
 212        { "ADC", NULL, "ADC Right Capture Source" },
 213};
 214
 215static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = {
 216        { "ADC1 Left Capture Source", NULL, "VINL1" },
 217        { "ADC1 Left Capture Source", NULL, "VINR1" },
 218        { "ADC1 Left Capture Source", NULL, "VINL2" },
 219        { "ADC1 Left Capture Source", NULL, "VINR2" },
 220        { "ADC1 Left Capture Source", NULL, "VINL3" },
 221        { "ADC1 Left Capture Source", NULL, "VINR3" },
 222        { "ADC1 Left Capture Source", NULL, "VINL4" },
 223        { "ADC1 Left Capture Source", NULL, "VINR4" },
 224
 225        { "ADC1", NULL, "ADC1 Left Capture Source" },
 226
 227        { "ADC1 Right Capture Source", NULL, "VINL1" },
 228        { "ADC1 Right Capture Source", NULL, "VINR1" },
 229        { "ADC1 Right Capture Source", NULL, "VINL2" },
 230        { "ADC1 Right Capture Source", NULL, "VINR2" },
 231        { "ADC1 Right Capture Source", NULL, "VINL3" },
 232        { "ADC1 Right Capture Source", NULL, "VINR3" },
 233        { "ADC1 Right Capture Source", NULL, "VINL4" },
 234        { "ADC1 Right Capture Source", NULL, "VINR4" },
 235
 236        { "ADC1", NULL, "ADC1 Right Capture Source" },
 237
 238        { "ADC2 Left Capture Source", NULL, "VINL1" },
 239        { "ADC2 Left Capture Source", NULL, "VINR1" },
 240        { "ADC2 Left Capture Source", NULL, "VINL2" },
 241        { "ADC2 Left Capture Source", NULL, "VINR2" },
 242        { "ADC2 Left Capture Source", NULL, "VINL3" },
 243        { "ADC2 Left Capture Source", NULL, "VINR3" },
 244        { "ADC2 Left Capture Source", NULL, "VINL4" },
 245        { "ADC2 Left Capture Source", NULL, "VINR4" },
 246
 247        { "ADC2", NULL, "ADC2 Left Capture Source" },
 248
 249        { "ADC2 Right Capture Source", NULL, "VINL1" },
 250        { "ADC2 Right Capture Source", NULL, "VINR1" },
 251        { "ADC2 Right Capture Source", NULL, "VINL2" },
 252        { "ADC2 Right Capture Source", NULL, "VINR2" },
 253        { "ADC2 Right Capture Source", NULL, "VINL3" },
 254        { "ADC2 Right Capture Source", NULL, "VINR3" },
 255        { "ADC2 Right Capture Source", NULL, "VINL4" },
 256        { "ADC2 Right Capture Source", NULL, "VINR4" },
 257
 258        { "ADC2", NULL, "ADC2 Right Capture Source" },
 259};
 260
 261static int pcm186x_hw_params(struct snd_pcm_substream *substream,
 262                             struct snd_pcm_hw_params *params,
 263                             struct snd_soc_dai *dai)
 264{
 265        struct snd_soc_component *component = dai->component;
 266        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 267        unsigned int rate = params_rate(params);
 268        snd_pcm_format_t format = params_format(params);
 269        unsigned int width = params_width(params);
 270        unsigned int channels = params_channels(params);
 271        unsigned int div_lrck;
 272        unsigned int div_bck;
 273        u8 tdm_tx_sel = 0;
 274        u8 pcm_cfg = 0;
 275
 276        dev_dbg(component->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
 277                __func__, rate, format, width, channels);
 278
 279        switch (width) {
 280        case 16:
 281                pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 <<
 282                          PCM186X_PCM_CFG_RX_WLEN_SHIFT |
 283                          PCM186X_PCM_CFG_TX_WLEN_16 <<
 284                          PCM186X_PCM_CFG_TX_WLEN_SHIFT;
 285                break;
 286        case 20:
 287                pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 <<
 288                          PCM186X_PCM_CFG_RX_WLEN_SHIFT |
 289                          PCM186X_PCM_CFG_TX_WLEN_20 <<
 290                          PCM186X_PCM_CFG_TX_WLEN_SHIFT;
 291                break;
 292        case 24:
 293                pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 <<
 294                          PCM186X_PCM_CFG_RX_WLEN_SHIFT |
 295                          PCM186X_PCM_CFG_TX_WLEN_24 <<
 296                          PCM186X_PCM_CFG_TX_WLEN_SHIFT;
 297                break;
 298        case 32:
 299                pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 <<
 300                          PCM186X_PCM_CFG_RX_WLEN_SHIFT |
 301                          PCM186X_PCM_CFG_TX_WLEN_32 <<
 302                          PCM186X_PCM_CFG_TX_WLEN_SHIFT;
 303                break;
 304        default:
 305                return -EINVAL;
 306        }
 307
 308        snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
 309                            PCM186X_PCM_CFG_RX_WLEN_MASK |
 310                            PCM186X_PCM_CFG_TX_WLEN_MASK,
 311                            pcm_cfg);
 312
 313        div_lrck = width * channels;
 314
 315        if (priv->is_tdm_mode) {
 316                /* Select TDM transmission data */
 317                switch (channels) {
 318                case 2:
 319                        tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH;
 320                        break;
 321                case 4:
 322                        tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH;
 323                        break;
 324                case 6:
 325                        tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH;
 326                        break;
 327                default:
 328                        return -EINVAL;
 329                }
 330
 331                snd_soc_component_update_bits(component, PCM186X_TDM_TX_SEL,
 332                                    PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
 333
 334                /* In DSP/TDM mode, the LRCLK divider must be 256 */
 335                div_lrck = 256;
 336
 337                /* Configure 1/256 duty cycle for LRCK */
 338                snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
 339                                    PCM186X_PCM_CFG_TDM_LRCK_MODE,
 340                                    PCM186X_PCM_CFG_TDM_LRCK_MODE);
 341        }
 342
 343        /* Only configure clock dividers in master mode. */
 344        if (priv->is_master_mode) {
 345                div_bck = priv->sysclk / (div_lrck * rate);
 346
 347                dev_dbg(component->dev,
 348                        "%s() master_clk=%u div_bck=%u div_lrck=%u\n",
 349                        __func__, priv->sysclk, div_bck, div_lrck);
 350
 351                snd_soc_component_write(component, PCM186X_BCK_DIV, div_bck - 1);
 352                snd_soc_component_write(component, PCM186X_LRK_DIV, div_lrck - 1);
 353        }
 354
 355        return 0;
 356}
 357
 358static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
 359{
 360        struct snd_soc_component *component = dai->component;
 361        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 362        u8 clk_ctrl = 0;
 363        u8 pcm_cfg = 0;
 364
 365        dev_dbg(component->dev, "%s() format=0x%x\n", __func__, format);
 366
 367        /* set master/slave audio interface */
 368        switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
 369        case SND_SOC_DAIFMT_CBM_CFM:
 370                if (!priv->sysclk) {
 371                        dev_err(component->dev, "operating in master mode requires sysclock to be configured\n");
 372                        return -EINVAL;
 373                }
 374                clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
 375                priv->is_master_mode = true;
 376                break;
 377        case SND_SOC_DAIFMT_CBS_CFS:
 378                priv->is_master_mode = false;
 379                break;
 380        default:
 381                dev_err(component->dev, "Invalid DAI master/slave interface\n");
 382                return -EINVAL;
 383        }
 384
 385        /* set interface polarity */
 386        switch (format & SND_SOC_DAIFMT_INV_MASK) {
 387        case SND_SOC_DAIFMT_NB_NF:
 388                break;
 389        default:
 390                dev_err(component->dev, "Inverted DAI clocks not supported\n");
 391                return -EINVAL;
 392        }
 393
 394        /* set interface format */
 395        switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
 396        case SND_SOC_DAIFMT_I2S:
 397                pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
 398                break;
 399        case SND_SOC_DAIFMT_LEFT_J:
 400                pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
 401                break;
 402        case SND_SOC_DAIFMT_DSP_A:
 403                priv->tdm_offset += 1;
 404                fallthrough;
 405                /* DSP_A uses the same basic config as DSP_B
 406                 * except we need to shift the TDM output by one BCK cycle
 407                 */
 408        case SND_SOC_DAIFMT_DSP_B:
 409                priv->is_tdm_mode = true;
 410                pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
 411                break;
 412        default:
 413                dev_err(component->dev, "Invalid DAI format\n");
 414                return -EINVAL;
 415        }
 416
 417        snd_soc_component_update_bits(component, PCM186X_CLK_CTRL,
 418                            PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
 419
 420        snd_soc_component_write(component, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
 421
 422        snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
 423                            PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
 424
 425        return 0;
 426}
 427
 428static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 429                                unsigned int rx_mask, int slots, int slot_width)
 430{
 431        struct snd_soc_component *component = dai->component;
 432        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 433        unsigned int first_slot, last_slot, tdm_offset;
 434
 435        dev_dbg(component->dev,
 436                "%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
 437                __func__, tx_mask, rx_mask, slots, slot_width);
 438
 439        if (!tx_mask) {
 440                dev_err(component->dev, "tdm tx mask must not be 0\n");
 441                return -EINVAL;
 442        }
 443
 444        first_slot = __ffs(tx_mask);
 445        last_slot = __fls(tx_mask);
 446
 447        if (last_slot - first_slot != hweight32(tx_mask) - 1) {
 448                dev_err(component->dev, "tdm tx mask must be contiguous\n");
 449                return -EINVAL;
 450        }
 451
 452        tdm_offset = first_slot * slot_width;
 453
 454        if (tdm_offset > 255) {
 455                dev_err(component->dev, "tdm tx slot selection out of bounds\n");
 456                return -EINVAL;
 457        }
 458
 459        priv->tdm_offset = tdm_offset;
 460
 461        return 0;
 462}
 463
 464static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 465                                  unsigned int freq, int dir)
 466{
 467        struct snd_soc_component *component = dai->component;
 468        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 469
 470        dev_dbg(component->dev, "%s() clk_id=%d freq=%u dir=%d\n",
 471                __func__, clk_id, freq, dir);
 472
 473        priv->sysclk = freq;
 474
 475        return 0;
 476}
 477
 478static const struct snd_soc_dai_ops pcm186x_dai_ops = {
 479        .set_sysclk = pcm186x_set_dai_sysclk,
 480        .set_tdm_slot = pcm186x_set_tdm_slot,
 481        .set_fmt = pcm186x_set_fmt,
 482        .hw_params = pcm186x_hw_params,
 483};
 484
 485static struct snd_soc_dai_driver pcm1863_dai = {
 486        .name = "pcm1863-aif",
 487        .capture = {
 488                 .stream_name = "Capture",
 489                 .channels_min = 1,
 490                 .channels_max = 2,
 491                 .rates = PCM186X_RATES,
 492                 .formats = PCM186X_FORMATS,
 493         },
 494        .ops = &pcm186x_dai_ops,
 495};
 496
 497static struct snd_soc_dai_driver pcm1865_dai = {
 498        .name = "pcm1865-aif",
 499        .capture = {
 500                 .stream_name = "Capture",
 501                 .channels_min = 1,
 502                 .channels_max = 4,
 503                 .rates = PCM186X_RATES,
 504                 .formats = PCM186X_FORMATS,
 505         },
 506        .ops = &pcm186x_dai_ops,
 507};
 508
 509static int pcm186x_power_on(struct snd_soc_component *component)
 510{
 511        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 512        int ret = 0;
 513
 514        ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
 515                                    priv->supplies);
 516        if (ret)
 517                return ret;
 518
 519        regcache_cache_only(priv->regmap, false);
 520        ret = regcache_sync(priv->regmap);
 521        if (ret) {
 522                dev_err(component->dev, "Failed to restore cache\n");
 523                regcache_cache_only(priv->regmap, true);
 524                regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
 525                                       priv->supplies);
 526                return ret;
 527        }
 528
 529        snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
 530                            PCM186X_PWR_CTRL_PWRDN, 0);
 531
 532        return 0;
 533}
 534
 535static int pcm186x_power_off(struct snd_soc_component *component)
 536{
 537        struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
 538        int ret;
 539
 540        snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
 541                            PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
 542
 543        regcache_cache_only(priv->regmap, true);
 544
 545        ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
 546                                     priv->supplies);
 547        if (ret)
 548                return ret;
 549
 550        return 0;
 551}
 552
 553static int pcm186x_set_bias_level(struct snd_soc_component *component,
 554                                  enum snd_soc_bias_level level)
 555{
 556        dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
 557                snd_soc_component_get_bias_level(component), level);
 558
 559        switch (level) {
 560        case SND_SOC_BIAS_ON:
 561                break;
 562        case SND_SOC_BIAS_PREPARE:
 563                break;
 564        case SND_SOC_BIAS_STANDBY:
 565                if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
 566                        pcm186x_power_on(component);
 567                break;
 568        case SND_SOC_BIAS_OFF:
 569                pcm186x_power_off(component);
 570                break;
 571        }
 572
 573        return 0;
 574}
 575
 576static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
 577        .set_bias_level         = pcm186x_set_bias_level,
 578        .controls               = pcm1863_snd_controls,
 579        .num_controls           = ARRAY_SIZE(pcm1863_snd_controls),
 580        .dapm_widgets           = pcm1863_dapm_widgets,
 581        .num_dapm_widgets       = ARRAY_SIZE(pcm1863_dapm_widgets),
 582        .dapm_routes            = pcm1863_dapm_routes,
 583        .num_dapm_routes        = ARRAY_SIZE(pcm1863_dapm_routes),
 584        .idle_bias_on           = 1,
 585        .use_pmdown_time        = 1,
 586        .endianness             = 1,
 587        .non_legacy_dai_naming  = 1,
 588};
 589
 590static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
 591        .set_bias_level         = pcm186x_set_bias_level,
 592        .controls               = pcm1865_snd_controls,
 593        .num_controls           = ARRAY_SIZE(pcm1865_snd_controls),
 594        .dapm_widgets           = pcm1865_dapm_widgets,
 595        .num_dapm_widgets       = ARRAY_SIZE(pcm1865_dapm_widgets),
 596        .dapm_routes            = pcm1865_dapm_routes,
 597        .num_dapm_routes        = ARRAY_SIZE(pcm1865_dapm_routes),
 598        .suspend_bias_off       = 1,
 599        .idle_bias_on           = 1,
 600        .use_pmdown_time        = 1,
 601        .endianness             = 1,
 602        .non_legacy_dai_naming  = 1,
 603};
 604
 605static bool pcm186x_volatile(struct device *dev, unsigned int reg)
 606{
 607        switch (reg) {
 608        case PCM186X_PAGE:
 609        case PCM186X_DEVICE_STATUS:
 610        case PCM186X_FSAMPLE_STATUS:
 611        case PCM186X_DIV_STATUS:
 612        case PCM186X_CLK_STATUS:
 613        case PCM186X_SUPPLY_STATUS:
 614        case PCM186X_MMAP_STAT_CTRL:
 615        case PCM186X_MMAP_ADDRESS:
 616                return true;
 617        }
 618
 619        return false;
 620}
 621
 622static const struct regmap_range_cfg pcm186x_range = {
 623        .name = "Pages",
 624        .range_max = PCM186X_MAX_REGISTER,
 625        .selector_reg = PCM186X_PAGE,
 626        .selector_mask = 0xff,
 627        .window_len = PCM186X_PAGE_LEN,
 628};
 629
 630const struct regmap_config pcm186x_regmap = {
 631        .reg_bits = 8,
 632        .val_bits = 8,
 633
 634        .volatile_reg = pcm186x_volatile,
 635
 636        .ranges = &pcm186x_range,
 637        .num_ranges = 1,
 638
 639        .max_register = PCM186X_MAX_REGISTER,
 640
 641        .cache_type = REGCACHE_RBTREE,
 642};
 643EXPORT_SYMBOL_GPL(pcm186x_regmap);
 644
 645int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
 646                  struct regmap *regmap)
 647{
 648        struct pcm186x_priv *priv;
 649        int i, ret;
 650
 651        priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
 652        if (!priv)
 653                return -ENOMEM;
 654
 655        dev_set_drvdata(dev, priv);
 656        priv->regmap = regmap;
 657
 658        for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
 659                priv->supplies[i].supply = pcm186x_supply_names[i];
 660
 661        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
 662                                      priv->supplies);
 663        if (ret) {
 664                dev_err(dev, "failed to request supplies: %d\n", ret);
 665                return ret;
 666        }
 667
 668        ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
 669                                    priv->supplies);
 670        if (ret) {
 671                dev_err(dev, "failed enable supplies: %d\n", ret);
 672                return ret;
 673        }
 674
 675        /* Reset device registers for a consistent power-on like state */
 676        ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
 677        if (ret) {
 678                dev_err(dev, "failed to write device: %d\n", ret);
 679                return ret;
 680        }
 681
 682        ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
 683                                     priv->supplies);
 684        if (ret) {
 685                dev_err(dev, "failed disable supplies: %d\n", ret);
 686                return ret;
 687        }
 688
 689        switch (type) {
 690        case PCM1865:
 691        case PCM1864:
 692                ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1865,
 693                                             &pcm1865_dai, 1);
 694                break;
 695        case PCM1863:
 696        case PCM1862:
 697        default:
 698                ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1863,
 699                                             &pcm1863_dai, 1);
 700        }
 701        if (ret) {
 702                dev_err(dev, "failed to register CODEC: %d\n", ret);
 703                return ret;
 704        }
 705
 706        return 0;
 707}
 708EXPORT_SYMBOL_GPL(pcm186x_probe);
 709
 710MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
 711MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
 712MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
 713MODULE_LICENSE("GPL v2");
 714