diff options
author | Daniel Mack <zonque@gmail.com> | 2013-06-24 10:31:30 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-06-25 05:32:08 -0400 |
commit | 2352d4bf43b105ec2da5f43211db4a4c9bf34d4e (patch) | |
tree | 71c6740303824f89611a11a918dd9ce16144213a /sound | |
parent | de9fc724daaf5ceaf0af6ef23b2b3b1d933273e3 (diff) |
ASoC: adau1701: allow configuration of PLL mode pins
The ADAU1701 has 2 hardware pins to configure the PLL mode in accordance
to the MCLK-to-LRCLK ratio. These pins have to be stable before the chip
is released from reset, and a full reset cycle, including a new firmware
download is needed whenever they change.
This patch adds GPIO properties to the DT bindings of the Codec, and
implements makes the set_sysclk memorize the configured sysclk.
Because the run-time parameters are unknown at probe time, the first
firmware download is postponed to the first hw_params call, when the
driver can determine the mclk/lrclk divider. Subsequent downloads
are only issued when the divider configuration changes.
Signed-off-by: Daniel Mack <zonque@gmail.com>
Acked-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/adau1701.c | 105 |
1 files changed, 98 insertions, 7 deletions
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 997fc3b881fe..770d90ee5f92 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -87,11 +87,16 @@ | |||
87 | #define ADAU1701_OSCIPOW_OPD 0x04 | 87 | #define ADAU1701_OSCIPOW_OPD 0x04 |
88 | #define ADAU1701_DACSET_DACINIT 1 | 88 | #define ADAU1701_DACSET_DACINIT 1 |
89 | 89 | ||
90 | #define ADAU1707_CLKDIV_UNSET (-1UL) | ||
91 | |||
90 | #define ADAU1701_FIRMWARE "adau1701.bin" | 92 | #define ADAU1701_FIRMWARE "adau1701.bin" |
91 | 93 | ||
92 | struct adau1701 { | 94 | struct adau1701 { |
93 | int gpio_nreset; | 95 | int gpio_nreset; |
96 | int gpio_pll_mode[2]; | ||
94 | unsigned int dai_fmt; | 97 | unsigned int dai_fmt; |
98 | unsigned int pll_clkdiv; | ||
99 | unsigned int sysclk; | ||
95 | }; | 100 | }; |
96 | 101 | ||
97 | static const struct snd_kcontrol_new adau1701_controls[] = { | 102 | static const struct snd_kcontrol_new adau1701_controls[] = { |
@@ -184,12 +189,38 @@ static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) | |||
184 | return value; | 189 | return value; |
185 | } | 190 | } |
186 | 191 | ||
187 | static int adau1701_reset(struct snd_soc_codec *codec) | 192 | static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) |
188 | { | 193 | { |
189 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | 194 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); |
190 | struct i2c_client *client = to_i2c_client(codec->dev); | 195 | struct i2c_client *client = to_i2c_client(codec->dev); |
191 | int ret; | 196 | int ret; |
192 | 197 | ||
198 | if (clkdiv != ADAU1707_CLKDIV_UNSET && | ||
199 | gpio_is_valid(adau1701->gpio_pll_mode[0]) && | ||
200 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { | ||
201 | switch (clkdiv) { | ||
202 | case 64: | ||
203 | gpio_set_value(adau1701->gpio_pll_mode[0], 0); | ||
204 | gpio_set_value(adau1701->gpio_pll_mode[1], 0); | ||
205 | break; | ||
206 | case 256: | ||
207 | gpio_set_value(adau1701->gpio_pll_mode[0], 0); | ||
208 | gpio_set_value(adau1701->gpio_pll_mode[1], 1); | ||
209 | break; | ||
210 | case 384: | ||
211 | gpio_set_value(adau1701->gpio_pll_mode[0], 1); | ||
212 | gpio_set_value(adau1701->gpio_pll_mode[1], 0); | ||
213 | break; | ||
214 | case 0: /* fallback */ | ||
215 | case 512: | ||
216 | gpio_set_value(adau1701->gpio_pll_mode[0], 1); | ||
217 | gpio_set_value(adau1701->gpio_pll_mode[1], 1); | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | adau1701->pll_clkdiv = clkdiv; | ||
223 | |||
193 | if (gpio_is_valid(adau1701->gpio_nreset)) { | 224 | if (gpio_is_valid(adau1701->gpio_nreset)) { |
194 | gpio_set_value(adau1701->gpio_nreset, 0); | 225 | gpio_set_value(adau1701->gpio_nreset, 0); |
195 | /* minimum reset time is 20ns */ | 226 | /* minimum reset time is 20ns */ |
@@ -199,10 +230,16 @@ static int adau1701_reset(struct snd_soc_codec *codec) | |||
199 | mdelay(85); | 230 | mdelay(85); |
200 | } | 231 | } |
201 | 232 | ||
202 | ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); | 233 | /* |
203 | if (ret) { | 234 | * Postpone the firmware download to a point in time when we |
204 | dev_warn(codec->dev, "Failed to load firmware\n"); | 235 | * know the correct PLL setup |
205 | return ret; | 236 | */ |
237 | if (clkdiv != ADAU1707_CLKDIV_UNSET) { | ||
238 | ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); | ||
239 | if (ret) { | ||
240 | dev_warn(codec->dev, "Failed to load firmware\n"); | ||
241 | return ret; | ||
242 | } | ||
206 | } | 243 | } |
207 | 244 | ||
208 | snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); | 245 | snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); |
@@ -285,8 +322,22 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, | |||
285 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 322 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
286 | { | 323 | { |
287 | struct snd_soc_codec *codec = dai->codec; | 324 | struct snd_soc_codec *codec = dai->codec; |
325 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
326 | unsigned int clkdiv = adau1701->sysclk / params_rate(params); | ||
288 | snd_pcm_format_t format; | 327 | snd_pcm_format_t format; |
289 | unsigned int val; | 328 | unsigned int val; |
329 | int ret; | ||
330 | |||
331 | /* | ||
332 | * If the mclk/lrclk ratio changes, the chip needs updated PLL | ||
333 | * mode GPIO settings, and a full reset cycle, including a new | ||
334 | * firmware upload. | ||
335 | */ | ||
336 | if (clkdiv != adau1701->pll_clkdiv) { | ||
337 | ret = adau1701_reset(codec, clkdiv); | ||
338 | if (ret < 0) | ||
339 | return ret; | ||
340 | } | ||
290 | 341 | ||
291 | switch (params_rate(params)) { | 342 | switch (params_rate(params)) { |
292 | case 192000: | 343 | case 192000: |
@@ -429,6 +480,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
429 | int source, unsigned int freq, int dir) | 480 | int source, unsigned int freq, int dir) |
430 | { | 481 | { |
431 | unsigned int val; | 482 | unsigned int val; |
483 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
432 | 484 | ||
433 | switch (clk_id) { | 485 | switch (clk_id) { |
434 | case ADAU1701_CLK_SRC_OSC: | 486 | case ADAU1701_CLK_SRC_OSC: |
@@ -442,6 +494,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
442 | } | 494 | } |
443 | 495 | ||
444 | snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); | 496 | snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); |
497 | adau1701->sysclk = freq; | ||
445 | 498 | ||
446 | return 0; | 499 | return 0; |
447 | } | 500 | } |
@@ -489,11 +542,21 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids); | |||
489 | static int adau1701_probe(struct snd_soc_codec *codec) | 542 | static int adau1701_probe(struct snd_soc_codec *codec) |
490 | { | 543 | { |
491 | int ret; | 544 | int ret; |
545 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
492 | 546 | ||
493 | codec->control_data = to_i2c_client(codec->dev); | 547 | codec->control_data = to_i2c_client(codec->dev); |
494 | 548 | ||
495 | ret = adau1701_reset(codec); | 549 | /* |
496 | if (ret) | 550 | * Let the pll_clkdiv variable default to something that won't happen |
551 | * at runtime. That way, we can postpone the firmware download from | ||
552 | * adau1701_reset() to a point in time when we know the correct PLL | ||
553 | * mode parameters. | ||
554 | */ | ||
555 | adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; | ||
556 | |||
557 | /* initalize with pre-configured pll mode settings */ | ||
558 | ret = adau1701_reset(codec, adau1701->pll_clkdiv); | ||
559 | if (ret < 0) | ||
497 | return ret; | 560 | return ret; |
498 | 561 | ||
499 | return 0; | 562 | return 0; |
@@ -526,6 +589,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
526 | struct adau1701 *adau1701; | 589 | struct adau1701 *adau1701; |
527 | struct device *dev = &client->dev; | 590 | struct device *dev = &client->dev; |
528 | int gpio_nreset = -EINVAL; | 591 | int gpio_nreset = -EINVAL; |
592 | int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; | ||
529 | int ret; | 593 | int ret; |
530 | 594 | ||
531 | adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); | 595 | adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); |
@@ -536,6 +600,16 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
536 | gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); | 600 | gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); |
537 | if (gpio_nreset < 0 && gpio_nreset != -ENOENT) | 601 | if (gpio_nreset < 0 && gpio_nreset != -ENOENT) |
538 | return gpio_nreset; | 602 | return gpio_nreset; |
603 | |||
604 | gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, | ||
605 | "adi,pll-mode-gpios", 0); | ||
606 | if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) | ||
607 | return gpio_pll_mode[0]; | ||
608 | |||
609 | gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, | ||
610 | "adi,pll-mode-gpios", 1); | ||
611 | if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) | ||
612 | return gpio_pll_mode[1]; | ||
539 | } | 613 | } |
540 | 614 | ||
541 | if (gpio_is_valid(gpio_nreset)) { | 615 | if (gpio_is_valid(gpio_nreset)) { |
@@ -545,7 +619,24 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
545 | return ret; | 619 | return ret; |
546 | } | 620 | } |
547 | 621 | ||
622 | if (gpio_is_valid(gpio_pll_mode[0]) && | ||
623 | gpio_is_valid(gpio_pll_mode[1])) { | ||
624 | ret = devm_gpio_request_one(dev, gpio_pll_mode[0], | ||
625 | GPIOF_OUT_INIT_LOW, | ||
626 | "ADAU1701 PLL mode 0"); | ||
627 | if (ret < 0) | ||
628 | return ret; | ||
629 | |||
630 | ret = devm_gpio_request_one(dev, gpio_pll_mode[1], | ||
631 | GPIOF_OUT_INIT_LOW, | ||
632 | "ADAU1701 PLL mode 1"); | ||
633 | if (ret < 0) | ||
634 | return ret; | ||
635 | } | ||
636 | |||
548 | adau1701->gpio_nreset = gpio_nreset; | 637 | adau1701->gpio_nreset = gpio_nreset; |
638 | adau1701->gpio_pll_mode[0] = gpio_pll_mode[0]; | ||
639 | adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; | ||
549 | 640 | ||
550 | i2c_set_clientdata(client, adau1701); | 641 | i2c_set_clientdata(client, adau1701); |
551 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, | 642 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, |