cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcm186x.c (20765B)


      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_provider_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 provider mode. */
    344	if (priv->is_provider_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	switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
    368	case SND_SOC_DAIFMT_CBP_CFP:
    369		if (!priv->sysclk) {
    370			dev_err(component->dev, "operating in provider mode requires sysclock to be configured\n");
    371			return -EINVAL;
    372		}
    373		clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
    374		priv->is_provider_mode = true;
    375		break;
    376	case SND_SOC_DAIFMT_CBC_CFC:
    377		priv->is_provider_mode = false;
    378		break;
    379	default:
    380		dev_err(component->dev, "Invalid DAI master/slave interface\n");
    381		return -EINVAL;
    382	}
    383
    384	/* set interface polarity */
    385	switch (format & SND_SOC_DAIFMT_INV_MASK) {
    386	case SND_SOC_DAIFMT_NB_NF:
    387		break;
    388	default:
    389		dev_err(component->dev, "Inverted DAI clocks not supported\n");
    390		return -EINVAL;
    391	}
    392
    393	/* set interface format */
    394	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
    395	case SND_SOC_DAIFMT_I2S:
    396		pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
    397		break;
    398	case SND_SOC_DAIFMT_LEFT_J:
    399		pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
    400		break;
    401	case SND_SOC_DAIFMT_DSP_A:
    402		priv->tdm_offset += 1;
    403		fallthrough;
    404		/* DSP_A uses the same basic config as DSP_B
    405		 * except we need to shift the TDM output by one BCK cycle
    406		 */
    407	case SND_SOC_DAIFMT_DSP_B:
    408		priv->is_tdm_mode = true;
    409		pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
    410		break;
    411	default:
    412		dev_err(component->dev, "Invalid DAI format\n");
    413		return -EINVAL;
    414	}
    415
    416	snd_soc_component_update_bits(component, PCM186X_CLK_CTRL,
    417			    PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
    418
    419	snd_soc_component_write(component, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
    420
    421	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
    422			    PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
    423
    424	return 0;
    425}
    426
    427static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
    428				unsigned int rx_mask, int slots, int slot_width)
    429{
    430	struct snd_soc_component *component = dai->component;
    431	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
    432	unsigned int first_slot, last_slot, tdm_offset;
    433
    434	dev_dbg(component->dev,
    435		"%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
    436		__func__, tx_mask, rx_mask, slots, slot_width);
    437
    438	if (!tx_mask) {
    439		dev_err(component->dev, "tdm tx mask must not be 0\n");
    440		return -EINVAL;
    441	}
    442
    443	first_slot = __ffs(tx_mask);
    444	last_slot = __fls(tx_mask);
    445
    446	if (last_slot - first_slot != hweight32(tx_mask) - 1) {
    447		dev_err(component->dev, "tdm tx mask must be contiguous\n");
    448		return -EINVAL;
    449	}
    450
    451	tdm_offset = first_slot * slot_width;
    452
    453	if (tdm_offset > 255) {
    454		dev_err(component->dev, "tdm tx slot selection out of bounds\n");
    455		return -EINVAL;
    456	}
    457
    458	priv->tdm_offset = tdm_offset;
    459
    460	return 0;
    461}
    462
    463static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
    464				  unsigned int freq, int dir)
    465{
    466	struct snd_soc_component *component = dai->component;
    467	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
    468
    469	dev_dbg(component->dev, "%s() clk_id=%d freq=%u dir=%d\n",
    470		__func__, clk_id, freq, dir);
    471
    472	priv->sysclk = freq;
    473
    474	return 0;
    475}
    476
    477static const struct snd_soc_dai_ops pcm186x_dai_ops = {
    478	.set_sysclk = pcm186x_set_dai_sysclk,
    479	.set_tdm_slot = pcm186x_set_tdm_slot,
    480	.set_fmt = pcm186x_set_fmt,
    481	.hw_params = pcm186x_hw_params,
    482};
    483
    484static struct snd_soc_dai_driver pcm1863_dai = {
    485	.name = "pcm1863-aif",
    486	.capture = {
    487		 .stream_name = "Capture",
    488		 .channels_min = 1,
    489		 .channels_max = 2,
    490		 .rates = PCM186X_RATES,
    491		 .formats = PCM186X_FORMATS,
    492	 },
    493	.ops = &pcm186x_dai_ops,
    494};
    495
    496static struct snd_soc_dai_driver pcm1865_dai = {
    497	.name = "pcm1865-aif",
    498	.capture = {
    499		 .stream_name = "Capture",
    500		 .channels_min = 1,
    501		 .channels_max = 4,
    502		 .rates = PCM186X_RATES,
    503		 .formats = PCM186X_FORMATS,
    504	 },
    505	.ops = &pcm186x_dai_ops,
    506};
    507
    508static int pcm186x_power_on(struct snd_soc_component *component)
    509{
    510	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
    511	int ret = 0;
    512
    513	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
    514				    priv->supplies);
    515	if (ret)
    516		return ret;
    517
    518	regcache_cache_only(priv->regmap, false);
    519	ret = regcache_sync(priv->regmap);
    520	if (ret) {
    521		dev_err(component->dev, "Failed to restore cache\n");
    522		regcache_cache_only(priv->regmap, true);
    523		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
    524				       priv->supplies);
    525		return ret;
    526	}
    527
    528	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
    529			    PCM186X_PWR_CTRL_PWRDN, 0);
    530
    531	return 0;
    532}
    533
    534static int pcm186x_power_off(struct snd_soc_component *component)
    535{
    536	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
    537
    538	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
    539			    PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
    540
    541	regcache_cache_only(priv->regmap, true);
    542
    543	return regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
    544				     priv->supplies);
    545}
    546
    547static int pcm186x_set_bias_level(struct snd_soc_component *component,
    548				  enum snd_soc_bias_level level)
    549{
    550	dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
    551		snd_soc_component_get_bias_level(component), level);
    552
    553	switch (level) {
    554	case SND_SOC_BIAS_ON:
    555		break;
    556	case SND_SOC_BIAS_PREPARE:
    557		break;
    558	case SND_SOC_BIAS_STANDBY:
    559		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
    560			pcm186x_power_on(component);
    561		break;
    562	case SND_SOC_BIAS_OFF:
    563		pcm186x_power_off(component);
    564		break;
    565	}
    566
    567	return 0;
    568}
    569
    570static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
    571	.set_bias_level		= pcm186x_set_bias_level,
    572	.controls		= pcm1863_snd_controls,
    573	.num_controls		= ARRAY_SIZE(pcm1863_snd_controls),
    574	.dapm_widgets		= pcm1863_dapm_widgets,
    575	.num_dapm_widgets	= ARRAY_SIZE(pcm1863_dapm_widgets),
    576	.dapm_routes		= pcm1863_dapm_routes,
    577	.num_dapm_routes	= ARRAY_SIZE(pcm1863_dapm_routes),
    578	.idle_bias_on		= 1,
    579	.use_pmdown_time	= 1,
    580	.endianness		= 1,
    581	.non_legacy_dai_naming	= 1,
    582};
    583
    584static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
    585	.set_bias_level		= pcm186x_set_bias_level,
    586	.controls		= pcm1865_snd_controls,
    587	.num_controls		= ARRAY_SIZE(pcm1865_snd_controls),
    588	.dapm_widgets		= pcm1865_dapm_widgets,
    589	.num_dapm_widgets	= ARRAY_SIZE(pcm1865_dapm_widgets),
    590	.dapm_routes		= pcm1865_dapm_routes,
    591	.num_dapm_routes	= ARRAY_SIZE(pcm1865_dapm_routes),
    592	.suspend_bias_off	= 1,
    593	.idle_bias_on		= 1,
    594	.use_pmdown_time	= 1,
    595	.endianness		= 1,
    596	.non_legacy_dai_naming	= 1,
    597};
    598
    599static bool pcm186x_volatile(struct device *dev, unsigned int reg)
    600{
    601	switch (reg) {
    602	case PCM186X_PAGE:
    603	case PCM186X_DEVICE_STATUS:
    604	case PCM186X_FSAMPLE_STATUS:
    605	case PCM186X_DIV_STATUS:
    606	case PCM186X_CLK_STATUS:
    607	case PCM186X_SUPPLY_STATUS:
    608	case PCM186X_MMAP_STAT_CTRL:
    609	case PCM186X_MMAP_ADDRESS:
    610		return true;
    611	}
    612
    613	return false;
    614}
    615
    616static const struct regmap_range_cfg pcm186x_range = {
    617	.name = "Pages",
    618	.range_max = PCM186X_MAX_REGISTER,
    619	.selector_reg = PCM186X_PAGE,
    620	.selector_mask = 0xff,
    621	.window_len = PCM186X_PAGE_LEN,
    622};
    623
    624const struct regmap_config pcm186x_regmap = {
    625	.reg_bits = 8,
    626	.val_bits = 8,
    627
    628	.volatile_reg = pcm186x_volatile,
    629
    630	.ranges = &pcm186x_range,
    631	.num_ranges = 1,
    632
    633	.max_register = PCM186X_MAX_REGISTER,
    634
    635	.cache_type = REGCACHE_RBTREE,
    636};
    637EXPORT_SYMBOL_GPL(pcm186x_regmap);
    638
    639int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
    640		  struct regmap *regmap)
    641{
    642	struct pcm186x_priv *priv;
    643	int i, ret;
    644
    645	priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
    646	if (!priv)
    647		return -ENOMEM;
    648
    649	dev_set_drvdata(dev, priv);
    650	priv->regmap = regmap;
    651
    652	for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
    653		priv->supplies[i].supply = pcm186x_supply_names[i];
    654
    655	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
    656				      priv->supplies);
    657	if (ret) {
    658		dev_err(dev, "failed to request supplies: %d\n", ret);
    659		return ret;
    660	}
    661
    662	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
    663				    priv->supplies);
    664	if (ret) {
    665		dev_err(dev, "failed enable supplies: %d\n", ret);
    666		return ret;
    667	}
    668
    669	/* Reset device registers for a consistent power-on like state */
    670	ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
    671	if (ret) {
    672		dev_err(dev, "failed to write device: %d\n", ret);
    673		return ret;
    674	}
    675
    676	ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
    677				     priv->supplies);
    678	if (ret) {
    679		dev_err(dev, "failed disable supplies: %d\n", ret);
    680		return ret;
    681	}
    682
    683	switch (type) {
    684	case PCM1865:
    685	case PCM1864:
    686		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1865,
    687					     &pcm1865_dai, 1);
    688		break;
    689	case PCM1863:
    690	case PCM1862:
    691	default:
    692		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1863,
    693					     &pcm1863_dai, 1);
    694	}
    695	if (ret) {
    696		dev_err(dev, "failed to register CODEC: %d\n", ret);
    697		return ret;
    698	}
    699
    700	return 0;
    701}
    702EXPORT_SYMBOL_GPL(pcm186x_probe);
    703
    704MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
    705MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
    706MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
    707MODULE_LICENSE("GPL v2");