brintos

brintos / linux-shallow public Read only

0
0
Text · 19.5 KiB · 9c44b62 Raw
680 lines · c
1/*2 * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver3 *4 * Copyright (C) 2014 Freescale Semiconductor, Inc.5 *6 * Author: Nicolin Chen <Guangyu.Chen@freescale.com>7 *8 * This file is licensed under the terms of the GNU General Public License9 * version 2. This program is licensed "as is" without any warranty of any10 * kind, whether express or implied.11 */12 13#include <linux/clk.h>14#include <linux/delay.h>15#include <linux/module.h>16#include <linux/gpio/consumer.h>17#include <linux/pm_runtime.h>18#include <linux/regulator/consumer.h>19#include <sound/pcm_params.h>20#include <sound/soc.h>21#include <sound/tlv.h>22 23#include "cs42xx8.h"24 25#define CS42XX8_NUM_SUPPLIES 426static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {27	"VA",28	"VD",29	"VLS",30	"VLC",31};32 33#define CS42XX8_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \34			 SNDRV_PCM_FMTBIT_S20_3LE | \35			 SNDRV_PCM_FMTBIT_S24_LE | \36			 SNDRV_PCM_FMTBIT_S32_LE)37 38/* codec private data */39struct cs42xx8_priv {40	struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];41	const struct cs42xx8_driver_data *drvdata;42	struct regmap *regmap;43	struct clk *clk;44 45	bool slave_mode;46	unsigned long sysclk;47	u32 tx_channels;48	struct gpio_desc *gpiod_reset;49	u32 rate[2];50};51 52/* -127.5dB to 0dB with step of 0.5dB */53static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);54/* -64dB to 24dB with step of 0.5dB */55static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);56 57static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };58static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",59					"Soft Ramp", "Soft Ramp on Zero Cross" };60 61static const struct soc_enum adc1_single_enum =62	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);63static const struct soc_enum adc2_single_enum =64	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);65static const struct soc_enum adc3_single_enum =66	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);67static const struct soc_enum dac_szc_enum =68	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);69static const struct soc_enum adc_szc_enum =70	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);71 72static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {73	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,74			 CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),75	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,76			 CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),77	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,78			 CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),79	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,80			 CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),81	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,82			   CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),83	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,84			   CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),85	SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),86	SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),87	SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),88	SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),89	SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),90	SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),91	SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),92	SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),93	SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),94	SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),95	SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),96	SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),97	SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),98	SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),99	SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),100	SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),101};102 103static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {104	SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,105			   CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),106	SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),107	SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),108};109 110static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {111	SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),112	SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),113	SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),114	SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),115 116	SND_SOC_DAPM_OUTPUT("AOUT1L"),117	SND_SOC_DAPM_OUTPUT("AOUT1R"),118	SND_SOC_DAPM_OUTPUT("AOUT2L"),119	SND_SOC_DAPM_OUTPUT("AOUT2R"),120	SND_SOC_DAPM_OUTPUT("AOUT3L"),121	SND_SOC_DAPM_OUTPUT("AOUT3R"),122	SND_SOC_DAPM_OUTPUT("AOUT4L"),123	SND_SOC_DAPM_OUTPUT("AOUT4R"),124 125	SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),126	SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),127 128	SND_SOC_DAPM_INPUT("AIN1L"),129	SND_SOC_DAPM_INPUT("AIN1R"),130	SND_SOC_DAPM_INPUT("AIN2L"),131	SND_SOC_DAPM_INPUT("AIN2R"),132 133	SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),134};135 136static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {137	SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),138 139	SND_SOC_DAPM_INPUT("AIN3L"),140	SND_SOC_DAPM_INPUT("AIN3R"),141};142 143static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {144	/* Playback */145	{ "AOUT1L", NULL, "DAC1" },146	{ "AOUT1R", NULL, "DAC1" },147	{ "DAC1", NULL, "PWR" },148 149	{ "AOUT2L", NULL, "DAC2" },150	{ "AOUT2R", NULL, "DAC2" },151	{ "DAC2", NULL, "PWR" },152 153	{ "AOUT3L", NULL, "DAC3" },154	{ "AOUT3R", NULL, "DAC3" },155	{ "DAC3", NULL, "PWR" },156 157	{ "AOUT4L", NULL, "DAC4" },158	{ "AOUT4R", NULL, "DAC4" },159	{ "DAC4", NULL, "PWR" },160 161	/* Capture */162	{ "ADC1", NULL, "AIN1L" },163	{ "ADC1", NULL, "AIN1R" },164	{ "ADC1", NULL, "PWR" },165 166	{ "ADC2", NULL, "AIN2L" },167	{ "ADC2", NULL, "AIN2R" },168	{ "ADC2", NULL, "PWR" },169};170 171static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {172	/* Capture */173	{ "ADC3", NULL, "AIN3L" },174	{ "ADC3", NULL, "AIN3R" },175	{ "ADC3", NULL, "PWR" },176};177 178struct cs42xx8_ratios {179	unsigned int mfreq;180	unsigned int min_mclk;181	unsigned int max_mclk;182	unsigned int ratio[3];183};184 185/*186 * According to reference mannual, define the cs42xx8_ratio struct187 * MFreq2 | MFreq1 | MFreq0 |     Description     | SSM | DSM | QSM |188 * 0      | 0      | 0      |1.029MHz to 12.8MHz  | 256 | 128 |  64 |189 * 0      | 0      | 1      |1.536MHz to 19.2MHz  | 384 | 192 |  96 |190 * 0      | 1      | 0      |2.048MHz to 25.6MHz  | 512 | 256 | 128 |191 * 0      | 1      | 1      |3.072MHz to 38.4MHz  | 768 | 384 | 192 |192 * 1      | x      | x      |4.096MHz to 51.2MHz  |1024 | 512 | 256 |193 */194static const struct cs42xx8_ratios cs42xx8_ratios[] = {195	{ 0, 1029000, 12800000, {256, 128, 64} },196	{ 2, 1536000, 19200000, {384, 192, 96} },197	{ 4, 2048000, 25600000, {512, 256, 128} },198	{ 6, 3072000, 38400000, {768, 384, 192} },199	{ 8, 4096000, 51200000, {1024, 512, 256} },200};201 202static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,203				  int clk_id, unsigned int freq, int dir)204{205	struct snd_soc_component *component = codec_dai->component;206	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);207 208	cs42xx8->sysclk = freq;209 210	return 0;211}212 213static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,214			       unsigned int format)215{216	struct snd_soc_component *component = codec_dai->component;217	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);218	u32 val;219 220	/* Set DAI format */221	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {222	case SND_SOC_DAIFMT_LEFT_J:223		val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;224		break;225	case SND_SOC_DAIFMT_I2S:226		val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;227		break;228	case SND_SOC_DAIFMT_RIGHT_J:229		val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;230		break;231	case SND_SOC_DAIFMT_DSP_A:232		val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;233		break;234	default:235		dev_err(component->dev, "unsupported dai format\n");236		return -EINVAL;237	}238 239	regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,240			   CS42XX8_INTF_DAC_DIF_MASK |241			   CS42XX8_INTF_ADC_DIF_MASK, val);242 243	/* Set master/slave audio interface */244	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {245	case SND_SOC_DAIFMT_CBS_CFS:246		cs42xx8->slave_mode = true;247		break;248	case SND_SOC_DAIFMT_CBM_CFM:249		cs42xx8->slave_mode = false;250		break;251	default:252		dev_err(component->dev, "unsupported master/slave mode\n");253		return -EINVAL;254	}255 256	return 0;257}258 259static int cs42xx8_hw_params(struct snd_pcm_substream *substream,260			     struct snd_pcm_hw_params *params,261			     struct snd_soc_dai *dai)262{263	struct snd_soc_component *component = dai->component;264	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);265	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;266	u32 ratio[2];267	u32 rate[2];268	u32 fm[2];269	u32 i, val, mask;270	bool condition1, condition2;271 272	if (tx)273		cs42xx8->tx_channels = params_channels(params);274 275	rate[tx]  = params_rate(params);276	rate[!tx] = cs42xx8->rate[!tx];277 278	ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;279	ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;280 281	/* Get functional mode for tx and rx according to rate */282	for (i = 0; i < 2; i++) {283		if (cs42xx8->slave_mode) {284			fm[i] = CS42XX8_FM_AUTO;285		} else {286			if (rate[i] < 50000) {287				fm[i] = CS42XX8_FM_SINGLE;288			} else if (rate[i] > 50000 && rate[i] < 100000) {289				fm[i] = CS42XX8_FM_DOUBLE;290			} else if (rate[i] > 100000 && rate[i] < 200000) {291				fm[i] = CS42XX8_FM_QUAD;292			} else {293				dev_err(component->dev,294					"unsupported sample rate\n");295				return -EINVAL;296			}297		}298	}299 300	for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {301		/* Is the ratio[tx] valid ? */302		condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?303			(cs42xx8_ratios[i].ratio[0] == ratio[tx] ||304			cs42xx8_ratios[i].ratio[1] == ratio[tx] ||305			cs42xx8_ratios[i].ratio[2] == ratio[tx]) :306			(cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&307			cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&308			cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;309 310		if (!ratio[tx])311			condition1 = true;312 313		/* Is the ratio[!tx] valid ? */314		condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?315			(cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||316			cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||317			cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :318			(cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));319 320		if (!ratio[!tx])321			condition2 = true;322 323		/*324		 * Both ratio[tx] and ratio[!tx] is valid, then we get325		 * a proper MFreq.326		 */327		if (condition1 && condition2)328			break;329	}330 331	if (i == ARRAY_SIZE(cs42xx8_ratios)) {332		dev_err(component->dev, "unsupported sysclk ratio\n");333		return -EINVAL;334	}335 336	cs42xx8->rate[tx] = params_rate(params);337 338	mask = CS42XX8_FUNCMOD_MFREQ_MASK;339	val = cs42xx8_ratios[i].mfreq;340 341	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,342			   CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,343			   CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);344 345	return 0;346}347 348static int cs42xx8_hw_free(struct snd_pcm_substream *substream,349			   struct snd_soc_dai *dai)350{351	struct snd_soc_component *component = dai->component;352	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);353	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;354 355	/* Clear stored rate */356	cs42xx8->rate[tx] = 0;357 358	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,359			   CS42XX8_FUNCMOD_xC_FM_MASK(tx),360			   CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));361	return 0;362}363 364static int cs42xx8_mute(struct snd_soc_dai *dai, int mute, int direction)365{366	struct snd_soc_component *component = dai->component;367	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);368	u8 dac_unmute = cs42xx8->tx_channels ?369		        ~((0x1 << cs42xx8->tx_channels) - 1) : 0;370 371	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,372		     mute ? CS42XX8_DACMUTE_ALL : dac_unmute);373 374	return 0;375}376 377static const struct snd_soc_dai_ops cs42xx8_dai_ops = {378	.set_fmt	= cs42xx8_set_dai_fmt,379	.set_sysclk	= cs42xx8_set_dai_sysclk,380	.hw_params	= cs42xx8_hw_params,381	.hw_free	= cs42xx8_hw_free,382	.mute_stream	= cs42xx8_mute,383	.no_capture_mute = 1,384};385 386static struct snd_soc_dai_driver cs42xx8_dai = {387	.playback = {388		.stream_name = "Playback",389		.channels_min = 1,390		.channels_max = 8,391		.rates = SNDRV_PCM_RATE_8000_192000,392		.formats = CS42XX8_FORMATS,393	},394	.capture = {395		.stream_name = "Capture",396		.channels_min = 1,397		.rates = SNDRV_PCM_RATE_8000_192000,398		.formats = CS42XX8_FORMATS,399	},400	.ops = &cs42xx8_dai_ops,401};402 403static const struct reg_default cs42xx8_reg[] = {404	{ 0x02, 0x00 },   /* Power Control */405	{ 0x03, 0xF0 },   /* Functional Mode */406	{ 0x04, 0x46 },   /* Interface Formats */407	{ 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */408	{ 0x06, 0x10 },   /* Transition Control */409	{ 0x07, 0x00 },   /* DAC Channel Mute */410	{ 0x08, 0x00 },   /* Volume Control AOUT1 */411	{ 0x09, 0x00 },   /* Volume Control AOUT2 */412	{ 0x0a, 0x00 },   /* Volume Control AOUT3 */413	{ 0x0b, 0x00 },   /* Volume Control AOUT4 */414	{ 0x0c, 0x00 },   /* Volume Control AOUT5 */415	{ 0x0d, 0x00 },   /* Volume Control AOUT6 */416	{ 0x0e, 0x00 },   /* Volume Control AOUT7 */417	{ 0x0f, 0x00 },   /* Volume Control AOUT8 */418	{ 0x10, 0x00 },   /* DAC Channel Invert */419	{ 0x11, 0x00 },   /* Volume Control AIN1 */420	{ 0x12, 0x00 },   /* Volume Control AIN2 */421	{ 0x13, 0x00 },   /* Volume Control AIN3 */422	{ 0x14, 0x00 },   /* Volume Control AIN4 */423	{ 0x15, 0x00 },   /* Volume Control AIN5 */424	{ 0x16, 0x00 },   /* Volume Control AIN6 */425	{ 0x17, 0x00 },   /* ADC Channel Invert */426	{ 0x18, 0x00 },   /* Status Control */427	{ 0x1a, 0x00 },   /* Status Mask */428	{ 0x1b, 0x00 },   /* MUTEC Pin Control */429};430 431static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)432{433	switch (reg) {434	case CS42XX8_STATUS:435		return true;436	default:437		return false;438	}439}440 441static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)442{443	switch (reg) {444	case CS42XX8_CHIPID:445	case CS42XX8_STATUS:446		return false;447	default:448		return true;449	}450}451 452const struct regmap_config cs42xx8_regmap_config = {453	.reg_bits = 8,454	.val_bits = 8,455 456	.max_register = CS42XX8_LASTREG,457	.reg_defaults = cs42xx8_reg,458	.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),459	.volatile_reg = cs42xx8_volatile_register,460	.writeable_reg = cs42xx8_writeable_register,461	.cache_type = REGCACHE_MAPLE,462};463EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);464 465static int cs42xx8_component_probe(struct snd_soc_component *component)466{467	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);468	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);469 470	switch (cs42xx8->drvdata->num_adcs) {471	case 3:472		snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,473					ARRAY_SIZE(cs42xx8_adc3_snd_controls));474		snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,475					ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));476		snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,477					ARRAY_SIZE(cs42xx8_adc3_dapm_routes));478		break;479	default:480		break;481	}482 483	/* Mute all DAC channels */484	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);485 486	return 0;487}488 489static const struct snd_soc_component_driver cs42xx8_driver = {490	.probe			= cs42xx8_component_probe,491	.controls		= cs42xx8_snd_controls,492	.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),493	.dapm_widgets		= cs42xx8_dapm_widgets,494	.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),495	.dapm_routes		= cs42xx8_dapm_routes,496	.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),497	.use_pmdown_time	= 1,498	.endianness		= 1,499};500 501const struct cs42xx8_driver_data cs42448_data = {502	.name = "cs42448",503	.num_adcs = 3,504};505EXPORT_SYMBOL_GPL(cs42448_data);506 507const struct cs42xx8_driver_data cs42888_data = {508	.name = "cs42888",509	.num_adcs = 2,510};511EXPORT_SYMBOL_GPL(cs42888_data);512 513int cs42xx8_probe(struct device *dev, struct regmap *regmap, struct cs42xx8_driver_data *drvdata)514{515	struct cs42xx8_priv *cs42xx8;516	int ret, val, i;517 518	if (IS_ERR(regmap)) {519		ret = PTR_ERR(regmap);520		dev_err(dev, "failed to allocate regmap: %d\n", ret);521		return ret;522	}523 524	cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);525	if (cs42xx8 == NULL)526		return -ENOMEM;527 528	dev_set_drvdata(dev, cs42xx8);529 530	cs42xx8->regmap = regmap;531 532	cs42xx8->drvdata = drvdata;533 534	cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",535							GPIOD_OUT_HIGH);536	if (IS_ERR(cs42xx8->gpiod_reset))537		return PTR_ERR(cs42xx8->gpiod_reset);538 539	gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);540 541	cs42xx8->clk = devm_clk_get(dev, "mclk");542	if (IS_ERR(cs42xx8->clk)) {543		dev_err(dev, "failed to get the clock: %ld\n",544				PTR_ERR(cs42xx8->clk));545		return -EINVAL;546	}547 548	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);549 550	for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)551		cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];552 553	ret = devm_regulator_bulk_get(dev,554			ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);555	if (ret) {556		dev_err(dev, "failed to request supplies: %d\n", ret);557		return ret;558	}559 560	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),561				    cs42xx8->supplies);562	if (ret) {563		dev_err(dev, "failed to enable supplies: %d\n", ret);564		return ret;565	}566 567	/* Make sure hardware reset done */568	msleep(5);569 570	/* Validate the chip ID */571	ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);572	if (ret < 0) {573		dev_err(dev, "failed to get device ID, ret = %d", ret);574		goto err_enable;575	}576 577	/* The top four bits of the chip ID should be 0000 */578	if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {579		dev_err(dev, "unmatched chip ID: %d\n",580			(val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);581		ret = -EINVAL;582		goto err_enable;583	}584 585	dev_info(dev, "found device, revision %X\n",586			val & CS42XX8_CHIPID_REV_ID_MASK);587 588	cs42xx8_dai.name = cs42xx8->drvdata->name;589 590	/* Each adc supports stereo input */591	cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;592 593	ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);594	if (ret) {595		dev_err(dev, "failed to register component:%d\n", ret);596		goto err_enable;597	}598 599	regcache_cache_only(cs42xx8->regmap, true);600 601err_enable:602	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),603			       cs42xx8->supplies);604 605	return ret;606}607EXPORT_SYMBOL_GPL(cs42xx8_probe);608 609#ifdef CONFIG_PM610static int cs42xx8_runtime_resume(struct device *dev)611{612	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);613	int ret;614 615	ret = clk_prepare_enable(cs42xx8->clk);616	if (ret) {617		dev_err(dev, "failed to enable mclk: %d\n", ret);618		return ret;619	}620 621	gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);622 623	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),624				    cs42xx8->supplies);625	if (ret) {626		dev_err(dev, "failed to enable supplies: %d\n", ret);627		goto err_clk;628	}629 630	/* Make sure hardware reset done */631	msleep(5);632 633	regcache_cache_only(cs42xx8->regmap, false);634	regcache_mark_dirty(cs42xx8->regmap);635 636	ret = regcache_sync(cs42xx8->regmap);637	if (ret) {638		dev_err(dev, "failed to sync regmap: %d\n", ret);639		goto err_bulk;640	}641 642	return 0;643 644err_bulk:645	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),646			       cs42xx8->supplies);647err_clk:648	clk_disable_unprepare(cs42xx8->clk);649 650	return ret;651}652 653static int cs42xx8_runtime_suspend(struct device *dev)654{655	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);656 657	regcache_cache_only(cs42xx8->regmap, true);658 659	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),660			       cs42xx8->supplies);661 662	gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);663 664	clk_disable_unprepare(cs42xx8->clk);665 666	return 0;667}668#endif669 670const struct dev_pm_ops cs42xx8_pm = {671	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,672				pm_runtime_force_resume)673	SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)674};675EXPORT_SYMBOL_GPL(cs42xx8_pm);676 677MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");678MODULE_AUTHOR("Freescale Semiconductor, Inc.");679MODULE_LICENSE("GPL");680