2 * ALSA ASoC Machine Driver for Allo Boss DAC
4 * Author: Baswaraj K <jaikumar@cem-solutions.net>
6 * based on code by Daniel Matuschek,
7 * Stuart MacLean <stuart@hifiberry.com>
8 * based on code by Florian Meier <florian.meier@koalo.de>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
20 #include <linux/module.h>
21 #include <linux/gpio/consumer.h>
22 #include <linux/platform_device.h>
23 #include <linux/clk.h>
24 #include <linux/delay.h>
26 #include <sound/core.h>
27 #include <sound/pcm.h>
28 #include <sound/pcm_params.h>
29 #include <sound/soc.h>
30 #include "../codecs/pcm512x.h"
32 #define ALLO_BOSS_NOCLOCK 0
33 #define ALLO_BOSS_CLK44EN 1
34 #define ALLO_BOSS_CLK48EN 2
37 struct regmap
*regmap
;
41 static struct gpio_desc
*mute_gpio
;
43 /* Clock rate of CLK44EN attached to GPIO6 pin */
44 #define CLK_44EN_RATE 45158400UL
45 /* Clock rate of CLK48EN attached to GPIO3 pin */
46 #define CLK_48EN_RATE 49152000UL
49 static bool snd_soc_allo_boss_master
;
50 static bool digital_gain_0db_limit
= true;
52 static void snd_allo_boss_select_clk(struct snd_soc_codec
*codec
,
56 case ALLO_BOSS_NOCLOCK
:
57 snd_soc_update_bits(codec
, PCM512x_GPIO_CONTROL_1
, 0x24, 0x00);
59 case ALLO_BOSS_CLK44EN
:
60 snd_soc_update_bits(codec
, PCM512x_GPIO_CONTROL_1
, 0x24, 0x20);
62 case ALLO_BOSS_CLK48EN
:
63 snd_soc_update_bits(codec
, PCM512x_GPIO_CONTROL_1
, 0x24, 0x04);
68 static void snd_allo_boss_clk_gpio(struct snd_soc_codec
*codec
)
70 snd_soc_update_bits(codec
, PCM512x_GPIO_EN
, 0x24, 0x24);
71 snd_soc_update_bits(codec
, PCM512x_GPIO_OUTPUT_3
, 0x0f, 0x02);
72 snd_soc_update_bits(codec
, PCM512x_GPIO_OUTPUT_6
, 0x0f, 0x02);
75 static bool snd_allo_boss_is_sclk(struct snd_soc_codec
*codec
)
79 sck
= snd_soc_read(codec
, PCM512x_RATE_DET_4
);
80 return (!(sck
& 0x40));
83 static bool snd_allo_boss_is_sclk_sleep(
84 struct snd_soc_codec
*codec
)
87 return snd_allo_boss_is_sclk(codec
);
90 static bool snd_allo_boss_is_master_card(struct snd_soc_codec
*codec
)
92 bool isClk44EN
, isClk48En
, isNoClk
;
94 snd_allo_boss_clk_gpio(codec
);
96 snd_allo_boss_select_clk(codec
, ALLO_BOSS_CLK44EN
);
97 isClk44EN
= snd_allo_boss_is_sclk_sleep(codec
);
99 snd_allo_boss_select_clk(codec
, ALLO_BOSS_NOCLOCK
);
100 isNoClk
= snd_allo_boss_is_sclk_sleep(codec
);
102 snd_allo_boss_select_clk(codec
, ALLO_BOSS_CLK48EN
);
103 isClk48En
= snd_allo_boss_is_sclk_sleep(codec
);
105 return (isClk44EN
&& isClk48En
&& !isNoClk
);
108 static int snd_allo_boss_clk_for_rate(int sample_rate
)
112 switch (sample_rate
) {
119 type
= ALLO_BOSS_CLK44EN
;
122 type
= ALLO_BOSS_CLK48EN
;
128 static void snd_allo_boss_set_sclk(struct snd_soc_codec
*codec
,
131 struct pcm512x_priv
*pcm512x
= snd_soc_codec_get_drvdata(codec
);
133 if (!IS_ERR(pcm512x
->sclk
)) {
136 ctype
= snd_allo_boss_clk_for_rate(sample_rate
);
137 clk_set_rate(pcm512x
->sclk
, (ctype
== ALLO_BOSS_CLK44EN
)
138 ? CLK_44EN_RATE
: CLK_48EN_RATE
);
139 snd_allo_boss_select_clk(codec
, ctype
);
143 static int snd_allo_boss_init(struct snd_soc_pcm_runtime
*rtd
)
145 struct snd_soc_codec
*codec
= rtd
->codec
;
146 struct pcm512x_priv
*priv
= snd_soc_codec_get_drvdata(codec
);
149 snd_soc_allo_boss_master
= false;
151 snd_soc_allo_boss_master
=
152 snd_allo_boss_is_master_card(codec
);
154 if (snd_soc_allo_boss_master
) {
155 struct snd_soc_dai_link
*dai
= rtd
->dai_link
;
157 dai
->name
= "BossDAC";
158 dai
->stream_name
= "Boss DAC HiFi [Master]";
159 dai
->dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
160 | SND_SOC_DAIFMT_CBM_CFM
;
162 snd_soc_update_bits(codec
, PCM512x_BCLK_LRCLK_CFG
, 0x31, 0x11);
163 snd_soc_update_bits(codec
, PCM512x_MASTER_MODE
, 0x03, 0x03);
164 snd_soc_update_bits(codec
, PCM512x_MASTER_CLKDIV_2
, 0x7f, 63);
166 * Default sclk to CLK_48EN_RATE, otherwise codec
167 * pcm512x_dai_startup_master method could call
168 * snd_pcm_hw_constraint_ratnums using CLK_44EN/64
169 * which will mask 384k sample rate.
171 if (!IS_ERR(priv
->sclk
))
172 clk_set_rate(priv
->sclk
, CLK_48EN_RATE
);
174 priv
->sclk
= ERR_PTR(-ENOENT
);
177 snd_soc_update_bits(codec
, PCM512x_GPIO_EN
, 0x08, 0x08);
178 snd_soc_update_bits(codec
, PCM512x_GPIO_OUTPUT_4
, 0x0f, 0x02);
179 snd_soc_update_bits(codec
, PCM512x_GPIO_CONTROL_1
, 0x08, 0x08);
181 if (digital_gain_0db_limit
) {
183 struct snd_soc_card
*card
= rtd
->card
;
185 ret
= snd_soc_limit_volume(card
, "Digital Playback Volume",
188 dev_warn(card
->dev
, "Failed to set volume limit: %d\n",
195 static int snd_allo_boss_update_rate_den(
196 struct snd_pcm_substream
*substream
, struct snd_pcm_hw_params
*params
)
198 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
199 struct snd_soc_codec
*codec
= rtd
->codec
;
200 struct pcm512x_priv
*pcm512x
= snd_soc_codec_get_drvdata(codec
);
201 struct snd_ratnum
*rats_no_pll
;
202 unsigned int num
= 0, den
= 0;
205 rats_no_pll
= devm_kzalloc(rtd
->dev
, sizeof(*rats_no_pll
), GFP_KERNEL
);
209 rats_no_pll
->num
= clk_get_rate(pcm512x
->sclk
) / 64;
210 rats_no_pll
->den_min
= 1;
211 rats_no_pll
->den_max
= 128;
212 rats_no_pll
->den_step
= 1;
214 err
= snd_interval_ratnum(hw_param_interval(params
,
215 SNDRV_PCM_HW_PARAM_RATE
), 1, rats_no_pll
, &num
, &den
);
216 if (err
>= 0 && den
) {
217 params
->rate_num
= num
;
218 params
->rate_den
= den
;
221 devm_kfree(rtd
->dev
, rats_no_pll
);
225 static int snd_allo_boss_set_bclk_ratio_pro(
226 struct snd_soc_dai
*cpu_dai
, struct snd_pcm_hw_params
*params
)
228 int bratio
= snd_pcm_format_physical_width(params_format(params
))
229 * params_channels(params
);
230 return snd_soc_dai_set_bclk_ratio(cpu_dai
, bratio
);
233 static void snd_allo_boss_gpio_mute(struct snd_soc_card
*card
)
236 gpiod_set_value_cansleep(mute_gpio
, 1);
239 static void snd_allo_boss_gpio_unmute(struct snd_soc_card
*card
)
242 gpiod_set_value_cansleep(mute_gpio
, 0);
245 static int snd_allo_boss_set_bias_level(struct snd_soc_card
*card
,
246 struct snd_soc_dapm_context
*dapm
, enum snd_soc_bias_level level
)
248 struct snd_soc_pcm_runtime
*rtd
;
249 struct snd_soc_dai
*codec_dai
;
251 rtd
= snd_soc_get_pcm_runtime(card
, card
->dai_link
[0].name
);
252 codec_dai
= rtd
->codec_dai
;
254 if (dapm
->dev
!= codec_dai
->dev
)
258 case SND_SOC_BIAS_PREPARE
:
259 if (dapm
->bias_level
!= SND_SOC_BIAS_STANDBY
)
262 snd_allo_boss_gpio_unmute(card
);
265 case SND_SOC_BIAS_STANDBY
:
266 if (dapm
->bias_level
!= SND_SOC_BIAS_PREPARE
)
269 snd_allo_boss_gpio_mute(card
);
279 static int snd_allo_boss_hw_params(
280 struct snd_pcm_substream
*substream
, struct snd_pcm_hw_params
*params
)
283 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
284 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
285 unsigned int sample_bits
=
286 snd_pcm_format_physical_width(params_format(params
));
288 if (snd_soc_allo_boss_master
) {
289 struct snd_soc_codec
*codec
= rtd
->codec
;
291 snd_allo_boss_set_sclk(codec
,
292 params_rate(params
));
294 ret
= snd_allo_boss_set_bclk_ratio_pro(cpu_dai
,
297 ret
= snd_allo_boss_update_rate_den(
300 ret
= snd_soc_dai_set_bclk_ratio(cpu_dai
, sample_bits
* 2);
305 static int snd_allo_boss_startup(
306 struct snd_pcm_substream
*substream
)
308 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
309 struct snd_soc_codec
*codec
= rtd
->codec
;
310 struct snd_soc_card
*card
= rtd
->card
;
312 snd_soc_update_bits(codec
, PCM512x_GPIO_CONTROL_1
, 0x08, 0x08);
313 snd_allo_boss_gpio_mute(card
);
315 if (snd_soc_allo_boss_master
) {
316 struct pcm512x_priv
*priv
= snd_soc_codec_get_drvdata(codec
);
318 * Default sclk to CLK_48EN_RATE, otherwise codec
319 * pcm512x_dai_startup_master method could call
320 * snd_pcm_hw_constraint_ratnums using CLK_44EN/64
321 * which will mask 384k sample rate.
323 if (!IS_ERR(priv
->sclk
))
324 clk_set_rate(priv
->sclk
, CLK_48EN_RATE
);
330 static void snd_allo_boss_shutdown(
331 struct snd_pcm_substream
*substream
)
333 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
334 struct snd_soc_codec
*codec
= rtd
->codec
;
336 snd_soc_update_bits(codec
, PCM512x_GPIO_CONTROL_1
, 0x08, 0x00);
339 static int snd_allo_boss_prepare(
340 struct snd_pcm_substream
*substream
)
342 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
343 struct snd_soc_card
*card
= rtd
->card
;
345 snd_allo_boss_gpio_unmute(card
);
348 /* machine stream operations */
349 static struct snd_soc_ops snd_allo_boss_ops
= {
350 .hw_params
= snd_allo_boss_hw_params
,
351 .startup
= snd_allo_boss_startup
,
352 .shutdown
= snd_allo_boss_shutdown
,
353 .prepare
= snd_allo_boss_prepare
,
356 static struct snd_soc_dai_link snd_allo_boss_dai
[] = {
359 .stream_name
= "Boss DAC HiFi",
360 .cpu_dai_name
= "bcm2708-i2s.0",
361 .codec_dai_name
= "pcm512x-hifi",
362 .platform_name
= "bcm2708-i2s.0",
363 .codec_name
= "pcm512x.1-004d",
364 .dai_fmt
= SND_SOC_DAIFMT_I2S
|
365 SND_SOC_DAIFMT_NB_NF
|
366 SND_SOC_DAIFMT_CBS_CFS
,
367 .ops
= &snd_allo_boss_ops
,
368 .init
= snd_allo_boss_init
,
372 /* audio machine driver */
373 static struct snd_soc_card snd_allo_boss
= {
375 .owner
= THIS_MODULE
,
376 .dai_link
= snd_allo_boss_dai
,
377 .num_links
= ARRAY_SIZE(snd_allo_boss_dai
),
380 static int snd_allo_boss_probe(struct platform_device
*pdev
)
384 snd_allo_boss
.dev
= &pdev
->dev
;
386 if (pdev
->dev
.of_node
) {
387 struct device_node
*i2s_node
;
388 struct snd_soc_dai_link
*dai
;
390 dai
= &snd_allo_boss_dai
[0];
391 i2s_node
= of_parse_phandle(pdev
->dev
.of_node
,
392 "i2s-controller", 0);
395 dai
->cpu_dai_name
= NULL
;
396 dai
->cpu_of_node
= i2s_node
;
397 dai
->platform_name
= NULL
;
398 dai
->platform_of_node
= i2s_node
;
401 digital_gain_0db_limit
= !of_property_read_bool(
402 pdev
->dev
.of_node
, "allo,24db_digital_gain");
403 slave
= of_property_read_bool(pdev
->dev
.of_node
,
406 mute_gpio
= devm_gpiod_get_optional(&pdev
->dev
, "mute",
408 if (IS_ERR(mute_gpio
)) {
409 ret
= PTR_ERR(mute_gpio
);
411 "failed to get mute gpio: %d\n", ret
);
416 snd_allo_boss
.set_bias_level
=
417 snd_allo_boss_set_bias_level
;
419 ret
= snd_soc_register_card(&snd_allo_boss
);
422 "snd_soc_register_card() failed: %d\n", ret
);
427 snd_allo_boss_gpio_mute(&snd_allo_boss
);
435 static int snd_allo_boss_remove(struct platform_device
*pdev
)
437 snd_allo_boss_gpio_mute(&snd_allo_boss
);
438 return snd_soc_unregister_card(&snd_allo_boss
);
441 static const struct of_device_id snd_allo_boss_of_match
[] = {
442 { .compatible
= "allo,boss-dac", },
445 MODULE_DEVICE_TABLE(of
, snd_allo_boss_of_match
);
447 static struct platform_driver snd_allo_boss_driver
= {
449 .name
= "snd-allo-boss-dac",
450 .owner
= THIS_MODULE
,
451 .of_match_table
= snd_allo_boss_of_match
,
453 .probe
= snd_allo_boss_probe
,
454 .remove
= snd_allo_boss_remove
,
457 module_platform_driver(snd_allo_boss_driver
);
459 MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
460 MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Boss DAC");
461 MODULE_LICENSE("GPL v2");