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

cs35l32.c (15195B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * cs35l32.c -- CS35L32 ALSA SoC audio driver
      4 *
      5 * Copyright 2014 CirrusLogic, Inc.
      6 *
      7 * Author: Brian Austin <brian.austin@cirrus.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/moduleparam.h>
     12#include <linux/kernel.h>
     13#include <linux/init.h>
     14#include <linux/delay.h>
     15#include <linux/i2c.h>
     16#include <linux/gpio.h>
     17#include <linux/regmap.h>
     18#include <linux/slab.h>
     19#include <linux/platform_device.h>
     20#include <linux/regulator/consumer.h>
     21#include <linux/gpio/consumer.h>
     22#include <linux/of_device.h>
     23#include <sound/core.h>
     24#include <sound/pcm.h>
     25#include <sound/pcm_params.h>
     26#include <sound/soc.h>
     27#include <sound/soc-dapm.h>
     28#include <sound/initval.h>
     29#include <sound/tlv.h>
     30#include <dt-bindings/sound/cs35l32.h>
     31
     32#include "cs35l32.h"
     33#include "cirrus_legacy.h"
     34
     35#define CS35L32_NUM_SUPPLIES 2
     36static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
     37	"VA",
     38	"VP",
     39};
     40
     41struct  cs35l32_private {
     42	struct regmap *regmap;
     43	struct snd_soc_component *component;
     44	struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
     45	struct cs35l32_platform_data pdata;
     46	struct gpio_desc *reset_gpio;
     47};
     48
     49static const struct reg_default cs35l32_reg_defaults[] = {
     50
     51	{ 0x06, 0x04 }, /* Power Ctl 1 */
     52	{ 0x07, 0xE8 }, /* Power Ctl 2 */
     53	{ 0x08, 0x40 }, /* Clock Ctl */
     54	{ 0x09, 0x20 }, /* Low Battery Threshold */
     55	{ 0x0A, 0x00 }, /* Voltage Monitor [RO] */
     56	{ 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
     57	{ 0x0C, 0x07 }, /* IMON Scaling */
     58	{ 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
     59	{ 0x0F, 0x20 }, /* Serial Port Control */
     60	{ 0x10, 0x14 }, /* Class D Amp CTL */
     61	{ 0x11, 0x00 }, /* Protection Release CTL */
     62	{ 0x12, 0xFF }, /* Interrupt Mask 1 */
     63	{ 0x13, 0xFF }, /* Interrupt Mask 2 */
     64	{ 0x14, 0xFF }, /* Interrupt Mask 3 */
     65	{ 0x19, 0x00 }, /* LED Flash Mode Current */
     66	{ 0x1A, 0x00 }, /* LED Movie Mode Current */
     67	{ 0x1B, 0x20 }, /* LED Flash Timer */
     68	{ 0x1C, 0x00 }, /* LED Flash Inhibit Current */
     69};
     70
     71static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
     72{
     73	switch (reg) {
     74	case CS35L32_DEVID_AB ... CS35L32_AUDIO_LED_MNGR:
     75	case CS35L32_ADSP_CTL ... CS35L32_FLASH_INHIBIT:
     76		return true;
     77	default:
     78		return false;
     79	}
     80}
     81
     82static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
     83{
     84	switch (reg) {
     85	case CS35L32_DEVID_AB ... CS35L32_REV_ID:
     86	case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
     87		return true;
     88	default:
     89		return false;
     90	}
     91}
     92
     93static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
     94{
     95	switch (reg) {
     96	case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
     97		return true;
     98	default:
     99		return false;
    100	}
    101}
    102
    103static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
    104
    105static const struct snd_kcontrol_new imon_ctl =
    106	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
    107
    108static const struct snd_kcontrol_new vmon_ctl =
    109	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
    110
    111static const struct snd_kcontrol_new vpmon_ctl =
    112	SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
    113
    114static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
    115	SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
    116		       3, 0x04, 1, classd_ctl_tlv),
    117	SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
    118	SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
    119};
    120
    121static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
    122
    123	SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
    124	SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
    125
    126	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
    127
    128	SND_SOC_DAPM_INPUT("VP"),
    129	SND_SOC_DAPM_INPUT("ISENSE"),
    130	SND_SOC_DAPM_INPUT("VSENSE"),
    131
    132	SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
    133	SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
    134	SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
    135};
    136
    137static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
    138
    139	{"Speaker", NULL, "BOOST"},
    140
    141	{"VMON ADC", NULL, "VSENSE"},
    142	{"IMON ADC", NULL, "ISENSE"},
    143	{"VPMON ADC", NULL, "VP"},
    144
    145	{"SDOUT", "Switch", "VMON ADC"},
    146	{"SDOUT",  "Switch", "IMON ADC"},
    147	{"SDOUT", "Switch", "VPMON ADC"},
    148
    149	{"Capture", NULL, "SDOUT"},
    150};
    151
    152static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
    153{
    154	struct snd_soc_component *component = codec_dai->component;
    155
    156	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    157	case SND_SOC_DAIFMT_CBM_CFM:
    158		snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
    159				    CS35L32_ADSP_MASTER_MASK,
    160				CS35L32_ADSP_MASTER_MASK);
    161		break;
    162	case SND_SOC_DAIFMT_CBS_CFS:
    163		snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
    164				    CS35L32_ADSP_MASTER_MASK, 0);
    165		break;
    166	default:
    167		return -EINVAL;
    168	}
    169
    170	return 0;
    171}
    172
    173static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
    174{
    175	struct snd_soc_component *component = dai->component;
    176
    177	return snd_soc_component_update_bits(component, CS35L32_PWRCTL2,
    178					CS35L32_SDOUT_3ST, tristate << 3);
    179}
    180
    181static const struct snd_soc_dai_ops cs35l32_ops = {
    182	.set_fmt = cs35l32_set_dai_fmt,
    183	.set_tristate = cs35l32_set_tristate,
    184};
    185
    186static struct snd_soc_dai_driver cs35l32_dai[] = {
    187	{
    188		.name = "cs35l32-monitor",
    189		.id = 0,
    190		.capture = {
    191			.stream_name = "Capture",
    192			.channels_min = 2,
    193			.channels_max = 2,
    194			.rates = CS35L32_RATES,
    195			.formats = CS35L32_FORMATS,
    196		},
    197		.ops = &cs35l32_ops,
    198		.symmetric_rate = 1,
    199	}
    200};
    201
    202static int cs35l32_component_set_sysclk(struct snd_soc_component *component,
    203			      int clk_id, int source, unsigned int freq, int dir)
    204{
    205	unsigned int val;
    206
    207	switch (freq) {
    208	case 6000000:
    209		val = CS35L32_MCLK_RATIO;
    210		break;
    211	case 12000000:
    212		val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
    213		break;
    214	case 6144000:
    215		val = 0;
    216		break;
    217	case 12288000:
    218		val = CS35L32_MCLK_DIV2_MASK;
    219		break;
    220	default:
    221		return -EINVAL;
    222	}
    223
    224	return snd_soc_component_update_bits(component, CS35L32_CLK_CTL,
    225			CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
    226}
    227
    228static const struct snd_soc_component_driver soc_component_dev_cs35l32 = {
    229	.set_sysclk		= cs35l32_component_set_sysclk,
    230	.controls		= cs35l32_snd_controls,
    231	.num_controls		= ARRAY_SIZE(cs35l32_snd_controls),
    232	.dapm_widgets		= cs35l32_dapm_widgets,
    233	.num_dapm_widgets	= ARRAY_SIZE(cs35l32_dapm_widgets),
    234	.dapm_routes		= cs35l32_audio_map,
    235	.num_dapm_routes	= ARRAY_SIZE(cs35l32_audio_map),
    236	.idle_bias_on		= 1,
    237	.use_pmdown_time	= 1,
    238	.endianness		= 1,
    239	.non_legacy_dai_naming	= 1,
    240};
    241
    242/* Current and threshold powerup sequence Pg37 in datasheet */
    243static const struct reg_sequence cs35l32_monitor_patch[] = {
    244
    245	{ 0x00, 0x99 },
    246	{ 0x48, 0x17 },
    247	{ 0x49, 0x56 },
    248	{ 0x43, 0x01 },
    249	{ 0x3B, 0x62 },
    250	{ 0x3C, 0x80 },
    251	{ 0x00, 0x00 },
    252};
    253
    254static const struct regmap_config cs35l32_regmap = {
    255	.reg_bits = 8,
    256	.val_bits = 8,
    257
    258	.max_register = CS35L32_MAX_REGISTER,
    259	.reg_defaults = cs35l32_reg_defaults,
    260	.num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
    261	.volatile_reg = cs35l32_volatile_register,
    262	.readable_reg = cs35l32_readable_register,
    263	.precious_reg = cs35l32_precious_register,
    264	.cache_type = REGCACHE_RBTREE,
    265
    266	.use_single_read = true,
    267	.use_single_write = true,
    268};
    269
    270static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
    271				    struct cs35l32_platform_data *pdata)
    272{
    273	struct device_node *np = i2c_client->dev.of_node;
    274	unsigned int val;
    275
    276	if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
    277		pdata->sdout_share = val;
    278
    279	if (of_property_read_u32(np, "cirrus,boost-manager", &val))
    280		val = -1u;
    281
    282	switch (val) {
    283	case CS35L32_BOOST_MGR_AUTO:
    284	case CS35L32_BOOST_MGR_AUTO_AUDIO:
    285	case CS35L32_BOOST_MGR_BYPASS:
    286	case CS35L32_BOOST_MGR_FIXED:
    287		pdata->boost_mng = val;
    288		break;
    289	case -1u:
    290	default:
    291		dev_err(&i2c_client->dev,
    292			"Wrong cirrus,boost-manager DT value %d\n", val);
    293		pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
    294	}
    295
    296	if (of_property_read_u32(np, "cirrus,sdout-datacfg", &val))
    297		val = -1u;
    298	switch (val) {
    299	case CS35L32_DATA_CFG_LR_VP:
    300	case CS35L32_DATA_CFG_LR_STAT:
    301	case CS35L32_DATA_CFG_LR:
    302	case CS35L32_DATA_CFG_LR_VPSTAT:
    303		pdata->sdout_datacfg = val;
    304		break;
    305	case -1u:
    306	default:
    307		dev_err(&i2c_client->dev,
    308			"Wrong cirrus,sdout-datacfg DT value %d\n", val);
    309		pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
    310	}
    311
    312	if (of_property_read_u32(np, "cirrus,battery-threshold", &val))
    313		val = -1u;
    314	switch (val) {
    315	case CS35L32_BATT_THRESH_3_1V:
    316	case CS35L32_BATT_THRESH_3_2V:
    317	case CS35L32_BATT_THRESH_3_3V:
    318	case CS35L32_BATT_THRESH_3_4V:
    319		pdata->batt_thresh = val;
    320		break;
    321	case -1u:
    322	default:
    323		dev_err(&i2c_client->dev,
    324			"Wrong cirrus,battery-threshold DT value %d\n", val);
    325		pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
    326	}
    327
    328	if (of_property_read_u32(np, "cirrus,battery-recovery", &val))
    329		val = -1u;
    330	switch (val) {
    331	case CS35L32_BATT_RECOV_3_1V:
    332	case CS35L32_BATT_RECOV_3_2V:
    333	case CS35L32_BATT_RECOV_3_3V:
    334	case CS35L32_BATT_RECOV_3_4V:
    335	case CS35L32_BATT_RECOV_3_5V:
    336	case CS35L32_BATT_RECOV_3_6V:
    337		pdata->batt_recov = val;
    338		break;
    339	case -1u:
    340	default:
    341		dev_err(&i2c_client->dev,
    342			"Wrong cirrus,battery-recovery DT value %d\n", val);
    343		pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
    344	}
    345
    346	return 0;
    347}
    348
    349static int cs35l32_i2c_probe(struct i2c_client *i2c_client)
    350{
    351	struct cs35l32_private *cs35l32;
    352	struct cs35l32_platform_data *pdata =
    353		dev_get_platdata(&i2c_client->dev);
    354	int ret, i, devid;
    355	unsigned int reg;
    356
    357	cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l32), GFP_KERNEL);
    358	if (!cs35l32)
    359		return -ENOMEM;
    360
    361	i2c_set_clientdata(i2c_client, cs35l32);
    362
    363	cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
    364	if (IS_ERR(cs35l32->regmap)) {
    365		ret = PTR_ERR(cs35l32->regmap);
    366		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
    367		return ret;
    368	}
    369
    370	if (pdata) {
    371		cs35l32->pdata = *pdata;
    372	} else {
    373		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
    374				     GFP_KERNEL);
    375		if (!pdata)
    376			return -ENOMEM;
    377
    378		if (i2c_client->dev.of_node) {
    379			ret = cs35l32_handle_of_data(i2c_client,
    380						     &cs35l32->pdata);
    381			if (ret != 0)
    382				return ret;
    383		}
    384	}
    385
    386	for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
    387		cs35l32->supplies[i].supply = cs35l32_supply_names[i];
    388
    389	ret = devm_regulator_bulk_get(&i2c_client->dev,
    390				      ARRAY_SIZE(cs35l32->supplies),
    391				      cs35l32->supplies);
    392	if (ret != 0) {
    393		dev_err(&i2c_client->dev,
    394			"Failed to request supplies: %d\n", ret);
    395		return ret;
    396	}
    397
    398	ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
    399				    cs35l32->supplies);
    400	if (ret != 0) {
    401		dev_err(&i2c_client->dev,
    402			"Failed to enable supplies: %d\n", ret);
    403		return ret;
    404	}
    405
    406	/* Reset the Device */
    407	cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
    408		"reset", GPIOD_OUT_LOW);
    409	if (IS_ERR(cs35l32->reset_gpio)) {
    410		ret = PTR_ERR(cs35l32->reset_gpio);
    411		goto err_supplies;
    412	}
    413
    414	gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
    415
    416	/* initialize codec */
    417	devid = cirrus_read_device_id(cs35l32->regmap, CS35L32_DEVID_AB);
    418	if (devid < 0) {
    419		ret = devid;
    420		dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret);
    421		goto err_disable;
    422	}
    423
    424	if (devid != CS35L32_CHIP_ID) {
    425		ret = -ENODEV;
    426		dev_err(&i2c_client->dev,
    427			"CS35L32 Device ID (%X). Expected %X\n",
    428			devid, CS35L32_CHIP_ID);
    429		goto err_disable;
    430	}
    431
    432	ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, &reg);
    433	if (ret < 0) {
    434		dev_err(&i2c_client->dev, "Get Revision ID failed\n");
    435		goto err_disable;
    436	}
    437
    438	ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
    439				    ARRAY_SIZE(cs35l32_monitor_patch));
    440	if (ret < 0) {
    441		dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
    442		goto err_disable;
    443	}
    444
    445	dev_info(&i2c_client->dev,
    446		 "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
    447
    448	/* Setup VBOOST Management */
    449	if (cs35l32->pdata.boost_mng)
    450		regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
    451				   CS35L32_BOOST_MASK,
    452				cs35l32->pdata.boost_mng);
    453
    454	/* Setup ADSP Format Config */
    455	if (cs35l32->pdata.sdout_share)
    456		regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
    457				    CS35L32_ADSP_SHARE_MASK,
    458				cs35l32->pdata.sdout_share << 3);
    459
    460	/* Setup ADSP Data Configuration */
    461	if (cs35l32->pdata.sdout_datacfg)
    462		regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
    463				   CS35L32_ADSP_DATACFG_MASK,
    464				cs35l32->pdata.sdout_datacfg << 4);
    465
    466	/* Setup Low Battery Recovery  */
    467	if (cs35l32->pdata.batt_recov)
    468		regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
    469				   CS35L32_BATT_REC_MASK,
    470				cs35l32->pdata.batt_recov << 1);
    471
    472	/* Setup Low Battery Threshold */
    473	if (cs35l32->pdata.batt_thresh)
    474		regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
    475				   CS35L32_BATT_THRESH_MASK,
    476				cs35l32->pdata.batt_thresh << 4);
    477
    478	/* Power down the AMP */
    479	regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
    480			    CS35L32_PDN_AMP);
    481
    482	/* Clear MCLK Error Bit since we don't have the clock yet */
    483	regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
    484
    485	ret = devm_snd_soc_register_component(&i2c_client->dev,
    486			&soc_component_dev_cs35l32, cs35l32_dai,
    487			ARRAY_SIZE(cs35l32_dai));
    488	if (ret < 0)
    489		goto err_disable;
    490
    491	return 0;
    492
    493err_disable:
    494	gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
    495err_supplies:
    496	regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
    497			       cs35l32->supplies);
    498	return ret;
    499}
    500
    501static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
    502{
    503	struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
    504
    505	/* Hold down reset */
    506	gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
    507
    508	return 0;
    509}
    510
    511#ifdef CONFIG_PM
    512static int cs35l32_runtime_suspend(struct device *dev)
    513{
    514	struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
    515
    516	regcache_cache_only(cs35l32->regmap, true);
    517	regcache_mark_dirty(cs35l32->regmap);
    518
    519	/* Hold down reset */
    520	gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
    521
    522	/* remove power */
    523	regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
    524			       cs35l32->supplies);
    525
    526	return 0;
    527}
    528
    529static int cs35l32_runtime_resume(struct device *dev)
    530{
    531	struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
    532	int ret;
    533
    534	/* Enable power */
    535	ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
    536				    cs35l32->supplies);
    537	if (ret != 0) {
    538		dev_err(dev, "Failed to enable supplies: %d\n",
    539			ret);
    540		return ret;
    541	}
    542
    543	gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
    544
    545	regcache_cache_only(cs35l32->regmap, false);
    546	regcache_sync(cs35l32->regmap);
    547
    548	return 0;
    549}
    550#endif
    551
    552static const struct dev_pm_ops cs35l32_runtime_pm = {
    553	SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
    554			   NULL)
    555};
    556
    557static const struct of_device_id cs35l32_of_match[] = {
    558	{ .compatible = "cirrus,cs35l32", },
    559	{},
    560};
    561MODULE_DEVICE_TABLE(of, cs35l32_of_match);
    562
    563
    564static const struct i2c_device_id cs35l32_id[] = {
    565	{"cs35l32", 0},
    566	{}
    567};
    568
    569MODULE_DEVICE_TABLE(i2c, cs35l32_id);
    570
    571static struct i2c_driver cs35l32_i2c_driver = {
    572	.driver = {
    573		   .name = "cs35l32",
    574		   .pm = &cs35l32_runtime_pm,
    575		   .of_match_table = cs35l32_of_match,
    576		   },
    577	.id_table = cs35l32_id,
    578	.probe_new = cs35l32_i2c_probe,
    579	.remove = cs35l32_i2c_remove,
    580};
    581
    582module_i2c_driver(cs35l32_i2c_driver);
    583
    584MODULE_DESCRIPTION("ASoC CS35L32 driver");
    585MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
    586MODULE_LICENSE("GPL");