root/sound/soc/codecs/pcm186x.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcm186x_hw_params
  2. pcm186x_set_fmt
  3. pcm186x_set_tdm_slot
  4. pcm186x_set_dai_sysclk
  5. pcm186x_power_on
  6. pcm186x_power_off
  7. pcm186x_set_bias_level
  8. pcm186x_volatile
  9. pcm186x_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Texas Instruments PCM186x Universal Audio ADC
   4  *
   5  * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://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 
  29 static 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 
  36 struct 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 
  45 static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 50, 0);
  46 
  47 static 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 
  53 static 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 
  62 static 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 
  68 static 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 
  90 static 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 
 112 static 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 
 135 static 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 
 142 static 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 
 164 static 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 
 191 static 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 
 215 static 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 
 261 static 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 
 358 static 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                 /* fall through */
 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 
 428 static 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 
 464 static 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 
 478 static 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 
 485 static 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 
 497 static 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 
 509 static 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 
 535 static 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 
 553 static 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 
 576 static 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 
 590 static 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 
 605 static 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 
 622 static 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 
 630 const 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 };
 643 EXPORT_SYMBOL_GPL(pcm186x_regmap);
 644 
 645 int 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 }
 708 EXPORT_SYMBOL_GPL(pcm186x_probe);
 709 
 710 MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
 711 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
 712 MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
 713 MODULE_LICENSE("GPL v2");

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