Skip to content

Commit 5d76de6

Browse files
larsclausenbroonie
authored andcommitted
ASoC: adau17x1: Add support for specifying the MCLK using the CCF
The devices from the ADAU17X1 family all have a MCLK clock input which supplies the master clock for the device. The master clock is used as the input clock for the PLL. Currently the MCLK rate as well as the desired PLL output frequency need to be supplied by calling snd_soc_dai_set_pll() form a machine driver. Add support for specifying the MCLK using the common clock framework. In addition to that also automatically configure the PLL to a suitable rate if the master clock was provided using the CCW. This allows to use the CODEC driver without any special configuration requirements from the machine driver. While the PLL output frequency can be configured over a (more or less) continuous range the narrowness of the range and the other constraints of the clocking tree usually only result in two output frequencies that will actually be chosen. One for 44.1kHz based rates and one for 48kHz based rates, these are the rates that the automatic PLL configuration will use. For the rare case where a non-standard setup is required a machine driver can disable the auto-configuration and configure a custom frequency using the existing mechanisms. If the common clock framework is not enabled clk_get() will return NULL and the driver will function as before and the clock rate needs to be configured manually. Signed-off-by: Lars-Peter Clausen <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 0eadaa9 commit 5d76de6

File tree

7 files changed

+179
-62
lines changed

7 files changed

+179
-62
lines changed

Documentation/devicetree/bindings/sound/adi,adau17x1.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,20 @@ Required properties:
1313
- reg: The i2c address. Value depends on the state of ADDR0
1414
and ADDR1, as wired in hardware.
1515

16+
Optional properties:
17+
- clock-names: If provided must be "mclk".
18+
- clocks: phandle + clock-specifiers for the clock that provides
19+
the audio master clock for the device.
20+
1621
Examples:
1722
#include <dt-bindings/sound/adau17x1.h>
1823

1924
i2c_bus {
2025
adau1361@38 {
2126
compatible = "adi,adau1761";
2227
reg = <0x38>;
28+
29+
clock-names = "mclk";
30+
clocks = <&audio_clock>;
2331
};
2432
};

sound/soc/codecs/adau1761-i2c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static int adau1761_i2c_probe(struct i2c_client *client,
3131

3232
static int adau1761_i2c_remove(struct i2c_client *client)
3333
{
34-
snd_soc_unregister_codec(&client->dev);
34+
adau17x1_remove(&client->dev);
3535
return 0;
3636
}
3737

sound/soc/codecs/adau1761-spi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static int adau1761_spi_probe(struct spi_device *spi)
4848

4949
static int adau1761_spi_remove(struct spi_device *spi)
5050
{
51-
snd_soc_unregister_codec(&spi->dev);
51+
adau17x1_remove(&spi->dev);
5252
return 0;
5353
}
5454

sound/soc/codecs/adau1781-i2c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static int adau1781_i2c_probe(struct i2c_client *client,
3131

3232
static int adau1781_i2c_remove(struct i2c_client *client)
3333
{
34-
snd_soc_unregister_codec(&client->dev);
34+
adau17x1_remove(&client->dev);
3535
return 0;
3636
}
3737

sound/soc/codecs/adau1781-spi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static int adau1781_spi_probe(struct spi_device *spi)
4848

4949
static int adau1781_spi_remove(struct spi_device *spi)
5050
{
51-
snd_soc_unregister_codec(&spi->dev);
51+
adau17x1_remove(&spi->dev);
5252
return 0;
5353
}
5454

sound/soc/codecs/adau17x1.c

Lines changed: 161 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/module.h>
1111
#include <linux/init.h>
12+
#include <linux/clk.h>
1213
#include <linux/delay.h>
1314
#include <linux/slab.h>
1415
#include <sound/core.h>
@@ -303,6 +304,116 @@ bool adau17x1_has_dsp(struct adau *adau)
303304
}
304305
EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
305306

307+
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
308+
int source, unsigned int freq_in, unsigned int freq_out)
309+
{
310+
struct snd_soc_codec *codec = dai->codec;
311+
struct adau *adau = snd_soc_codec_get_drvdata(codec);
312+
int ret;
313+
314+
if (freq_in < 8000000 || freq_in > 27000000)
315+
return -EINVAL;
316+
317+
ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs);
318+
if (ret < 0)
319+
return ret;
320+
321+
/* The PLL register is 6 bytes long and can only be written at once. */
322+
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
323+
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
324+
if (ret)
325+
return ret;
326+
327+
adau->pll_freq = freq_out;
328+
329+
return 0;
330+
}
331+
332+
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
333+
int clk_id, unsigned int freq, int dir)
334+
{
335+
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
336+
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
337+
bool is_pll;
338+
bool was_pll;
339+
340+
switch (clk_id) {
341+
case ADAU17X1_CLK_SRC_MCLK:
342+
is_pll = false;
343+
break;
344+
case ADAU17X1_CLK_SRC_PLL_AUTO:
345+
if (!adau->mclk)
346+
return -EINVAL;
347+
/* Fall-through */
348+
case ADAU17X1_CLK_SRC_PLL:
349+
is_pll = true;
350+
break;
351+
default:
352+
return -EINVAL;
353+
}
354+
355+
switch (adau->clk_src) {
356+
case ADAU17X1_CLK_SRC_MCLK:
357+
was_pll = false;
358+
break;
359+
case ADAU17X1_CLK_SRC_PLL:
360+
case ADAU17X1_CLK_SRC_PLL_AUTO:
361+
was_pll = true;
362+
break;
363+
default:
364+
return -EINVAL;
365+
}
366+
367+
adau->sysclk = freq;
368+
369+
if (is_pll != was_pll) {
370+
if (is_pll) {
371+
snd_soc_dapm_add_routes(dapm,
372+
&adau17x1_dapm_pll_route, 1);
373+
} else {
374+
snd_soc_dapm_del_routes(dapm,
375+
&adau17x1_dapm_pll_route, 1);
376+
}
377+
}
378+
379+
adau->clk_src = clk_id;
380+
381+
return 0;
382+
}
383+
384+
static int adau17x1_auto_pll(struct snd_soc_dai *dai,
385+
struct snd_pcm_hw_params *params)
386+
{
387+
struct adau *adau = snd_soc_dai_get_drvdata(dai);
388+
unsigned int pll_rate;
389+
390+
switch (params_rate(params)) {
391+
case 48000:
392+
case 8000:
393+
case 12000:
394+
case 16000:
395+
case 24000:
396+
case 32000:
397+
case 96000:
398+
pll_rate = 48000 * 1024;
399+
break;
400+
case 44100:
401+
case 7350:
402+
case 11025:
403+
case 14700:
404+
case 22050:
405+
case 29400:
406+
case 88200:
407+
pll_rate = 44100 * 1024;
408+
break;
409+
default:
410+
return -EINVAL;
411+
}
412+
413+
return adau17x1_set_dai_pll(dai, ADAU17X1_PLL, ADAU17X1_PLL_SRC_MCLK,
414+
clk_get_rate(adau->mclk), pll_rate);
415+
}
416+
306417
static int adau17x1_hw_params(struct snd_pcm_substream *substream,
307418
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
308419
{
@@ -312,10 +423,19 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
312423
unsigned int freq;
313424
int ret;
314425

315-
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
426+
switch (adau->clk_src) {
427+
case ADAU17X1_CLK_SRC_PLL_AUTO:
428+
ret = adau17x1_auto_pll(dai, params);
429+
if (ret)
430+
return ret;
431+
/* Fall-through */
432+
case ADAU17X1_CLK_SRC_PLL:
316433
freq = adau->pll_freq;
317-
else
434+
break;
435+
default:
318436
freq = adau->sysclk;
437+
break;
438+
}
319439

320440
if (freq % params_rate(params) != 0)
321441
return -EINVAL;
@@ -387,62 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
387507
ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
388508
}
389509

390-
static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
391-
int source, unsigned int freq_in, unsigned int freq_out)
392-
{
393-
struct snd_soc_codec *codec = dai->codec;
394-
struct adau *adau = snd_soc_codec_get_drvdata(codec);
395-
int ret;
396-
397-
if (freq_in < 8000000 || freq_in > 27000000)
398-
return -EINVAL;
399-
400-
ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs);
401-
if (ret < 0)
402-
return ret;
403-
404-
/* The PLL register is 6 bytes long and can only be written at once. */
405-
ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
406-
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
407-
if (ret)
408-
return ret;
409-
410-
adau->pll_freq = freq_out;
411-
412-
return 0;
413-
}
414-
415-
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
416-
int clk_id, unsigned int freq, int dir)
417-
{
418-
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
419-
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
420-
421-
switch (clk_id) {
422-
case ADAU17X1_CLK_SRC_MCLK:
423-
case ADAU17X1_CLK_SRC_PLL:
424-
break;
425-
default:
426-
return -EINVAL;
427-
}
428-
429-
adau->sysclk = freq;
430-
431-
if (adau->clk_src != clk_id) {
432-
if (clk_id == ADAU17X1_CLK_SRC_PLL) {
433-
snd_soc_dapm_add_routes(dapm,
434-
&adau17x1_dapm_pll_route, 1);
435-
} else {
436-
snd_soc_dapm_del_routes(dapm,
437-
&adau17x1_dapm_pll_route, 1);
438-
}
439-
}
440-
441-
adau->clk_src = clk_id;
442-
443-
return 0;
444-
}
445-
446510
static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
447511
unsigned int fmt)
448512
{
@@ -827,6 +891,10 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
827891
ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
828892
ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
829893
}
894+
895+
if (adau->clk_src != ADAU17X1_CLK_SRC_MCLK)
896+
snd_soc_dapm_add_routes(dapm, &adau17x1_dapm_pll_route, 1);
897+
830898
return ret;
831899
}
832900
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
@@ -849,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
849917
const char *firmware_name)
850918
{
851919
struct adau *adau;
920+
int ret;
852921

853922
if (IS_ERR(regmap))
854923
return PTR_ERR(regmap);
@@ -857,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
857926
if (!adau)
858927
return -ENOMEM;
859928

929+
adau->mclk = devm_clk_get(dev, "mclk");
930+
if (IS_ERR(adau->mclk)) {
931+
if (PTR_ERR(adau->mclk) != -ENOENT)
932+
return PTR_ERR(adau->mclk);
933+
/* Clock is optional (for the driver) */
934+
adau->mclk = NULL;
935+
} else if (adau->mclk) {
936+
adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO;
937+
938+
/*
939+
* Any valid PLL output rate will work at this point, use one
940+
* that is likely to be chosen later as well. The register will
941+
* be written when the PLL is powered up for the first time.
942+
*/
943+
ret = adau_calc_pll_cfg(clk_get_rate(adau->mclk), 48000 * 1024,
944+
adau->pll_regs);
945+
if (ret < 0)
946+
return ret;
947+
948+
ret = clk_prepare_enable(adau->mclk);
949+
if (ret)
950+
return ret;
951+
}
952+
860953
adau->regmap = regmap;
861954
adau->switch_mode = switch_mode;
862955
adau->type = type;
@@ -880,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
880973
}
881974
EXPORT_SYMBOL_GPL(adau17x1_probe);
882975

976+
void adau17x1_remove(struct device *dev)
977+
{
978+
struct adau *adau = dev_get_drvdata(dev);
979+
980+
snd_soc_unregister_codec(dev);
981+
if (adau->mclk)
982+
clk_disable_unprepare(adau->mclk);
983+
}
984+
EXPORT_SYMBOL_GPL(adau17x1_remove);
985+
883986
MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
884987
MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
885988
MODULE_LICENSE("GPL");

sound/soc/codecs/adau17x1.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,18 @@ enum adau17x1_pll_src {
2222
};
2323

2424
enum adau17x1_clk_src {
25+
/* Automatically configure PLL based on the sample rate */
26+
ADAU17X1_CLK_SRC_PLL_AUTO,
2527
ADAU17X1_CLK_SRC_MCLK,
2628
ADAU17X1_CLK_SRC_PLL,
2729
};
2830

31+
struct clk;
32+
2933
struct adau {
3034
unsigned int sysclk;
3135
unsigned int pll_freq;
36+
struct clk *mclk;
3237

3338
enum adau17x1_clk_src clk_src;
3439
enum adau17x1_type type;
@@ -52,6 +57,7 @@ int adau17x1_add_routes(struct snd_soc_codec *codec);
5257
int adau17x1_probe(struct device *dev, struct regmap *regmap,
5358
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
5459
const char *firmware_name);
60+
void adau17x1_remove(struct device *dev);
5561
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
5662
enum adau17x1_micbias_voltage micbias);
5763
bool adau17x1_readable_register(struct device *dev, unsigned int reg);

0 commit comments

Comments
 (0)