18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * cs4349.c -- CS4349 ALSA Soc Audio driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2015 Cirrus Logic, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Tim Howe <Tim.Howe@cirrus.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/gpio.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pm.h> 198c2ecf20Sopenharmony_ci#include <linux/i2c.h> 208c2ecf20Sopenharmony_ci#include <linux/of_device.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <sound/core.h> 248c2ecf20Sopenharmony_ci#include <sound/pcm.h> 258c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 268c2ecf20Sopenharmony_ci#include <sound/soc.h> 278c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h> 288c2ecf20Sopenharmony_ci#include <sound/initval.h> 298c2ecf20Sopenharmony_ci#include <sound/tlv.h> 308c2ecf20Sopenharmony_ci#include "cs4349.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic const struct reg_default cs4349_reg_defaults[] = { 348c2ecf20Sopenharmony_ci { 2, 0x00 }, /* r02 - Mode Control */ 358c2ecf20Sopenharmony_ci { 3, 0x09 }, /* r03 - Volume, Mixing and Inversion Control */ 368c2ecf20Sopenharmony_ci { 4, 0x81 }, /* r04 - Mute Control */ 378c2ecf20Sopenharmony_ci { 5, 0x00 }, /* r05 - Channel A Volume Control */ 388c2ecf20Sopenharmony_ci { 6, 0x00 }, /* r06 - Channel B Volume Control */ 398c2ecf20Sopenharmony_ci { 7, 0xB1 }, /* r07 - Ramp and Filter Control */ 408c2ecf20Sopenharmony_ci { 8, 0x1C }, /* r08 - Misc. Control */ 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Private data for the CS4349 */ 448c2ecf20Sopenharmony_cistruct cs4349_private { 458c2ecf20Sopenharmony_ci struct regmap *regmap; 468c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpio; 478c2ecf20Sopenharmony_ci unsigned int mode; 488c2ecf20Sopenharmony_ci int rate; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic bool cs4349_readable_register(struct device *dev, unsigned int reg) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci switch (reg) { 548c2ecf20Sopenharmony_ci case CS4349_CHIPID ... CS4349_MISC: 558c2ecf20Sopenharmony_ci return true; 568c2ecf20Sopenharmony_ci default: 578c2ecf20Sopenharmony_ci return false; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic bool cs4349_writeable_register(struct device *dev, unsigned int reg) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci switch (reg) { 648c2ecf20Sopenharmony_ci case CS4349_MODE ... CS4349_MISC: 658c2ecf20Sopenharmony_ci return true; 668c2ecf20Sopenharmony_ci default: 678c2ecf20Sopenharmony_ci return false; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int cs4349_set_dai_fmt(struct snd_soc_dai *codec_dai, 728c2ecf20Sopenharmony_ci unsigned int format) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 758c2ecf20Sopenharmony_ci struct cs4349_private *cs4349 = snd_soc_component_get_drvdata(component); 768c2ecf20Sopenharmony_ci unsigned int fmt; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci switch (fmt) { 818c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 828c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 838c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 848c2ecf20Sopenharmony_ci cs4349->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci default: 878c2ecf20Sopenharmony_ci return -EINVAL; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, 948c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 958c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 988c2ecf20Sopenharmony_ci struct cs4349_private *cs4349 = snd_soc_component_get_drvdata(component); 998c2ecf20Sopenharmony_ci int fmt, ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci cs4349->rate = params_rate(params); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci switch (cs4349->mode) { 1048c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 1058c2ecf20Sopenharmony_ci fmt = DIF_I2S; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 1088c2ecf20Sopenharmony_ci fmt = DIF_LEFT_JST; 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 1118c2ecf20Sopenharmony_ci switch (params_width(params)) { 1128c2ecf20Sopenharmony_ci case 16: 1138c2ecf20Sopenharmony_ci fmt = DIF_RGHT_JST16; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case 24: 1168c2ecf20Sopenharmony_ci fmt = DIF_RGHT_JST24; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci default: 1198c2ecf20Sopenharmony_ci return -EINVAL; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci default: 1238c2ecf20Sopenharmony_ci return -EINVAL; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, CS4349_MODE, DIF_MASK, 1278c2ecf20Sopenharmony_ci MODE_FORMAT(fmt)); 1288c2ecf20Sopenharmony_ci if (ret < 0) 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int cs4349_mute(struct snd_soc_dai *dai, int mute, int direction) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 1378c2ecf20Sopenharmony_ci int reg; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci reg = 0; 1408c2ecf20Sopenharmony_ci if (mute) 1418c2ecf20Sopenharmony_ci reg = MUTE_AB_MASK; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return snd_soc_component_update_bits(component, CS4349_MUTE, MUTE_AB_MASK, reg); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(dig_tlv, -12750, 50, 0); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic const char * const chan_mix_texts[] = { 1498c2ecf20Sopenharmony_ci "Mute", "MuteA", "MuteA SwapB", "MuteA MonoB", "SwapA MuteB", 1508c2ecf20Sopenharmony_ci "BothR", "Swap", "SwapA MonoB", "MuteB", "Normal", "BothL", 1518c2ecf20Sopenharmony_ci "MonoB", "MonoA MuteB", "MonoA", "MonoA SwapB", "Mono", 1528c2ecf20Sopenharmony_ci /*Normal == Channel A = Left, Channel B = Right*/ 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const char * const fm_texts[] = { 1568c2ecf20Sopenharmony_ci "Auto", "Single", "Double", "Quad", 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic const char * const deemph_texts[] = { 1608c2ecf20Sopenharmony_ci "None", "44.1k", "48k", "32k", 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic const char * const softr_zeroc_texts[] = { 1648c2ecf20Sopenharmony_ci "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC", 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int deemph_values[] = { 1688c2ecf20Sopenharmony_ci 0, 4, 8, 12, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int softr_zeroc_values[] = { 1728c2ecf20Sopenharmony_ci 0, 64, 128, 192, 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic const struct soc_enum chan_mix_enum = 1768c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS4349_VMI, 0, 1778c2ecf20Sopenharmony_ci ARRAY_SIZE(chan_mix_texts), 1788c2ecf20Sopenharmony_ci chan_mix_texts); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic const struct soc_enum fm_mode_enum = 1818c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(CS4349_MODE, 0, 1828c2ecf20Sopenharmony_ci ARRAY_SIZE(fm_texts), 1838c2ecf20Sopenharmony_ci fm_texts); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic SOC_VALUE_ENUM_SINGLE_DECL(deemph_enum, CS4349_MODE, 0, DEM_MASK, 1868c2ecf20Sopenharmony_ci deemph_texts, deemph_values); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic SOC_VALUE_ENUM_SINGLE_DECL(softr_zeroc_enum, CS4349_RMPFLT, 0, 1898c2ecf20Sopenharmony_ci SR_ZC_MASK, softr_zeroc_texts, 1908c2ecf20Sopenharmony_ci softr_zeroc_values); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cs4349_snd_controls[] = { 1938c2ecf20Sopenharmony_ci SOC_DOUBLE_R_TLV("Master Playback Volume", 1948c2ecf20Sopenharmony_ci CS4349_VOLA, CS4349_VOLB, 0, 0xFF, 1, dig_tlv), 1958c2ecf20Sopenharmony_ci SOC_ENUM("Functional Mode", fm_mode_enum), 1968c2ecf20Sopenharmony_ci SOC_ENUM("De-Emphasis Control", deemph_enum), 1978c2ecf20Sopenharmony_ci SOC_ENUM("Soft Ramp Zero Cross Control", softr_zeroc_enum), 1988c2ecf20Sopenharmony_ci SOC_ENUM("Channel Mixer", chan_mix_enum), 1998c2ecf20Sopenharmony_ci SOC_SINGLE("VolA = VolB Switch", CS4349_VMI, 7, 1, 0), 2008c2ecf20Sopenharmony_ci SOC_SINGLE("InvertA Switch", CS4349_VMI, 6, 1, 0), 2018c2ecf20Sopenharmony_ci SOC_SINGLE("InvertB Switch", CS4349_VMI, 5, 1, 0), 2028c2ecf20Sopenharmony_ci SOC_SINGLE("Auto-Mute Switch", CS4349_MUTE, 7, 1, 0), 2038c2ecf20Sopenharmony_ci SOC_SINGLE("MUTEC A = B Switch", CS4349_MUTE, 5, 1, 0), 2048c2ecf20Sopenharmony_ci SOC_SINGLE("Soft Ramp Up Switch", CS4349_RMPFLT, 5, 1, 0), 2058c2ecf20Sopenharmony_ci SOC_SINGLE("Soft Ramp Down Switch", CS4349_RMPFLT, 4, 1, 0), 2068c2ecf20Sopenharmony_ci SOC_SINGLE("Slow Roll Off Filter Switch", CS4349_RMPFLT, 2, 1, 0), 2078c2ecf20Sopenharmony_ci SOC_SINGLE("Freeze Switch", CS4349_MISC, 5, 1, 0), 2088c2ecf20Sopenharmony_ci SOC_SINGLE("Popguard Switch", CS4349_MISC, 4, 1, 0), 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget cs4349_dapm_widgets[] = { 2128c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0), 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OutputA"), 2158c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OutputB"), 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route cs4349_routes[] = { 2198c2ecf20Sopenharmony_ci {"DAC Playback", NULL, "OutputA"}, 2208c2ecf20Sopenharmony_ci {"DAC Playback", NULL, "OutputB"}, 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci {"OutputA", NULL, "HiFi DAC"}, 2238c2ecf20Sopenharmony_ci {"OutputB", NULL, "HiFi DAC"}, 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 2278c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ 2288c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ 2298c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ 2308c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ 2318c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ 2328c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE) 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops cs4349_dai_ops = { 2378c2ecf20Sopenharmony_ci .hw_params = cs4349_pcm_hw_params, 2388c2ecf20Sopenharmony_ci .set_fmt = cs4349_set_dai_fmt, 2398c2ecf20Sopenharmony_ci .mute_stream = cs4349_mute, 2408c2ecf20Sopenharmony_ci .no_capture_mute = 1, 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver cs4349_dai = { 2448c2ecf20Sopenharmony_ci .name = "cs4349_hifi", 2458c2ecf20Sopenharmony_ci .playback = { 2468c2ecf20Sopenharmony_ci .stream_name = "DAC Playback", 2478c2ecf20Sopenharmony_ci .channels_min = 1, 2488c2ecf20Sopenharmony_ci .channels_max = 2, 2498c2ecf20Sopenharmony_ci .rates = CS4349_PCM_RATES, 2508c2ecf20Sopenharmony_ci .formats = CS4349_PCM_FORMATS, 2518c2ecf20Sopenharmony_ci }, 2528c2ecf20Sopenharmony_ci .ops = &cs4349_dai_ops, 2538c2ecf20Sopenharmony_ci .symmetric_rates = 1, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_cs4349 = { 2578c2ecf20Sopenharmony_ci .controls = cs4349_snd_controls, 2588c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(cs4349_snd_controls), 2598c2ecf20Sopenharmony_ci .dapm_widgets = cs4349_dapm_widgets, 2608c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs4349_dapm_widgets), 2618c2ecf20Sopenharmony_ci .dapm_routes = cs4349_routes, 2628c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs4349_routes), 2638c2ecf20Sopenharmony_ci .idle_bias_on = 1, 2648c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 2658c2ecf20Sopenharmony_ci .endianness = 1, 2668c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic const struct regmap_config cs4349_regmap = { 2708c2ecf20Sopenharmony_ci .reg_bits = 8, 2718c2ecf20Sopenharmony_ci .val_bits = 8, 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci .max_register = CS4349_MISC, 2748c2ecf20Sopenharmony_ci .reg_defaults = cs4349_reg_defaults, 2758c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), 2768c2ecf20Sopenharmony_ci .readable_reg = cs4349_readable_register, 2778c2ecf20Sopenharmony_ci .writeable_reg = cs4349_writeable_register, 2788c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int cs4349_i2c_probe(struct i2c_client *client, 2828c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct cs4349_private *cs4349; 2858c2ecf20Sopenharmony_ci int ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL); 2888c2ecf20Sopenharmony_ci if (!cs4349) 2898c2ecf20Sopenharmony_ci return -ENOMEM; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci cs4349->regmap = devm_regmap_init_i2c(client, &cs4349_regmap); 2928c2ecf20Sopenharmony_ci if (IS_ERR(cs4349->regmap)) { 2938c2ecf20Sopenharmony_ci ret = PTR_ERR(cs4349->regmap); 2948c2ecf20Sopenharmony_ci dev_err(&client->dev, "regmap_init() failed: %d\n", ret); 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Reset the Device */ 2998c2ecf20Sopenharmony_ci cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev, 3008c2ecf20Sopenharmony_ci "reset", GPIOD_OUT_LOW); 3018c2ecf20Sopenharmony_ci if (IS_ERR(cs4349->reset_gpio)) 3028c2ecf20Sopenharmony_ci return PTR_ERR(cs4349->reset_gpio); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs4349->reset_gpio, 1); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci i2c_set_clientdata(client, cs4349); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(&client->dev, 3098c2ecf20Sopenharmony_ci &soc_component_dev_cs4349, 3108c2ecf20Sopenharmony_ci &cs4349_dai, 1); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int cs4349_i2c_remove(struct i2c_client *client) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct cs4349_private *cs4349 = i2c_get_clientdata(client); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Hold down reset */ 3188c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs4349->reset_gpio, 0); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3248c2ecf20Sopenharmony_cistatic int cs4349_runtime_suspend(struct device *dev) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct cs4349_private *cs4349 = dev_get_drvdata(dev); 3278c2ecf20Sopenharmony_ci int ret; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, PWR_DWN); 3308c2ecf20Sopenharmony_ci if (ret < 0) 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci regcache_cache_only(cs4349->regmap, true); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Hold down reset */ 3368c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs4349->reset_gpio, 0); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int cs4349_runtime_resume(struct device *dev) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct cs4349_private *cs4349 = dev_get_drvdata(dev); 3448c2ecf20Sopenharmony_ci int ret; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 0); 3478c2ecf20Sopenharmony_ci if (ret < 0) 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(cs4349->reset_gpio, 1); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci regcache_cache_only(cs4349->regmap, false); 3538c2ecf20Sopenharmony_ci regcache_sync(cs4349->regmap); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci#endif 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cs4349_runtime_pm = { 3608c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume, 3618c2ecf20Sopenharmony_ci NULL) 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic const struct of_device_id cs4349_of_match[] = { 3658c2ecf20Sopenharmony_ci { .compatible = "cirrus,cs4349", }, 3668c2ecf20Sopenharmony_ci {}, 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs4349_of_match); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic const struct i2c_device_id cs4349_i2c_id[] = { 3728c2ecf20Sopenharmony_ci {"cs4349", 0}, 3738c2ecf20Sopenharmony_ci {} 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cs4349_i2c_id); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic struct i2c_driver cs4349_i2c_driver = { 3798c2ecf20Sopenharmony_ci .driver = { 3808c2ecf20Sopenharmony_ci .name = "cs4349", 3818c2ecf20Sopenharmony_ci .of_match_table = cs4349_of_match, 3828c2ecf20Sopenharmony_ci .pm = &cs4349_runtime_pm, 3838c2ecf20Sopenharmony_ci }, 3848c2ecf20Sopenharmony_ci .id_table = cs4349_i2c_id, 3858c2ecf20Sopenharmony_ci .probe = cs4349_i2c_probe, 3868c2ecf20Sopenharmony_ci .remove = cs4349_i2c_remove, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cimodule_i2c_driver(cs4349_i2c_driver); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tim Howe <tim.howe@cirrus.com>"); 3928c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cirrus Logic CS4349 ALSA SoC Codec Driver"); 3938c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 394