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

cs4265.c (17361B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * cs4265.c -- CS4265 ALSA SoC audio driver
      4 *
      5 * Copyright 2014 Cirrus Logic, Inc.
      6 *
      7 * Author: Paul Handrigan <paul.handrigan@cirrus.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/moduleparam.h>
     12#include <linux/kernel.h>
     13#include <linux/gpio/consumer.h>
     14#include <linux/init.h>
     15#include <linux/delay.h>
     16#include <linux/i2c.h>
     17#include <linux/input.h>
     18#include <linux/regmap.h>
     19#include <linux/slab.h>
     20#include <linux/platform_device.h>
     21#include <sound/core.h>
     22#include <sound/pcm.h>
     23#include <sound/pcm_params.h>
     24#include <sound/soc.h>
     25#include <sound/soc-dapm.h>
     26#include <sound/initval.h>
     27#include <sound/tlv.h>
     28#include "cs4265.h"
     29
     30struct cs4265_private {
     31	struct regmap *regmap;
     32	struct gpio_desc *reset_gpio;
     33	u8 format;
     34	u32 sysclk;
     35};
     36
     37static const struct reg_default cs4265_reg_defaults[] = {
     38	{ CS4265_PWRCTL, 0x0F },
     39	{ CS4265_DAC_CTL, 0x08 },
     40	{ CS4265_ADC_CTL, 0x00 },
     41	{ CS4265_MCLK_FREQ, 0x00 },
     42	{ CS4265_SIG_SEL, 0x40 },
     43	{ CS4265_CHB_PGA_CTL, 0x00 },
     44	{ CS4265_CHA_PGA_CTL, 0x00 },
     45	{ CS4265_ADC_CTL2, 0x19 },
     46	{ CS4265_DAC_CHA_VOL, 0x00 },
     47	{ CS4265_DAC_CHB_VOL, 0x00 },
     48	{ CS4265_DAC_CTL2, 0xC0 },
     49	{ CS4265_SPDIF_CTL1, 0x00 },
     50	{ CS4265_SPDIF_CTL2, 0x00 },
     51	{ CS4265_INT_MASK, 0x00 },
     52	{ CS4265_STATUS_MODE_MSB, 0x00 },
     53	{ CS4265_STATUS_MODE_LSB, 0x00 },
     54};
     55
     56static bool cs4265_readable_register(struct device *dev, unsigned int reg)
     57{
     58	switch (reg) {
     59	case CS4265_CHIP_ID ... CS4265_MAX_REGISTER:
     60		return true;
     61	default:
     62		return false;
     63	}
     64}
     65
     66static bool cs4265_volatile_register(struct device *dev, unsigned int reg)
     67{
     68	switch (reg) {
     69	case CS4265_INT_STATUS:
     70		return true;
     71	default:
     72		return false;
     73	}
     74}
     75
     76static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0);
     77
     78static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0);
     79
     80static const char * const digital_input_mux_text[] = {
     81	"SDIN1", "SDIN2"
     82};
     83
     84static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7,
     85		digital_input_mux_text);
     86
     87static const struct snd_kcontrol_new digital_input_mux =
     88	SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum);
     89
     90static const char * const mic_linein_text[] = {
     91	"MIC", "LINEIN"
     92};
     93
     94static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0,
     95		mic_linein_text);
     96
     97static const char * const cam_mode_text[] = {
     98	"One Byte", "Two Byte"
     99};
    100
    101static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5,
    102		cam_mode_text);
    103
    104static const char * const cam_mono_stereo_text[] = {
    105	"Stereo", "Mono"
    106};
    107
    108static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2,
    109		cam_mono_stereo_text);
    110
    111static const char * const mono_select_text[] = {
    112	"Channel A", "Channel B"
    113};
    114
    115static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0,
    116		mono_select_text);
    117
    118static const struct snd_kcontrol_new mic_linein_mux =
    119	SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum);
    120
    121static const struct snd_kcontrol_new loopback_ctl =
    122	SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0);
    123
    124static const struct snd_kcontrol_new spdif_switch =
    125	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0);
    126
    127static const struct snd_kcontrol_new dac_switch =
    128	SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0);
    129
    130static const struct snd_kcontrol_new cs4265_snd_controls[] = {
    131
    132	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL,
    133			      CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv),
    134	SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL,
    135		      CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv),
    136	SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1,
    137				1, 0),
    138	SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5,
    139				1, 0),
    140	SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6,
    141				1, 0),
    142	SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7,
    143				1, 0),
    144	SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1,
    145				1, 0),
    146	SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3,
    147				1, 1),
    148	SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7,
    149				1, 0),
    150	SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
    151				6, 1, 0),
    152	SOC_ENUM("C Data Access", cam_mode_enum),
    153	SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
    154				3, 1, 0),
    155	SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
    156	SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, 0, 1, 0),
    157	SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
    158	SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
    159};
    160
    161static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = {
    162
    163	SND_SOC_DAPM_INPUT("LINEINL"),
    164	SND_SOC_DAPM_INPUT("LINEINR"),
    165	SND_SOC_DAPM_INPUT("MICL"),
    166	SND_SOC_DAPM_INPUT("MICR"),
    167
    168	SND_SOC_DAPM_AIF_OUT("DOUT", NULL,  0,
    169			SND_SOC_NOPM, 0, 0),
    170	SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL,  0,
    171			SND_SOC_NOPM, 0, 0),
    172
    173	SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux),
    174
    175	SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1),
    176	SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3,
    177			1, NULL, 0),
    178
    179	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM,
    180			 0, 0, &digital_input_mux),
    181
    182	SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
    183	SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
    184	SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0),
    185
    186	SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0,
    187			&loopback_ctl),
    188	SND_SOC_DAPM_SWITCH("SPDIF", CS4265_SPDIF_CTL2, 5, 1,
    189			&spdif_switch),
    190	SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1,
    191			&dac_switch),
    192
    193	SND_SOC_DAPM_AIF_IN("DIN1", NULL,  0,
    194			SND_SOC_NOPM, 0, 0),
    195	SND_SOC_DAPM_AIF_IN("DIN2", NULL,  0,
    196			SND_SOC_NOPM, 0, 0),
    197	SND_SOC_DAPM_AIF_IN("TXIN", NULL,  0,
    198			CS4265_SPDIF_CTL2, 5, 1),
    199
    200	SND_SOC_DAPM_OUTPUT("LINEOUTL"),
    201	SND_SOC_DAPM_OUTPUT("LINEOUTR"),
    202
    203};
    204
    205static const struct snd_soc_dapm_route cs4265_audio_map[] = {
    206
    207	{"DIN1", NULL, "DAI1 Playback"},
    208	{"DIN2", NULL, "DAI2 Playback"},
    209	{"SDIN1 Input Mixer", NULL, "DIN1"},
    210	{"SDIN2 Input Mixer", NULL, "DIN2"},
    211	{"Input Mux", "SDIN1", "SDIN1 Input Mixer"},
    212	{"Input Mux", "SDIN2", "SDIN2 Input Mixer"},
    213	{"DAC", "Switch", "Input Mux"},
    214	{"SPDIF", "Switch", "Input Mux"},
    215	{"LINEOUTL", NULL, "DAC"},
    216	{"LINEOUTR", NULL, "DAC"},
    217	{"SPDIFOUT", NULL, "SPDIF"},
    218
    219	{"Pre-amp MIC", NULL, "MICL"},
    220	{"Pre-amp MIC", NULL, "MICR"},
    221	{"ADC Mux", "MIC", "Pre-amp MIC"},
    222	{"ADC Mux", "LINEIN", "LINEINL"},
    223	{"ADC Mux", "LINEIN", "LINEINR"},
    224	{"ADC", NULL, "ADC Mux"},
    225	{"DOUT", NULL, "ADC"},
    226	{"DAI1 Capture", NULL, "DOUT"},
    227	{"DAI2 Capture", NULL, "DOUT"},
    228
    229	/* Loopback */
    230	{"Loopback", "Switch", "ADC"},
    231	{"DAC", NULL, "Loopback"},
    232};
    233
    234struct cs4265_clk_para {
    235	u32 mclk;
    236	u32 rate;
    237	u8 fm_mode; /* values 1, 2, or 4 */
    238	u8 mclkdiv;
    239};
    240
    241static const struct cs4265_clk_para clk_map_table[] = {
    242	/*32k*/
    243	{8192000, 32000, 0, 0},
    244	{12288000, 32000, 0, 1},
    245	{16384000, 32000, 0, 2},
    246	{24576000, 32000, 0, 3},
    247	{32768000, 32000, 0, 4},
    248
    249	/*44.1k*/
    250	{11289600, 44100, 0, 0},
    251	{16934400, 44100, 0, 1},
    252	{22579200, 44100, 0, 2},
    253	{33868000, 44100, 0, 3},
    254	{45158400, 44100, 0, 4},
    255
    256	/*48k*/
    257	{12288000, 48000, 0, 0},
    258	{18432000, 48000, 0, 1},
    259	{24576000, 48000, 0, 2},
    260	{36864000, 48000, 0, 3},
    261	{49152000, 48000, 0, 4},
    262
    263	/*64k*/
    264	{8192000, 64000, 1, 0},
    265	{12288000, 64000, 1, 1},
    266	{16934400, 64000, 1, 2},
    267	{24576000, 64000, 1, 3},
    268	{32768000, 64000, 1, 4},
    269
    270	/* 88.2k */
    271	{11289600, 88200, 1, 0},
    272	{16934400, 88200, 1, 1},
    273	{22579200, 88200, 1, 2},
    274	{33868000, 88200, 1, 3},
    275	{45158400, 88200, 1, 4},
    276
    277	/* 96k */
    278	{12288000, 96000, 1, 0},
    279	{18432000, 96000, 1, 1},
    280	{24576000, 96000, 1, 2},
    281	{36864000, 96000, 1, 3},
    282	{49152000, 96000, 1, 4},
    283
    284	/* 128k */
    285	{8192000, 128000, 2, 0},
    286	{12288000, 128000, 2, 1},
    287	{16934400, 128000, 2, 2},
    288	{24576000, 128000, 2, 3},
    289	{32768000, 128000, 2, 4},
    290
    291	/* 176.4k */
    292	{11289600, 176400, 2, 0},
    293	{16934400, 176400, 2, 1},
    294	{22579200, 176400, 2, 2},
    295	{33868000, 176400, 2, 3},
    296	{49152000, 176400, 2, 4},
    297
    298	/* 192k */
    299	{12288000, 192000, 2, 0},
    300	{18432000, 192000, 2, 1},
    301	{24576000, 192000, 2, 2},
    302	{36864000, 192000, 2, 3},
    303	{49152000, 192000, 2, 4},
    304};
    305
    306static int cs4265_get_clk_index(int mclk, int rate)
    307{
    308	int i;
    309
    310	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
    311		if (clk_map_table[i].rate == rate &&
    312				clk_map_table[i].mclk == mclk)
    313			return i;
    314	}
    315	return -EINVAL;
    316}
    317
    318static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
    319			unsigned int freq, int dir)
    320{
    321	struct snd_soc_component *component = codec_dai->component;
    322	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
    323	int i;
    324
    325	if (clk_id != 0) {
    326		dev_err(component->dev, "Invalid clk_id %d\n", clk_id);
    327		return -EINVAL;
    328	}
    329	for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
    330		if (clk_map_table[i].mclk == freq) {
    331			cs4265->sysclk = freq;
    332			return 0;
    333		}
    334	}
    335	cs4265->sysclk = 0;
    336	dev_err(component->dev, "Invalid freq parameter %d\n", freq);
    337	return -EINVAL;
    338}
    339
    340static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    341{
    342	struct snd_soc_component *component = codec_dai->component;
    343	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
    344	u8 iface = 0;
    345
    346	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    347	case SND_SOC_DAIFMT_CBM_CFM:
    348		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
    349				CS4265_ADC_MASTER,
    350				CS4265_ADC_MASTER);
    351		break;
    352	case SND_SOC_DAIFMT_CBS_CFS:
    353		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
    354				CS4265_ADC_MASTER,
    355				0);
    356		break;
    357	default:
    358		return -EINVAL;
    359	}
    360
    361	 /* interface format */
    362	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    363	case SND_SOC_DAIFMT_I2S:
    364		iface |= SND_SOC_DAIFMT_I2S;
    365		break;
    366	case SND_SOC_DAIFMT_RIGHT_J:
    367		iface |= SND_SOC_DAIFMT_RIGHT_J;
    368		break;
    369	case SND_SOC_DAIFMT_LEFT_J:
    370		iface |= SND_SOC_DAIFMT_LEFT_J;
    371		break;
    372	default:
    373		return -EINVAL;
    374	}
    375
    376	cs4265->format = iface;
    377	return 0;
    378}
    379
    380static int cs4265_mute(struct snd_soc_dai *dai, int mute, int direction)
    381{
    382	struct snd_soc_component *component = dai->component;
    383
    384	if (mute) {
    385		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
    386			CS4265_DAC_CTL_MUTE,
    387			CS4265_DAC_CTL_MUTE);
    388		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
    389			CS4265_SPDIF_CTL2_MUTE,
    390			CS4265_SPDIF_CTL2_MUTE);
    391	} else {
    392		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
    393			CS4265_DAC_CTL_MUTE,
    394			0);
    395		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
    396			CS4265_SPDIF_CTL2_MUTE,
    397			0);
    398	}
    399	return 0;
    400}
    401
    402static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
    403				     struct snd_pcm_hw_params *params,
    404				     struct snd_soc_dai *dai)
    405{
    406	struct snd_soc_component *component = dai->component;
    407	struct cs4265_private *cs4265 = snd_soc_component_get_drvdata(component);
    408	int index;
    409
    410	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
    411		((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK)
    412		== SND_SOC_DAIFMT_RIGHT_J))
    413		return -EINVAL;
    414
    415	index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
    416	if (index >= 0) {
    417		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
    418			CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
    419		snd_soc_component_update_bits(component, CS4265_MCLK_FREQ,
    420			CS4265_MCLK_FREQ_MASK,
    421			clk_map_table[index].mclkdiv << 4);
    422
    423	} else {
    424		dev_err(component->dev, "can't get correct mclk\n");
    425		return -EINVAL;
    426	}
    427
    428	switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
    429	case SND_SOC_DAIFMT_I2S:
    430		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
    431			CS4265_DAC_CTL_DIF, (1 << 4));
    432		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
    433			CS4265_ADC_DIF, (1 << 4));
    434		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
    435			CS4265_SPDIF_CTL2_DIF, (1 << 6));
    436		break;
    437	case SND_SOC_DAIFMT_RIGHT_J:
    438		if (params_width(params) == 16) {
    439			snd_soc_component_update_bits(component, CS4265_DAC_CTL,
    440				CS4265_DAC_CTL_DIF, (2 << 4));
    441			snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
    442				CS4265_SPDIF_CTL2_DIF, (2 << 6));
    443		} else {
    444			snd_soc_component_update_bits(component, CS4265_DAC_CTL,
    445				CS4265_DAC_CTL_DIF, (3 << 4));
    446			snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
    447				CS4265_SPDIF_CTL2_DIF, (3 << 6));
    448		}
    449		break;
    450	case SND_SOC_DAIFMT_LEFT_J:
    451		snd_soc_component_update_bits(component, CS4265_DAC_CTL,
    452			CS4265_DAC_CTL_DIF, 0);
    453		snd_soc_component_update_bits(component, CS4265_ADC_CTL,
    454			CS4265_ADC_DIF, 0);
    455		snd_soc_component_update_bits(component, CS4265_SPDIF_CTL2,
    456			CS4265_SPDIF_CTL2_DIF, 0);
    457
    458		break;
    459	default:
    460		return -EINVAL;
    461	}
    462	return 0;
    463}
    464
    465static int cs4265_set_bias_level(struct snd_soc_component *component,
    466					enum snd_soc_bias_level level)
    467{
    468	switch (level) {
    469	case SND_SOC_BIAS_ON:
    470		break;
    471	case SND_SOC_BIAS_PREPARE:
    472		snd_soc_component_update_bits(component, CS4265_PWRCTL,
    473			CS4265_PWRCTL_PDN, 0);
    474		break;
    475	case SND_SOC_BIAS_STANDBY:
    476		snd_soc_component_update_bits(component, CS4265_PWRCTL,
    477			CS4265_PWRCTL_PDN,
    478			CS4265_PWRCTL_PDN);
    479		break;
    480	case SND_SOC_BIAS_OFF:
    481		snd_soc_component_update_bits(component, CS4265_PWRCTL,
    482			CS4265_PWRCTL_PDN,
    483			CS4265_PWRCTL_PDN);
    484		break;
    485	}
    486	return 0;
    487}
    488
    489#define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
    490			SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
    491			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
    492			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
    493
    494#define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
    495			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE | \
    496			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
    497
    498static const struct snd_soc_dai_ops cs4265_ops = {
    499	.hw_params	= cs4265_pcm_hw_params,
    500	.mute_stream	= cs4265_mute,
    501	.set_fmt	= cs4265_set_fmt,
    502	.set_sysclk	= cs4265_set_sysclk,
    503	.no_capture_mute = 1,
    504};
    505
    506static struct snd_soc_dai_driver cs4265_dai[] = {
    507	{
    508		.name = "cs4265-dai1",
    509		.playback = {
    510			.stream_name = "DAI1 Playback",
    511			.channels_min = 1,
    512			.channels_max = 2,
    513			.rates = CS4265_RATES,
    514			.formats = CS4265_FORMATS,
    515		},
    516		.capture = {
    517			.stream_name = "DAI1 Capture",
    518			.channels_min = 1,
    519			.channels_max = 2,
    520			.rates = CS4265_RATES,
    521			.formats = CS4265_FORMATS,
    522		},
    523		.ops = &cs4265_ops,
    524	},
    525	{
    526		.name = "cs4265-dai2",
    527		.playback = {
    528			.stream_name = "DAI2 Playback",
    529			.channels_min = 1,
    530			.channels_max = 2,
    531			.rates = CS4265_RATES,
    532			.formats = CS4265_FORMATS,
    533		},
    534		.capture = {
    535			.stream_name = "DAI2 Capture",
    536			.channels_min = 1,
    537			.channels_max = 2,
    538			.rates = CS4265_RATES,
    539			.formats = CS4265_FORMATS,
    540		},
    541		.ops = &cs4265_ops,
    542	},
    543};
    544
    545static const struct snd_soc_component_driver soc_component_cs4265 = {
    546	.set_bias_level		= cs4265_set_bias_level,
    547	.controls		= cs4265_snd_controls,
    548	.num_controls		= ARRAY_SIZE(cs4265_snd_controls),
    549	.dapm_widgets		= cs4265_dapm_widgets,
    550	.num_dapm_widgets	= ARRAY_SIZE(cs4265_dapm_widgets),
    551	.dapm_routes		= cs4265_audio_map,
    552	.num_dapm_routes	= ARRAY_SIZE(cs4265_audio_map),
    553	.idle_bias_on		= 1,
    554	.use_pmdown_time	= 1,
    555	.endianness		= 1,
    556	.non_legacy_dai_naming	= 1,
    557};
    558
    559static const struct regmap_config cs4265_regmap = {
    560	.reg_bits = 8,
    561	.val_bits = 8,
    562
    563	.max_register = CS4265_MAX_REGISTER,
    564	.reg_defaults = cs4265_reg_defaults,
    565	.num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
    566	.readable_reg = cs4265_readable_register,
    567	.volatile_reg = cs4265_volatile_register,
    568	.cache_type = REGCACHE_RBTREE,
    569};
    570
    571static int cs4265_i2c_probe(struct i2c_client *i2c_client)
    572{
    573	struct cs4265_private *cs4265;
    574	int ret;
    575	unsigned int devid = 0;
    576	unsigned int reg;
    577
    578	cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private),
    579			       GFP_KERNEL);
    580	if (cs4265 == NULL)
    581		return -ENOMEM;
    582
    583	cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
    584	if (IS_ERR(cs4265->regmap)) {
    585		ret = PTR_ERR(cs4265->regmap);
    586		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
    587		return ret;
    588	}
    589
    590	cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
    591		"reset", GPIOD_OUT_LOW);
    592	if (IS_ERR(cs4265->reset_gpio))
    593		return PTR_ERR(cs4265->reset_gpio);
    594
    595	if (cs4265->reset_gpio) {
    596		mdelay(1);
    597		gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
    598	}
    599
    600	i2c_set_clientdata(i2c_client, cs4265);
    601
    602	ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, &reg);
    603	if (ret) {
    604		dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret);
    605		return ret;
    606	}
    607
    608	devid = reg & CS4265_CHIP_ID_MASK;
    609	if (devid != CS4265_CHIP_ID_VAL) {
    610		ret = -ENODEV;
    611		dev_err(&i2c_client->dev,
    612			"CS4265 Part Number ID: 0x%x Expected: 0x%x\n",
    613			devid >> 4, CS4265_CHIP_ID_VAL >> 4);
    614		return ret;
    615	}
    616	dev_info(&i2c_client->dev,
    617		"CS4265 Version %x\n",
    618			reg & CS4265_REV_ID_MASK);
    619
    620	regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
    621
    622	return devm_snd_soc_register_component(&i2c_client->dev,
    623			&soc_component_cs4265, cs4265_dai,
    624			ARRAY_SIZE(cs4265_dai));
    625}
    626
    627static int cs4265_i2c_remove(struct i2c_client *i2c)
    628{
    629	struct cs4265_private *cs4265 = i2c_get_clientdata(i2c);
    630
    631	if (cs4265->reset_gpio)
    632		gpiod_set_value_cansleep(cs4265->reset_gpio, 0);
    633
    634	return 0;
    635}
    636
    637static const struct of_device_id cs4265_of_match[] = {
    638	{ .compatible = "cirrus,cs4265", },
    639	{ }
    640};
    641MODULE_DEVICE_TABLE(of, cs4265_of_match);
    642
    643static const struct i2c_device_id cs4265_id[] = {
    644	{ "cs4265", 0 },
    645	{ }
    646};
    647MODULE_DEVICE_TABLE(i2c, cs4265_id);
    648
    649static struct i2c_driver cs4265_i2c_driver = {
    650	.driver = {
    651		.name = "cs4265",
    652		.of_match_table = cs4265_of_match,
    653	},
    654	.id_table = cs4265_id,
    655	.probe_new = cs4265_i2c_probe,
    656	.remove =   cs4265_i2c_remove,
    657};
    658
    659module_i2c_driver(cs4265_i2c_driver);
    660
    661MODULE_DESCRIPTION("ASoC CS4265 driver");
    662MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>");
    663MODULE_LICENSE("GPL");