18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cirrus Logic CS4341A ALSA SoC Codec Driver 48c2ecf20Sopenharmony_ci * Author: Alexander Shiyan <shc_work@mail.ru> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/i2c.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/regmap.h> 118c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <sound/pcm.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 158c2ecf20Sopenharmony_ci#include <sound/soc.h> 168c2ecf20Sopenharmony_ci#include <sound/tlv.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define CS4341_REG_MODE1 0x00 198c2ecf20Sopenharmony_ci#define CS4341_REG_MODE2 0x01 208c2ecf20Sopenharmony_ci#define CS4341_REG_MIX 0x02 218c2ecf20Sopenharmony_ci#define CS4341_REG_VOLA 0x03 228c2ecf20Sopenharmony_ci#define CS4341_REG_VOLB 0x04 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define CS4341_MODE2_DIF (7 << 4) 258c2ecf20Sopenharmony_ci#define CS4341_MODE2_DIF_I2S_24 (0 << 4) 268c2ecf20Sopenharmony_ci#define CS4341_MODE2_DIF_I2S_16 (1 << 4) 278c2ecf20Sopenharmony_ci#define CS4341_MODE2_DIF_LJ_24 (2 << 4) 288c2ecf20Sopenharmony_ci#define CS4341_MODE2_DIF_RJ_24 (3 << 4) 298c2ecf20Sopenharmony_ci#define CS4341_MODE2_DIF_RJ_16 (5 << 4) 308c2ecf20Sopenharmony_ci#define CS4341_VOLX_MUTE (1 << 7) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct cs4341_priv { 338c2ecf20Sopenharmony_ci unsigned int fmt; 348c2ecf20Sopenharmony_ci struct regmap *regmap; 358c2ecf20Sopenharmony_ci struct regmap_config regcfg; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const struct reg_default cs4341_reg_defaults[] = { 398c2ecf20Sopenharmony_ci { CS4341_REG_MODE1, 0x00 }, 408c2ecf20Sopenharmony_ci { CS4341_REG_MODE2, 0x82 }, 418c2ecf20Sopenharmony_ci { CS4341_REG_MIX, 0x49 }, 428c2ecf20Sopenharmony_ci { CS4341_REG_VOLA, 0x80 }, 438c2ecf20Sopenharmony_ci { CS4341_REG_VOLB, 0x80 }, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int cs4341_set_fmt(struct snd_soc_dai *dai, unsigned int format) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 498c2ecf20Sopenharmony_ci struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci switch (format & SND_SOC_DAIFMT_MASTER_MASK) { 528c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci default: 558c2ecf20Sopenharmony_ci return -EINVAL; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci switch (format & SND_SOC_DAIFMT_INV_MASK) { 598c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci default: 628c2ecf20Sopenharmony_ci return -EINVAL; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { 668c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 678c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 688c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 698c2ecf20Sopenharmony_ci cs4341->fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci default: 728c2ecf20Sopenharmony_ci return -EINVAL; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int cs4341_hw_params(struct snd_pcm_substream *substream, 798c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 808c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 838c2ecf20Sopenharmony_ci struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); 848c2ecf20Sopenharmony_ci unsigned int mode = 0; 858c2ecf20Sopenharmony_ci int b24 = 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci switch (params_format(params)) { 888c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 898c2ecf20Sopenharmony_ci b24 = 1; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci default: 948c2ecf20Sopenharmony_ci dev_err(component->dev, "Unsupported PCM format 0x%08x.\n", 958c2ecf20Sopenharmony_ci params_format(params)); 968c2ecf20Sopenharmony_ci return -EINVAL; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci switch (cs4341->fmt) { 1008c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 1018c2ecf20Sopenharmony_ci mode = b24 ? CS4341_MODE2_DIF_I2S_24 : CS4341_MODE2_DIF_I2S_16; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 1048c2ecf20Sopenharmony_ci mode = CS4341_MODE2_DIF_LJ_24; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 1078c2ecf20Sopenharmony_ci mode = b24 ? CS4341_MODE2_DIF_RJ_24 : CS4341_MODE2_DIF_RJ_16; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci default: 1108c2ecf20Sopenharmony_ci dev_err(component->dev, "Unsupported DAI format 0x%08x.\n", 1118c2ecf20Sopenharmony_ci cs4341->fmt); 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return snd_soc_component_update_bits(component, CS4341_REG_MODE2, 1168c2ecf20Sopenharmony_ci CS4341_MODE2_DIF, mode); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic int cs4341_mute(struct snd_soc_dai *dai, int mute, int direction) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 1228c2ecf20Sopenharmony_ci int ret; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, CS4341_REG_VOLA, 1258c2ecf20Sopenharmony_ci CS4341_VOLX_MUTE, 1268c2ecf20Sopenharmony_ci mute ? CS4341_VOLX_MUTE : 0); 1278c2ecf20Sopenharmony_ci if (ret < 0) 1288c2ecf20Sopenharmony_ci return ret; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return snd_soc_component_update_bits(component, CS4341_REG_VOLB, 1318c2ecf20Sopenharmony_ci CS4341_VOLX_MUTE, 1328c2ecf20Sopenharmony_ci mute ? CS4341_VOLX_MUTE : 0); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(out_tlv, -9000, 100, 0); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const char * const deemph[] = { 1388c2ecf20Sopenharmony_ci "None", "44.1k", "48k", "32k", 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const struct soc_enum deemph_enum = 1428c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS4341_REG_MODE2, 2, 4, deemph); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic const char * const srzc[] = { 1458c2ecf20Sopenharmony_ci "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC", 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const struct soc_enum srzc_enum = 1498c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS4341_REG_MIX, 5, 4, srzc); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget cs4341_dapm_widgets[] = { 1538c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0), 1548c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OutA"), 1558c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OutB"), 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route cs4341_routes[] = { 1598c2ecf20Sopenharmony_ci { "OutA", NULL, "HiFi DAC" }, 1608c2ecf20Sopenharmony_ci { "OutB", NULL, "HiFi DAC" }, 1618c2ecf20Sopenharmony_ci { "DAC Playback", NULL, "OutA" }, 1628c2ecf20Sopenharmony_ci { "DAC Playback", NULL, "OutB" }, 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cs4341_controls[] = { 1668c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Master Playback Volume", 1678c2ecf20Sopenharmony_ci CS4341_REG_VOLA, CS4341_REG_VOLB, 0, 90, 1, out_tlv), 1688c2ecf20Sopenharmony_ci SOC_ENUM("De-Emphasis Control", deemph_enum), 1698c2ecf20Sopenharmony_ci SOC_ENUM("Soft Ramp Zero Cross Control", srzc_enum), 1708c2ecf20Sopenharmony_ci SOC_SINGLE("Auto-Mute Switch", CS4341_REG_MODE2, 7, 1, 0), 1718c2ecf20Sopenharmony_ci SOC_SINGLE("Popguard Transient Switch", CS4341_REG_MODE2, 1, 1, 0), 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops cs4341_dai_ops = { 1758c2ecf20Sopenharmony_ci .set_fmt = cs4341_set_fmt, 1768c2ecf20Sopenharmony_ci .hw_params = cs4341_hw_params, 1778c2ecf20Sopenharmony_ci .mute_stream = cs4341_mute, 1788c2ecf20Sopenharmony_ci .no_capture_mute = 1, 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver cs4341_dai = { 1828c2ecf20Sopenharmony_ci .name = "cs4341a-hifi", 1838c2ecf20Sopenharmony_ci .playback = { 1848c2ecf20Sopenharmony_ci .stream_name = "DAC Playback", 1858c2ecf20Sopenharmony_ci .channels_min = 1, 1868c2ecf20Sopenharmony_ci .channels_max = 2, 1878c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 1888c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 1898c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE, 1908c2ecf20Sopenharmony_ci }, 1918c2ecf20Sopenharmony_ci .ops = &cs4341_dai_ops, 1928c2ecf20Sopenharmony_ci .symmetric_rates = 1, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_cs4341 = { 1968c2ecf20Sopenharmony_ci .controls = cs4341_controls, 1978c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(cs4341_controls), 1988c2ecf20Sopenharmony_ci .dapm_widgets = cs4341_dapm_widgets, 1998c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs4341_dapm_widgets), 2008c2ecf20Sopenharmony_ci .dapm_routes = cs4341_routes, 2018c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs4341_routes), 2028c2ecf20Sopenharmony_ci .idle_bias_on = 1, 2038c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 2048c2ecf20Sopenharmony_ci .endianness = 1, 2058c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused cs4341_dt_ids[] = { 2098c2ecf20Sopenharmony_ci { .compatible = "cirrus,cs4341a", }, 2108c2ecf20Sopenharmony_ci { } 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs4341_dt_ids); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int cs4341_probe(struct device *dev) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct cs4341_priv *cs4341 = dev_get_drvdata(dev); 2178c2ecf20Sopenharmony_ci int i; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs4341_reg_defaults); i++) 2208c2ecf20Sopenharmony_ci regmap_write(cs4341->regmap, cs4341_reg_defaults[i].reg, 2218c2ecf20Sopenharmony_ci cs4341_reg_defaults[i].def); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(dev, &soc_component_cs4341, 2248c2ecf20Sopenharmony_ci &cs4341_dai, 1); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 2288c2ecf20Sopenharmony_cistatic int cs4341_i2c_probe(struct i2c_client *i2c, 2298c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct cs4341_priv *cs4341; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci cs4341 = devm_kzalloc(&i2c->dev, sizeof(*cs4341), GFP_KERNEL); 2348c2ecf20Sopenharmony_ci if (!cs4341) 2358c2ecf20Sopenharmony_ci return -ENOMEM; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, cs4341); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci cs4341->regcfg.reg_bits = 8; 2408c2ecf20Sopenharmony_ci cs4341->regcfg.val_bits = 8; 2418c2ecf20Sopenharmony_ci cs4341->regcfg.max_register = CS4341_REG_VOLB; 2428c2ecf20Sopenharmony_ci cs4341->regcfg.cache_type = REGCACHE_FLAT; 2438c2ecf20Sopenharmony_ci cs4341->regcfg.reg_defaults = cs4341_reg_defaults; 2448c2ecf20Sopenharmony_ci cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults); 2458c2ecf20Sopenharmony_ci cs4341->regmap = devm_regmap_init_i2c(i2c, &cs4341->regcfg); 2468c2ecf20Sopenharmony_ci if (IS_ERR(cs4341->regmap)) 2478c2ecf20Sopenharmony_ci return PTR_ERR(cs4341->regmap); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return cs4341_probe(&i2c->dev); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic const struct i2c_device_id cs4341_i2c_id[] = { 2538c2ecf20Sopenharmony_ci { "cs4341", 0 }, 2548c2ecf20Sopenharmony_ci { } 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cs4341_i2c_id); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic struct i2c_driver cs4341_i2c_driver = { 2598c2ecf20Sopenharmony_ci .driver = { 2608c2ecf20Sopenharmony_ci .name = "cs4341-i2c", 2618c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(cs4341_dt_ids), 2628c2ecf20Sopenharmony_ci }, 2638c2ecf20Sopenharmony_ci .probe = cs4341_i2c_probe, 2648c2ecf20Sopenharmony_ci .id_table = cs4341_i2c_id, 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci#endif 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci#if defined(CONFIG_SPI_MASTER) 2698c2ecf20Sopenharmony_cistatic bool cs4341_reg_readable(struct device *dev, unsigned int reg) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci return false; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int cs4341_spi_probe(struct spi_device *spi) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct cs4341_priv *cs4341; 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci cs4341 = devm_kzalloc(&spi->dev, sizeof(*cs4341), GFP_KERNEL); 2808c2ecf20Sopenharmony_ci if (!cs4341) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (!spi->bits_per_word) 2848c2ecf20Sopenharmony_ci spi->bits_per_word = 8; 2858c2ecf20Sopenharmony_ci if (!spi->max_speed_hz) 2868c2ecf20Sopenharmony_ci spi->max_speed_hz = 6000000; 2878c2ecf20Sopenharmony_ci ret = spi_setup(spi); 2888c2ecf20Sopenharmony_ci if (ret) 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci spi_set_drvdata(spi, cs4341); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci cs4341->regcfg.reg_bits = 16; 2948c2ecf20Sopenharmony_ci cs4341->regcfg.val_bits = 8; 2958c2ecf20Sopenharmony_ci cs4341->regcfg.write_flag_mask = 0x20; 2968c2ecf20Sopenharmony_ci cs4341->regcfg.max_register = CS4341_REG_VOLB; 2978c2ecf20Sopenharmony_ci cs4341->regcfg.cache_type = REGCACHE_FLAT; 2988c2ecf20Sopenharmony_ci cs4341->regcfg.readable_reg = cs4341_reg_readable; 2998c2ecf20Sopenharmony_ci cs4341->regcfg.reg_defaults = cs4341_reg_defaults; 3008c2ecf20Sopenharmony_ci cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults); 3018c2ecf20Sopenharmony_ci cs4341->regmap = devm_regmap_init_spi(spi, &cs4341->regcfg); 3028c2ecf20Sopenharmony_ci if (IS_ERR(cs4341->regmap)) 3038c2ecf20Sopenharmony_ci return PTR_ERR(cs4341->regmap); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return cs4341_probe(&spi->dev); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic struct spi_driver cs4341_spi_driver = { 3098c2ecf20Sopenharmony_ci .driver = { 3108c2ecf20Sopenharmony_ci .name = "cs4341-spi", 3118c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(cs4341_dt_ids), 3128c2ecf20Sopenharmony_ci }, 3138c2ecf20Sopenharmony_ci .probe = cs4341_spi_probe, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci#endif 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int __init cs4341_init(void) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int ret = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 3228c2ecf20Sopenharmony_ci ret = i2c_add_driver(&cs4341_i2c_driver); 3238c2ecf20Sopenharmony_ci if (ret) 3248c2ecf20Sopenharmony_ci return ret; 3258c2ecf20Sopenharmony_ci#endif 3268c2ecf20Sopenharmony_ci#if defined(CONFIG_SPI_MASTER) 3278c2ecf20Sopenharmony_ci ret = spi_register_driver(&cs4341_spi_driver); 3288c2ecf20Sopenharmony_ci#endif 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_cimodule_init(cs4341_init); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic void __exit cs4341_exit(void) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C) 3378c2ecf20Sopenharmony_ci i2c_del_driver(&cs4341_i2c_driver); 3388c2ecf20Sopenharmony_ci#endif 3398c2ecf20Sopenharmony_ci#if defined(CONFIG_SPI_MASTER) 3408c2ecf20Sopenharmony_ci spi_unregister_driver(&cs4341_spi_driver); 3418c2ecf20Sopenharmony_ci#endif 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_cimodule_exit(cs4341_exit); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); 3468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cirrus Logic CS4341 ALSA SoC Codec Driver"); 3478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 348