2 * cs4349.c -- CS4349 ALSA Soc Audio driver
4 * Copyright 2015 Cirrus Logic, Inc.
6 * Authors: Tim Howe <Tim.Howe@cirrus.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/delay.h>
18 #include <linux/gpio.h>
19 #include <linux/gpio/consumer.h>
20 #include <linux/platform_device.h>
22 #include <linux/i2c.h>
23 #include <linux/of_device.h>
24 #include <linux/regmap.h>
25 #include <linux/slab.h>
26 #include <sound/core.h>
27 #include <sound/pcm.h>
28 #include <sound/pcm_params.h>
29 #include <sound/soc.h>
30 #include <sound/soc-dapm.h>
31 #include <sound/initval.h>
32 #include <sound/tlv.h>
36 static const struct reg_default cs4349_reg_defaults
[] = {
37 { 2, 0x00 }, /* r02 - Mode Control */
38 { 3, 0x09 }, /* r03 - Volume, Mixing and Inversion Control */
39 { 4, 0x81 }, /* r04 - Mute Control */
40 { 5, 0x00 }, /* r05 - Channel A Volume Control */
41 { 6, 0x00 }, /* r06 - Channel B Volume Control */
42 { 7, 0xB1 }, /* r07 - Ramp and Filter Control */
43 { 8, 0x1C }, /* r08 - Misc. Control */
46 /* Private data for the CS4349 */
47 struct cs4349_private
{
48 struct regmap
*regmap
;
49 struct gpio_desc
*reset_gpio
;
54 static bool cs4349_readable_register(struct device
*dev
, unsigned int reg
)
57 case CS4349_CHIPID
... CS4349_MISC
:
64 static bool cs4349_writeable_register(struct device
*dev
, unsigned int reg
)
67 case CS4349_MODE
... CS4349_MISC
:
74 static int cs4349_set_dai_fmt(struct snd_soc_dai
*codec_dai
,
77 struct snd_soc_codec
*codec
= codec_dai
->codec
;
78 struct cs4349_private
*cs4349
= snd_soc_codec_get_drvdata(codec
);
81 fmt
= format
& SND_SOC_DAIFMT_FORMAT_MASK
;
84 case SND_SOC_DAIFMT_I2S
:
85 case SND_SOC_DAIFMT_LEFT_J
:
86 case SND_SOC_DAIFMT_RIGHT_J
:
87 cs4349
->mode
= format
& SND_SOC_DAIFMT_FORMAT_MASK
;
96 static int cs4349_pcm_hw_params(struct snd_pcm_substream
*substream
,
97 struct snd_pcm_hw_params
*params
,
98 struct snd_soc_dai
*dai
)
100 struct snd_soc_codec
*codec
= dai
->codec
;
101 struct cs4349_private
*cs4349
= snd_soc_codec_get_drvdata(codec
);
104 cs4349
->rate
= params_rate(params
);
106 switch (cs4349
->mode
) {
107 case SND_SOC_DAIFMT_I2S
:
110 case SND_SOC_DAIFMT_LEFT_J
:
113 case SND_SOC_DAIFMT_RIGHT_J
:
114 switch (params_width(params
)) {
116 fmt
= DIF_RGHT_JST16
;
119 fmt
= DIF_RGHT_JST24
;
129 ret
= snd_soc_update_bits(codec
, CS4349_MODE
, DIF_MASK
,
137 static int cs4349_digital_mute(struct snd_soc_dai
*dai
, int mute
)
139 struct snd_soc_codec
*codec
= dai
->codec
;
146 return snd_soc_update_bits(codec
, CS4349_MUTE
, MUTE_AB_MASK
, reg
);
149 static DECLARE_TLV_DB_SCALE(dig_tlv
, -12750, 50, 0);
151 static const char * const chan_mix_texts
[] = {
152 "Mute", "MuteA", "MuteA SwapB", "MuteA MonoB", "SwapA MuteB",
153 "BothR", "Swap", "SwapA MonoB", "MuteB", "Normal", "BothL",
154 "MonoB", "MonoA MuteB", "MonoA", "MonoA SwapB", "Mono",
155 /*Normal == Channel A = Left, Channel B = Right*/
158 static const char * const fm_texts
[] = {
159 "Auto", "Single", "Double", "Quad",
162 static const char * const deemph_texts
[] = {
163 "None", "44.1k", "48k", "32k",
166 static const char * const softr_zeroc_texts
[] = {
167 "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC",
170 static int deemph_values
[] = {
174 static int softr_zeroc_values
[] = {
178 static const struct soc_enum chan_mix_enum
=
179 SOC_ENUM_SINGLE(CS4349_VMI
, 0,
180 ARRAY_SIZE(chan_mix_texts
),
183 static const struct soc_enum fm_mode_enum
=
184 SOC_ENUM_SINGLE(CS4349_MODE
, 0,
185 ARRAY_SIZE(fm_texts
),
188 static SOC_VALUE_ENUM_SINGLE_DECL(deemph_enum
, CS4349_MODE
, 0, DEM_MASK
,
189 deemph_texts
, deemph_values
);
191 static SOC_VALUE_ENUM_SINGLE_DECL(softr_zeroc_enum
, CS4349_RMPFLT
, 0,
192 SR_ZC_MASK
, softr_zeroc_texts
,
195 static const struct snd_kcontrol_new cs4349_snd_controls
[] = {
196 SOC_DOUBLE_R_TLV("Master Playback Volume",
197 CS4349_VOLA
, CS4349_VOLB
, 0, 0xFF, 1, dig_tlv
),
198 SOC_ENUM("Functional Mode", fm_mode_enum
),
199 SOC_ENUM("De-Emphasis Control", deemph_enum
),
200 SOC_ENUM("Soft Ramp Zero Cross Control", softr_zeroc_enum
),
201 SOC_ENUM("Channel Mixer", chan_mix_enum
),
202 SOC_SINGLE("VolA = VolB Switch", CS4349_VMI
, 7, 1, 0),
203 SOC_SINGLE("InvertA Switch", CS4349_VMI
, 6, 1, 0),
204 SOC_SINGLE("InvertB Switch", CS4349_VMI
, 5, 1, 0),
205 SOC_SINGLE("Auto-Mute Switch", CS4349_MUTE
, 7, 1, 0),
206 SOC_SINGLE("MUTEC A = B Switch", CS4349_MUTE
, 5, 1, 0),
207 SOC_SINGLE("Soft Ramp Up Switch", CS4349_RMPFLT
, 5, 1, 0),
208 SOC_SINGLE("Soft Ramp Down Switch", CS4349_RMPFLT
, 4, 1, 0),
209 SOC_SINGLE("Slow Roll Off Filter Switch", CS4349_RMPFLT
, 2, 1, 0),
210 SOC_SINGLE("Freeze Switch", CS4349_MISC
, 5, 1, 0),
211 SOC_SINGLE("Popguard Switch", CS4349_MISC
, 4, 1, 0),
214 static const struct snd_soc_dapm_widget cs4349_dapm_widgets
[] = {
215 SND_SOC_DAPM_DAC("HiFi DAC", NULL
, SND_SOC_NOPM
, 0, 0),
217 SND_SOC_DAPM_OUTPUT("OutputA"),
218 SND_SOC_DAPM_OUTPUT("OutputB"),
221 static const struct snd_soc_dapm_route cs4349_routes
[] = {
222 {"DAC Playback", NULL
, "OutputA"},
223 {"DAC Playback", NULL
, "OutputB"},
225 {"OutputA", NULL
, "HiFi DAC"},
226 {"OutputB", NULL
, "HiFi DAC"},
229 #define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
230 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
231 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
232 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
233 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
234 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
235 SNDRV_PCM_FMTBIT_S32_LE)
237 #define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000
239 static const struct snd_soc_dai_ops cs4349_dai_ops
= {
240 .hw_params
= cs4349_pcm_hw_params
,
241 .set_fmt
= cs4349_set_dai_fmt
,
242 .digital_mute
= cs4349_digital_mute
,
245 static struct snd_soc_dai_driver cs4349_dai
= {
246 .name
= "cs4349_hifi",
248 .stream_name
= "DAC Playback",
251 .rates
= CS4349_PCM_RATES
,
252 .formats
= CS4349_PCM_FORMATS
,
254 .ops
= &cs4349_dai_ops
,
255 .symmetric_rates
= 1,
258 static const struct snd_soc_codec_driver soc_codec_dev_cs4349
= {
259 .component_driver
= {
260 .controls
= cs4349_snd_controls
,
261 .num_controls
= ARRAY_SIZE(cs4349_snd_controls
),
262 .dapm_widgets
= cs4349_dapm_widgets
,
263 .num_dapm_widgets
= ARRAY_SIZE(cs4349_dapm_widgets
),
264 .dapm_routes
= cs4349_routes
,
265 .num_dapm_routes
= ARRAY_SIZE(cs4349_routes
),
269 static const struct regmap_config cs4349_regmap
= {
273 .max_register
= CS4349_MISC
,
274 .reg_defaults
= cs4349_reg_defaults
,
275 .num_reg_defaults
= ARRAY_SIZE(cs4349_reg_defaults
),
276 .readable_reg
= cs4349_readable_register
,
277 .writeable_reg
= cs4349_writeable_register
,
278 .cache_type
= REGCACHE_RBTREE
,
281 static int cs4349_i2c_probe(struct i2c_client
*client
,
282 const struct i2c_device_id
*id
)
284 struct cs4349_private
*cs4349
;
287 cs4349
= devm_kzalloc(&client
->dev
, sizeof(*cs4349
), GFP_KERNEL
);
291 cs4349
->regmap
= devm_regmap_init_i2c(client
, &cs4349_regmap
);
292 if (IS_ERR(cs4349
->regmap
)) {
293 ret
= PTR_ERR(cs4349
->regmap
);
294 dev_err(&client
->dev
, "regmap_init() failed: %d\n", ret
);
298 /* Reset the Device */
299 cs4349
->reset_gpio
= devm_gpiod_get_optional(&client
->dev
,
300 "reset", GPIOD_OUT_LOW
);
301 if (IS_ERR(cs4349
->reset_gpio
))
302 return PTR_ERR(cs4349
->reset_gpio
);
304 gpiod_set_value_cansleep(cs4349
->reset_gpio
, 1);
306 i2c_set_clientdata(client
, cs4349
);
308 return snd_soc_register_codec(&client
->dev
, &soc_codec_dev_cs4349
,
312 static int cs4349_i2c_remove(struct i2c_client
*client
)
314 struct cs4349_private
*cs4349
= i2c_get_clientdata(client
);
316 snd_soc_unregister_codec(&client
->dev
);
318 /* Hold down reset */
319 gpiod_set_value_cansleep(cs4349
->reset_gpio
, 0);
325 static int cs4349_runtime_suspend(struct device
*dev
)
327 struct cs4349_private
*cs4349
= dev_get_drvdata(dev
);
330 ret
= regmap_update_bits(cs4349
->regmap
, CS4349_MISC
, PWR_DWN
, PWR_DWN
);
334 regcache_cache_only(cs4349
->regmap
, true);
336 /* Hold down reset */
337 gpiod_set_value_cansleep(cs4349
->reset_gpio
, 0);
342 static int cs4349_runtime_resume(struct device
*dev
)
344 struct cs4349_private
*cs4349
= dev_get_drvdata(dev
);
347 ret
= regmap_update_bits(cs4349
->regmap
, CS4349_MISC
, PWR_DWN
, 0);
351 gpiod_set_value_cansleep(cs4349
->reset_gpio
, 1);
353 regcache_cache_only(cs4349
->regmap
, false);
354 regcache_sync(cs4349
->regmap
);
360 static const struct dev_pm_ops cs4349_runtime_pm
= {
361 SET_RUNTIME_PM_OPS(cs4349_runtime_suspend
, cs4349_runtime_resume
,
365 static const struct of_device_id cs4349_of_match
[] = {
366 { .compatible
= "cirrus,cs4349", },
370 MODULE_DEVICE_TABLE(of
, cs4349_of_match
);
372 static const struct i2c_device_id cs4349_i2c_id
[] = {
377 MODULE_DEVICE_TABLE(i2c
, cs4349_i2c_id
);
379 static struct i2c_driver cs4349_i2c_driver
= {
382 .of_match_table
= cs4349_of_match
,
384 .id_table
= cs4349_i2c_id
,
385 .probe
= cs4349_i2c_probe
,
386 .remove
= cs4349_i2c_remove
,
389 module_i2c_driver(cs4349_i2c_driver
);
391 MODULE_AUTHOR("Tim Howe <tim.howe@cirrus.com>");
392 MODULE_DESCRIPTION("Cirrus Logic CS4349 ALSA SoC Codec Driver");
393 MODULE_LICENSE("GPL");