Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * cs35l32.c -- CS35L32 ALSA SoC audio driver
0004  *
0005  * Copyright 2014 CirrusLogic, Inc.
0006  *
0007  * Author: Brian Austin <brian.austin@cirrus.com>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/kernel.h>
0013 #include <linux/init.h>
0014 #include <linux/delay.h>
0015 #include <linux/i2c.h>
0016 #include <linux/gpio.h>
0017 #include <linux/regmap.h>
0018 #include <linux/slab.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regulator/consumer.h>
0021 #include <linux/gpio/consumer.h>
0022 #include <linux/of_device.h>
0023 #include <sound/core.h>
0024 #include <sound/pcm.h>
0025 #include <sound/pcm_params.h>
0026 #include <sound/soc.h>
0027 #include <sound/soc-dapm.h>
0028 #include <sound/initval.h>
0029 #include <sound/tlv.h>
0030 #include <dt-bindings/sound/cs35l32.h>
0031 
0032 #include "cs35l32.h"
0033 #include "cirrus_legacy.h"
0034 
0035 #define CS35L32_NUM_SUPPLIES 2
0036 static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
0037     "VA",
0038     "VP",
0039 };
0040 
0041 struct  cs35l32_private {
0042     struct regmap *regmap;
0043     struct snd_soc_component *component;
0044     struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
0045     struct cs35l32_platform_data pdata;
0046     struct gpio_desc *reset_gpio;
0047 };
0048 
0049 static const struct reg_default cs35l32_reg_defaults[] = {
0050 
0051     { 0x06, 0x04 }, /* Power Ctl 1 */
0052     { 0x07, 0xE8 }, /* Power Ctl 2 */
0053     { 0x08, 0x40 }, /* Clock Ctl */
0054     { 0x09, 0x20 }, /* Low Battery Threshold */
0055     { 0x0A, 0x00 }, /* Voltage Monitor [RO] */
0056     { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
0057     { 0x0C, 0x07 }, /* IMON Scaling */
0058     { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
0059     { 0x0F, 0x20 }, /* Serial Port Control */
0060     { 0x10, 0x14 }, /* Class D Amp CTL */
0061     { 0x11, 0x00 }, /* Protection Release CTL */
0062     { 0x12, 0xFF }, /* Interrupt Mask 1 */
0063     { 0x13, 0xFF }, /* Interrupt Mask 2 */
0064     { 0x14, 0xFF }, /* Interrupt Mask 3 */
0065     { 0x19, 0x00 }, /* LED Flash Mode Current */
0066     { 0x1A, 0x00 }, /* LED Movie Mode Current */
0067     { 0x1B, 0x20 }, /* LED Flash Timer */
0068     { 0x1C, 0x00 }, /* LED Flash Inhibit Current */
0069 };
0070 
0071 static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
0072 {
0073     switch (reg) {
0074     case CS35L32_DEVID_AB ... CS35L32_AUDIO_LED_MNGR:
0075     case CS35L32_ADSP_CTL ... CS35L32_FLASH_INHIBIT:
0076         return true;
0077     default:
0078         return false;
0079     }
0080 }
0081 
0082 static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
0083 {
0084     switch (reg) {
0085     case CS35L32_DEVID_AB ... CS35L32_REV_ID:
0086     case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
0087         return true;
0088     default:
0089         return false;
0090     }
0091 }
0092 
0093 static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
0094 {
0095     switch (reg) {
0096     case CS35L32_INT_STATUS_1 ... CS35L32_LED_STATUS:
0097         return true;
0098     default:
0099         return false;
0100     }
0101 }
0102 
0103 static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
0104 
0105 static const struct snd_kcontrol_new imon_ctl =
0106     SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
0107 
0108 static const struct snd_kcontrol_new vmon_ctl =
0109     SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
0110 
0111 static const struct snd_kcontrol_new vpmon_ctl =
0112     SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
0113 
0114 static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
0115     SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
0116                3, 0x04, 1, classd_ctl_tlv),
0117     SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
0118     SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
0119 };
0120 
0121 static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
0122 
0123     SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
0124     SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
0125 
0126     SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
0127 
0128     SND_SOC_DAPM_INPUT("VP"),
0129     SND_SOC_DAPM_INPUT("ISENSE"),
0130     SND_SOC_DAPM_INPUT("VSENSE"),
0131 
0132     SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
0133     SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
0134     SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
0135 };
0136 
0137 static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
0138 
0139     {"Speaker", NULL, "BOOST"},
0140 
0141     {"VMON ADC", NULL, "VSENSE"},
0142     {"IMON ADC", NULL, "ISENSE"},
0143     {"VPMON ADC", NULL, "VP"},
0144 
0145     {"SDOUT", "Switch", "VMON ADC"},
0146     {"SDOUT",  "Switch", "IMON ADC"},
0147     {"SDOUT", "Switch", "VPMON ADC"},
0148 
0149     {"Capture", NULL, "SDOUT"},
0150 };
0151 
0152 static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
0153 {
0154     struct snd_soc_component *component = codec_dai->component;
0155 
0156     switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
0157     case SND_SOC_DAIFMT_CBM_CFM:
0158         snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
0159                     CS35L32_ADSP_MASTER_MASK,
0160                 CS35L32_ADSP_MASTER_MASK);
0161         break;
0162     case SND_SOC_DAIFMT_CBS_CFS:
0163         snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
0164                     CS35L32_ADSP_MASTER_MASK, 0);
0165         break;
0166     default:
0167         return -EINVAL;
0168     }
0169 
0170     return 0;
0171 }
0172 
0173 static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
0174 {
0175     struct snd_soc_component *component = dai->component;
0176 
0177     return snd_soc_component_update_bits(component, CS35L32_PWRCTL2,
0178                     CS35L32_SDOUT_3ST, tristate << 3);
0179 }
0180 
0181 static const struct snd_soc_dai_ops cs35l32_ops = {
0182     .set_fmt = cs35l32_set_dai_fmt,
0183     .set_tristate = cs35l32_set_tristate,
0184 };
0185 
0186 static struct snd_soc_dai_driver cs35l32_dai[] = {
0187     {
0188         .name = "cs35l32-monitor",
0189         .id = 0,
0190         .capture = {
0191             .stream_name = "Capture",
0192             .channels_min = 2,
0193             .channels_max = 2,
0194             .rates = CS35L32_RATES,
0195             .formats = CS35L32_FORMATS,
0196         },
0197         .ops = &cs35l32_ops,
0198         .symmetric_rate = 1,
0199     }
0200 };
0201 
0202 static int cs35l32_component_set_sysclk(struct snd_soc_component *component,
0203                   int clk_id, int source, unsigned int freq, int dir)
0204 {
0205     unsigned int val;
0206 
0207     switch (freq) {
0208     case 6000000:
0209         val = CS35L32_MCLK_RATIO;
0210         break;
0211     case 12000000:
0212         val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
0213         break;
0214     case 6144000:
0215         val = 0;
0216         break;
0217     case 12288000:
0218         val = CS35L32_MCLK_DIV2_MASK;
0219         break;
0220     default:
0221         return -EINVAL;
0222     }
0223 
0224     return snd_soc_component_update_bits(component, CS35L32_CLK_CTL,
0225             CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
0226 }
0227 
0228 static const struct snd_soc_component_driver soc_component_dev_cs35l32 = {
0229     .set_sysclk     = cs35l32_component_set_sysclk,
0230     .controls       = cs35l32_snd_controls,
0231     .num_controls       = ARRAY_SIZE(cs35l32_snd_controls),
0232     .dapm_widgets       = cs35l32_dapm_widgets,
0233     .num_dapm_widgets   = ARRAY_SIZE(cs35l32_dapm_widgets),
0234     .dapm_routes        = cs35l32_audio_map,
0235     .num_dapm_routes    = ARRAY_SIZE(cs35l32_audio_map),
0236     .idle_bias_on       = 1,
0237     .use_pmdown_time    = 1,
0238     .endianness     = 1,
0239 };
0240 
0241 /* Current and threshold powerup sequence Pg37 in datasheet */
0242 static const struct reg_sequence cs35l32_monitor_patch[] = {
0243 
0244     { 0x00, 0x99 },
0245     { 0x48, 0x17 },
0246     { 0x49, 0x56 },
0247     { 0x43, 0x01 },
0248     { 0x3B, 0x62 },
0249     { 0x3C, 0x80 },
0250     { 0x00, 0x00 },
0251 };
0252 
0253 static const struct regmap_config cs35l32_regmap = {
0254     .reg_bits = 8,
0255     .val_bits = 8,
0256 
0257     .max_register = CS35L32_MAX_REGISTER,
0258     .reg_defaults = cs35l32_reg_defaults,
0259     .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
0260     .volatile_reg = cs35l32_volatile_register,
0261     .readable_reg = cs35l32_readable_register,
0262     .precious_reg = cs35l32_precious_register,
0263     .cache_type = REGCACHE_RBTREE,
0264 
0265     .use_single_read = true,
0266     .use_single_write = true,
0267 };
0268 
0269 static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
0270                     struct cs35l32_platform_data *pdata)
0271 {
0272     struct device_node *np = i2c_client->dev.of_node;
0273     unsigned int val;
0274 
0275     if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
0276         pdata->sdout_share = val;
0277 
0278     if (of_property_read_u32(np, "cirrus,boost-manager", &val))
0279         val = -1u;
0280 
0281     switch (val) {
0282     case CS35L32_BOOST_MGR_AUTO:
0283     case CS35L32_BOOST_MGR_AUTO_AUDIO:
0284     case CS35L32_BOOST_MGR_BYPASS:
0285     case CS35L32_BOOST_MGR_FIXED:
0286         pdata->boost_mng = val;
0287         break;
0288     case -1u:
0289     default:
0290         dev_err(&i2c_client->dev,
0291             "Wrong cirrus,boost-manager DT value %d\n", val);
0292         pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
0293     }
0294 
0295     if (of_property_read_u32(np, "cirrus,sdout-datacfg", &val))
0296         val = -1u;
0297     switch (val) {
0298     case CS35L32_DATA_CFG_LR_VP:
0299     case CS35L32_DATA_CFG_LR_STAT:
0300     case CS35L32_DATA_CFG_LR:
0301     case CS35L32_DATA_CFG_LR_VPSTAT:
0302         pdata->sdout_datacfg = val;
0303         break;
0304     case -1u:
0305     default:
0306         dev_err(&i2c_client->dev,
0307             "Wrong cirrus,sdout-datacfg DT value %d\n", val);
0308         pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
0309     }
0310 
0311     if (of_property_read_u32(np, "cirrus,battery-threshold", &val))
0312         val = -1u;
0313     switch (val) {
0314     case CS35L32_BATT_THRESH_3_1V:
0315     case CS35L32_BATT_THRESH_3_2V:
0316     case CS35L32_BATT_THRESH_3_3V:
0317     case CS35L32_BATT_THRESH_3_4V:
0318         pdata->batt_thresh = val;
0319         break;
0320     case -1u:
0321     default:
0322         dev_err(&i2c_client->dev,
0323             "Wrong cirrus,battery-threshold DT value %d\n", val);
0324         pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
0325     }
0326 
0327     if (of_property_read_u32(np, "cirrus,battery-recovery", &val))
0328         val = -1u;
0329     switch (val) {
0330     case CS35L32_BATT_RECOV_3_1V:
0331     case CS35L32_BATT_RECOV_3_2V:
0332     case CS35L32_BATT_RECOV_3_3V:
0333     case CS35L32_BATT_RECOV_3_4V:
0334     case CS35L32_BATT_RECOV_3_5V:
0335     case CS35L32_BATT_RECOV_3_6V:
0336         pdata->batt_recov = val;
0337         break;
0338     case -1u:
0339     default:
0340         dev_err(&i2c_client->dev,
0341             "Wrong cirrus,battery-recovery DT value %d\n", val);
0342         pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
0343     }
0344 
0345     return 0;
0346 }
0347 
0348 static int cs35l32_i2c_probe(struct i2c_client *i2c_client)
0349 {
0350     struct cs35l32_private *cs35l32;
0351     struct cs35l32_platform_data *pdata =
0352         dev_get_platdata(&i2c_client->dev);
0353     int ret, i, devid;
0354     unsigned int reg;
0355 
0356     cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l32), GFP_KERNEL);
0357     if (!cs35l32)
0358         return -ENOMEM;
0359 
0360     i2c_set_clientdata(i2c_client, cs35l32);
0361 
0362     cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
0363     if (IS_ERR(cs35l32->regmap)) {
0364         ret = PTR_ERR(cs35l32->regmap);
0365         dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
0366         return ret;
0367     }
0368 
0369     if (pdata) {
0370         cs35l32->pdata = *pdata;
0371     } else {
0372         pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
0373                      GFP_KERNEL);
0374         if (!pdata)
0375             return -ENOMEM;
0376 
0377         if (i2c_client->dev.of_node) {
0378             ret = cs35l32_handle_of_data(i2c_client,
0379                              &cs35l32->pdata);
0380             if (ret != 0)
0381                 return ret;
0382         }
0383     }
0384 
0385     for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
0386         cs35l32->supplies[i].supply = cs35l32_supply_names[i];
0387 
0388     ret = devm_regulator_bulk_get(&i2c_client->dev,
0389                       ARRAY_SIZE(cs35l32->supplies),
0390                       cs35l32->supplies);
0391     if (ret != 0) {
0392         dev_err(&i2c_client->dev,
0393             "Failed to request supplies: %d\n", ret);
0394         return ret;
0395     }
0396 
0397     ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
0398                     cs35l32->supplies);
0399     if (ret != 0) {
0400         dev_err(&i2c_client->dev,
0401             "Failed to enable supplies: %d\n", ret);
0402         return ret;
0403     }
0404 
0405     /* Reset the Device */
0406     cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
0407         "reset", GPIOD_OUT_LOW);
0408     if (IS_ERR(cs35l32->reset_gpio)) {
0409         ret = PTR_ERR(cs35l32->reset_gpio);
0410         goto err_supplies;
0411     }
0412 
0413     gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
0414 
0415     /* initialize codec */
0416     devid = cirrus_read_device_id(cs35l32->regmap, CS35L32_DEVID_AB);
0417     if (devid < 0) {
0418         ret = devid;
0419         dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret);
0420         goto err_disable;
0421     }
0422 
0423     if (devid != CS35L32_CHIP_ID) {
0424         ret = -ENODEV;
0425         dev_err(&i2c_client->dev,
0426             "CS35L32 Device ID (%X). Expected %X\n",
0427             devid, CS35L32_CHIP_ID);
0428         goto err_disable;
0429     }
0430 
0431     ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, &reg);
0432     if (ret < 0) {
0433         dev_err(&i2c_client->dev, "Get Revision ID failed\n");
0434         goto err_disable;
0435     }
0436 
0437     ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
0438                     ARRAY_SIZE(cs35l32_monitor_patch));
0439     if (ret < 0) {
0440         dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
0441         goto err_disable;
0442     }
0443 
0444     dev_info(&i2c_client->dev,
0445          "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
0446 
0447     /* Setup VBOOST Management */
0448     if (cs35l32->pdata.boost_mng)
0449         regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
0450                    CS35L32_BOOST_MASK,
0451                 cs35l32->pdata.boost_mng);
0452 
0453     /* Setup ADSP Format Config */
0454     if (cs35l32->pdata.sdout_share)
0455         regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
0456                     CS35L32_ADSP_SHARE_MASK,
0457                 cs35l32->pdata.sdout_share << 3);
0458 
0459     /* Setup ADSP Data Configuration */
0460     if (cs35l32->pdata.sdout_datacfg)
0461         regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
0462                    CS35L32_ADSP_DATACFG_MASK,
0463                 cs35l32->pdata.sdout_datacfg << 4);
0464 
0465     /* Setup Low Battery Recovery  */
0466     if (cs35l32->pdata.batt_recov)
0467         regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
0468                    CS35L32_BATT_REC_MASK,
0469                 cs35l32->pdata.batt_recov << 1);
0470 
0471     /* Setup Low Battery Threshold */
0472     if (cs35l32->pdata.batt_thresh)
0473         regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
0474                    CS35L32_BATT_THRESH_MASK,
0475                 cs35l32->pdata.batt_thresh << 4);
0476 
0477     /* Power down the AMP */
0478     regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
0479                 CS35L32_PDN_AMP);
0480 
0481     /* Clear MCLK Error Bit since we don't have the clock yet */
0482     regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
0483 
0484     ret = devm_snd_soc_register_component(&i2c_client->dev,
0485             &soc_component_dev_cs35l32, cs35l32_dai,
0486             ARRAY_SIZE(cs35l32_dai));
0487     if (ret < 0)
0488         goto err_disable;
0489 
0490     return 0;
0491 
0492 err_disable:
0493     gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
0494 err_supplies:
0495     regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
0496                    cs35l32->supplies);
0497     return ret;
0498 }
0499 
0500 static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
0501 {
0502     struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
0503 
0504     /* Hold down reset */
0505     gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
0506 
0507     return 0;
0508 }
0509 
0510 #ifdef CONFIG_PM
0511 static int cs35l32_runtime_suspend(struct device *dev)
0512 {
0513     struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
0514 
0515     regcache_cache_only(cs35l32->regmap, true);
0516     regcache_mark_dirty(cs35l32->regmap);
0517 
0518     /* Hold down reset */
0519     gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
0520 
0521     /* remove power */
0522     regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
0523                    cs35l32->supplies);
0524 
0525     return 0;
0526 }
0527 
0528 static int cs35l32_runtime_resume(struct device *dev)
0529 {
0530     struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
0531     int ret;
0532 
0533     /* Enable power */
0534     ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
0535                     cs35l32->supplies);
0536     if (ret != 0) {
0537         dev_err(dev, "Failed to enable supplies: %d\n",
0538             ret);
0539         return ret;
0540     }
0541 
0542     gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
0543 
0544     regcache_cache_only(cs35l32->regmap, false);
0545     regcache_sync(cs35l32->regmap);
0546 
0547     return 0;
0548 }
0549 #endif
0550 
0551 static const struct dev_pm_ops cs35l32_runtime_pm = {
0552     SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
0553                NULL)
0554 };
0555 
0556 static const struct of_device_id cs35l32_of_match[] = {
0557     { .compatible = "cirrus,cs35l32", },
0558     {},
0559 };
0560 MODULE_DEVICE_TABLE(of, cs35l32_of_match);
0561 
0562 
0563 static const struct i2c_device_id cs35l32_id[] = {
0564     {"cs35l32", 0},
0565     {}
0566 };
0567 
0568 MODULE_DEVICE_TABLE(i2c, cs35l32_id);
0569 
0570 static struct i2c_driver cs35l32_i2c_driver = {
0571     .driver = {
0572            .name = "cs35l32",
0573            .pm = &cs35l32_runtime_pm,
0574            .of_match_table = cs35l32_of_match,
0575            },
0576     .id_table = cs35l32_id,
0577     .probe_new = cs35l32_i2c_probe,
0578     .remove = cs35l32_i2c_remove,
0579 };
0580 
0581 module_i2c_driver(cs35l32_i2c_driver);
0582 
0583 MODULE_DESCRIPTION("ASoC CS35L32 driver");
0584 MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
0585 MODULE_LICENSE("GPL");