aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-11-19 12:29:05 -0500
committerMark Brown <broonie@kernel.org>2014-11-20 04:55:34 -0500
commitd48b088e3ec45eeccf0fce0b75378e41428f47e9 (patch)
tree2a81e6d82c6aeeaf35620938f4079d290748b4bf
parent6b25730f68073ee95079d241ea6aa7be00805254 (diff)
ASoC: sigmadsp: Restructure in preparation for fw v2 support
The v2 file format of the SigmaDSP takes a more declarative style compared to the imperative style of the v1 format. In addition some features that are supported with v2 require the driver to keep state around for the firmware. This requires a bit of restructuring of both the firmware loader itself and the drivers making use of the firmware loader. Instead of loading and executing the firmware in place when the DSP is configured the firmware is now loaded at driver probe time. This is required since the new firmware format will in addition to the firmware data itself contain meta information describing the firmware and its requirements and capabilities. Those will for example be used to restrict the supported samplerates advertised by the driver to userspace to the list of samplerates supported for the firmware. This only does the restructuring required by the v2 format, but does not yet add support for the new format itself. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/adau1701.c33
-rw-r--r--sound/soc/codecs/adau1761.c21
-rw-r--r--sound/soc/codecs/adau1781.c30
-rw-r--r--sound/soc/codecs/adau17x1.c54
-rw-r--r--sound/soc/codecs/adau17x1.h9
-rw-r--r--sound/soc/codecs/sigmadsp-i2c.c52
-rw-r--r--sound/soc/codecs/sigmadsp-regmap.c38
-rw-r--r--sound/soc/codecs/sigmadsp.c255
-rw-r--r--sound/soc/codecs/sigmadsp.h53
9 files changed, 424 insertions, 121 deletions
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 370b742117ef..05d5eb5984b6 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -103,6 +103,8 @@ struct adau1701 {
103 unsigned int sysclk; 103 unsigned int sysclk;
104 struct regmap *regmap; 104 struct regmap *regmap;
105 u8 pin_config[12]; 105 u8 pin_config[12];
106
107 struct sigmadsp *sigmadsp;
106}; 108};
107 109
108static const struct snd_kcontrol_new adau1701_controls[] = { 110static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -238,12 +240,14 @@ static int adau1701_reg_read(void *context, unsigned int reg,
238 return 0; 240 return 0;
239} 241}
240 242
241static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) 243static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
244 unsigned int rate)
242{ 245{
243 struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); 246 struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
244 struct i2c_client *client = to_i2c_client(codec->dev);
245 int ret; 247 int ret;
246 248
249 sigmadsp_reset(adau1701->sigmadsp);
250
247 if (clkdiv != ADAU1707_CLKDIV_UNSET && 251 if (clkdiv != ADAU1707_CLKDIV_UNSET &&
248 gpio_is_valid(adau1701->gpio_pll_mode[0]) && 252 gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
249 gpio_is_valid(adau1701->gpio_pll_mode[1])) { 253 gpio_is_valid(adau1701->gpio_pll_mode[1])) {
@@ -284,7 +288,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
284 * know the correct PLL setup 288 * know the correct PLL setup
285 */ 289 */
286 if (clkdiv != ADAU1707_CLKDIV_UNSET) { 290 if (clkdiv != ADAU1707_CLKDIV_UNSET) {
287 ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); 291 ret = sigmadsp_setup(adau1701->sigmadsp, rate);
288 if (ret) { 292 if (ret) {
289 dev_warn(codec->dev, "Failed to load firmware\n"); 293 dev_warn(codec->dev, "Failed to load firmware\n");
290 return ret; 294 return ret;
@@ -385,7 +389,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
385 * firmware upload. 389 * firmware upload.
386 */ 390 */
387 if (clkdiv != adau1701->pll_clkdiv) { 391 if (clkdiv != adau1701->pll_clkdiv) {
388 ret = adau1701_reset(codec, clkdiv); 392 ret = adau1701_reset(codec, clkdiv, params_rate(params));
389 if (ret < 0) 393 if (ret < 0)
390 return ret; 394 return ret;
391 } 395 }
@@ -554,6 +558,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
554 return 0; 558 return 0;
555} 559}
556 560
561static int adau1701_startup(struct snd_pcm_substream *substream,
562 struct snd_soc_dai *dai)
563{
564 struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec);
565
566 return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
567}
568
557#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ 569#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
558 SNDRV_PCM_RATE_192000) 570 SNDRV_PCM_RATE_192000)
559 571
@@ -564,6 +576,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = {
564 .set_fmt = adau1701_set_dai_fmt, 576 .set_fmt = adau1701_set_dai_fmt,
565 .hw_params = adau1701_hw_params, 577 .hw_params = adau1701_hw_params,
566 .digital_mute = adau1701_digital_mute, 578 .digital_mute = adau1701_digital_mute,
579 .startup = adau1701_startup,
567}; 580};
568 581
569static struct snd_soc_dai_driver adau1701_dai = { 582static struct snd_soc_dai_driver adau1701_dai = {
@@ -600,6 +613,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
600 unsigned int val; 613 unsigned int val;
601 struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); 614 struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
602 615
616 ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component);
617 if (ret)
618 return ret;
619
603 /* 620 /*
604 * Let the pll_clkdiv variable default to something that won't happen 621 * Let the pll_clkdiv variable default to something that won't happen
605 * at runtime. That way, we can postpone the firmware download from 622 * at runtime. That way, we can postpone the firmware download from
@@ -609,7 +626,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
609 adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; 626 adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
610 627
611 /* initalize with pre-configured pll mode settings */ 628 /* initalize with pre-configured pll mode settings */
612 ret = adau1701_reset(codec, adau1701->pll_clkdiv); 629 ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
613 if (ret < 0) 630 if (ret < 0)
614 return ret; 631 return ret;
615 632
@@ -722,6 +739,12 @@ static int adau1701_i2c_probe(struct i2c_client *client,
722 adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; 739 adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
723 740
724 i2c_set_clientdata(client, adau1701); 741 i2c_set_clientdata(client, adau1701);
742
743 adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, NULL,
744 ADAU1701_FIRMWARE);
745 if (IS_ERR(adau1701->sigmadsp))
746 return PTR_ERR(adau1701->sigmadsp);
747
725 ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, 748 ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
726 &adau1701_dai, 1); 749 &adau1701_dai, 1);
727 return ret; 750 return ret;
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index 5518ebd6947c..0ae1501f3c11 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -698,11 +698,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
698 ARRAY_SIZE(adau1761_dapm_routes)); 698 ARRAY_SIZE(adau1761_dapm_routes));
699 if (ret) 699 if (ret)
700 return ret; 700 return ret;
701
702 ret = adau17x1_load_firmware(adau, codec->dev,
703 ADAU1761_FIRMWARE);
704 if (ret)
705 dev_warn(codec->dev, "Failed to firmware\n");
706 } 701 }
707 702
708 ret = adau17x1_add_routes(codec); 703 ret = adau17x1_add_routes(codec);
@@ -771,16 +766,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
771 enum adau17x1_type type, void (*switch_mode)(struct device *dev)) 766 enum adau17x1_type type, void (*switch_mode)(struct device *dev))
772{ 767{
773 struct snd_soc_dai_driver *dai_drv; 768 struct snd_soc_dai_driver *dai_drv;
769 const char *firmware_name;
774 int ret; 770 int ret;
775 771
776 ret = adau17x1_probe(dev, regmap, type, switch_mode); 772 if (type == ADAU1361) {
777 if (ret)
778 return ret;
779
780 if (type == ADAU1361)
781 dai_drv = &adau1361_dai_driver; 773 dai_drv = &adau1361_dai_driver;
782 else 774 firmware_name = NULL;
775 } else {
783 dai_drv = &adau1761_dai_driver; 776 dai_drv = &adau1761_dai_driver;
777 firmware_name = ADAU1761_FIRMWARE;
778 }
779
780 ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
781 if (ret)
782 return ret;
784 783
785 return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); 784 return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
786} 785}
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index e9fc00fb13dd..4c8ddc3c69e1 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
385{ 385{
386 struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); 386 struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
387 struct adau *adau = snd_soc_codec_get_drvdata(codec); 387 struct adau *adau = snd_soc_codec_get_drvdata(codec);
388 const char *firmware;
389 int ret; 388 int ret;
390 389
391 ret = adau17x1_add_widgets(codec); 390 ret = adau17x1_add_widgets(codec);
@@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
422 return ret; 421 return ret;
423 } 422 }
424 423
425 switch (adau->type) {
426 case ADAU1381:
427 firmware = ADAU1381_FIRMWARE;
428 break;
429 case ADAU1781:
430 firmware = ADAU1781_FIRMWARE;
431 break;
432 default:
433 return -EINVAL;
434 }
435
436 ret = adau17x1_add_routes(codec); 424 ret = adau17x1_add_routes(codec);
437 if (ret < 0) 425 if (ret < 0)
438 return ret; 426 return ret;
439 427
440 ret = adau17x1_load_firmware(adau, codec->dev, firmware);
441 if (ret)
442 dev_warn(codec->dev, "Failed to load firmware\n");
443
444 return 0; 428 return 0;
445} 429}
446 430
@@ -495,9 +479,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config);
495int adau1781_probe(struct device *dev, struct regmap *regmap, 479int adau1781_probe(struct device *dev, struct regmap *regmap,
496 enum adau17x1_type type, void (*switch_mode)(struct device *dev)) 480 enum adau17x1_type type, void (*switch_mode)(struct device *dev))
497{ 481{
482 const char *firmware_name;
498 int ret; 483 int ret;
499 484
500 ret = adau17x1_probe(dev, regmap, type, switch_mode); 485 switch (type) {
486 case ADAU1381:
487 firmware_name = ADAU1381_FIRMWARE;
488 break;
489 case ADAU1781:
490 firmware_name = ADAU1781_FIRMWARE;
491 break;
492 default:
493 return -EINVAL;
494 }
495
496 ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
501 if (ret) 497 if (ret)
502 return ret; 498 return ret;
503 499
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 3e16c1c64115..1cab34c57413 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -307,6 +307,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
307 struct adau *adau = snd_soc_codec_get_drvdata(codec); 307 struct adau *adau = snd_soc_codec_get_drvdata(codec);
308 unsigned int val, div, dsp_div; 308 unsigned int val, div, dsp_div;
309 unsigned int freq; 309 unsigned int freq;
310 int ret;
310 311
311 if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) 312 if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
312 freq = adau->pll_freq; 313 freq = adau->pll_freq;
@@ -356,6 +357,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
356 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); 357 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
357 } 358 }
358 359
360 if (adau->sigmadsp) {
361 ret = adau17x1_setup_firmware(adau, params_rate(params));
362 if (ret < 0)
363 return ret;
364 }
365
359 if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) 366 if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
360 return 0; 367 return 0;
361 368
@@ -661,12 +668,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
661 return 0; 668 return 0;
662} 669}
663 670
671static int adau17x1_startup(struct snd_pcm_substream *substream,
672 struct snd_soc_dai *dai)
673{
674 struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
675
676 if (adau->sigmadsp)
677 return sigmadsp_restrict_params(adau->sigmadsp, substream);
678
679 return 0;
680}
681
664const struct snd_soc_dai_ops adau17x1_dai_ops = { 682const struct snd_soc_dai_ops adau17x1_dai_ops = {
665 .hw_params = adau17x1_hw_params, 683 .hw_params = adau17x1_hw_params,
666 .set_sysclk = adau17x1_set_dai_sysclk, 684 .set_sysclk = adau17x1_set_dai_sysclk,
667 .set_fmt = adau17x1_set_dai_fmt, 685 .set_fmt = adau17x1_set_dai_fmt,
668 .set_pll = adau17x1_set_dai_pll, 686 .set_pll = adau17x1_set_dai_pll,
669 .set_tdm_slot = adau17x1_set_dai_tdm_slot, 687 .set_tdm_slot = adau17x1_set_dai_tdm_slot,
688 .startup = adau17x1_startup,
670}; 689};
671EXPORT_SYMBOL_GPL(adau17x1_dai_ops); 690EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
672 691
@@ -745,8 +764,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
745} 764}
746EXPORT_SYMBOL_GPL(adau17x1_volatile_register); 765EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
747 766
748int adau17x1_load_firmware(struct adau *adau, struct device *dev, 767int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
749 const char *firmware)
750{ 768{
751 int ret; 769 int ret;
752 int dspsr; 770 int dspsr;
@@ -758,7 +776,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
758 regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); 776 regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
759 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); 777 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
760 778
761 ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware); 779 ret = sigmadsp_setup(adau->sigmadsp, rate);
762 if (ret) { 780 if (ret) {
763 regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); 781 regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
764 return ret; 782 return ret;
@@ -767,7 +785,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
767 785
768 return 0; 786 return 0;
769} 787}
770EXPORT_SYMBOL_GPL(adau17x1_load_firmware); 788EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
771 789
772int adau17x1_add_widgets(struct snd_soc_codec *codec) 790int adau17x1_add_widgets(struct snd_soc_codec *codec)
773{ 791{
@@ -787,8 +805,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
787 ret = snd_soc_dapm_new_controls(&codec->dapm, 805 ret = snd_soc_dapm_new_controls(&codec->dapm,
788 adau17x1_dsp_dapm_widgets, 806 adau17x1_dsp_dapm_widgets,
789 ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); 807 ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
808 if (ret)
809 return ret;
810
811 if (!adau->sigmadsp)
812 return 0;
813
814 ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
815 if (ret) {
816 dev_err(codec->dev, "Failed to attach firmware: %d\n",
817 ret);
818 return ret;
819 }
790 } 820 }
791 return ret; 821
822 return 0;
792} 823}
793EXPORT_SYMBOL_GPL(adau17x1_add_widgets); 824EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
794 825
@@ -829,7 +860,8 @@ int adau17x1_resume(struct snd_soc_codec *codec)
829EXPORT_SYMBOL_GPL(adau17x1_resume); 860EXPORT_SYMBOL_GPL(adau17x1_resume);
830 861
831int adau17x1_probe(struct device *dev, struct regmap *regmap, 862int adau17x1_probe(struct device *dev, struct regmap *regmap,
832 enum adau17x1_type type, void (*switch_mode)(struct device *dev)) 863 enum adau17x1_type type, void (*switch_mode)(struct device *dev),
864 const char *firmware_name)
833{ 865{
834 struct adau *adau; 866 struct adau *adau;
835 867
@@ -846,6 +878,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
846 878
847 dev_set_drvdata(dev, adau); 879 dev_set_drvdata(dev, adau);
848 880
881 if (firmware_name) {
882 adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
883 firmware_name);
884 if (IS_ERR(adau->sigmadsp)) {
885 dev_warn(dev, "Could not find firmware file: %ld\n",
886 PTR_ERR(adau->sigmadsp));
887 adau->sigmadsp = NULL;
888 }
889 }
890
849 if (switch_mode) 891 if (switch_mode)
850 switch_mode(dev); 892 switch_mode(dev);
851 893
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index e4a557fd7155..6861aa3aec02 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -4,6 +4,8 @@
4#include <linux/regmap.h> 4#include <linux/regmap.h>
5#include <linux/platform_data/adau17x1.h> 5#include <linux/platform_data/adau17x1.h>
6 6
7#include "sigmadsp.h"
8
7enum adau17x1_type { 9enum adau17x1_type {
8 ADAU1361, 10 ADAU1361,
9 ADAU1761, 11 ADAU1761,
@@ -42,12 +44,14 @@ struct adau {
42 bool dsp_bypass[2]; 44 bool dsp_bypass[2];
43 45
44 struct regmap *regmap; 46 struct regmap *regmap;
47 struct sigmadsp *sigmadsp;
45}; 48};
46 49
47int adau17x1_add_widgets(struct snd_soc_codec *codec); 50int adau17x1_add_widgets(struct snd_soc_codec *codec);
48int adau17x1_add_routes(struct snd_soc_codec *codec); 51int adau17x1_add_routes(struct snd_soc_codec *codec);
49int adau17x1_probe(struct device *dev, struct regmap *regmap, 52int adau17x1_probe(struct device *dev, struct regmap *regmap,
50 enum adau17x1_type type, void (*switch_mode)(struct device *dev)); 53 enum adau17x1_type type, void (*switch_mode)(struct device *dev),
54 const char *firmware_name);
51int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, 55int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
52 enum adau17x1_micbias_voltage micbias); 56 enum adau17x1_micbias_voltage micbias);
53bool adau17x1_readable_register(struct device *dev, unsigned int reg); 57bool adau17x1_readable_register(struct device *dev, unsigned int reg);
@@ -56,8 +60,7 @@ int adau17x1_resume(struct snd_soc_codec *codec);
56 60
57extern const struct snd_soc_dai_ops adau17x1_dai_ops; 61extern const struct snd_soc_dai_ops adau17x1_dai_ops;
58 62
59int adau17x1_load_firmware(struct adau *adau, struct device *dev, 63int adau17x1_setup_firmware(struct adau *adau, unsigned int rate);
60 const char *firmware);
61bool adau17x1_has_dsp(struct adau *adau); 64bool adau17x1_has_dsp(struct adau *adau);
62 65
63#define ADAU17X1_CLOCK_CONTROL 0x4000 66#define ADAU17X1_CLOCK_CONTROL 0x4000
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c
index 246081aae8ca..bf6a2be72692 100644
--- a/sound/soc/codecs/sigmadsp-i2c.c
+++ b/sound/soc/codecs/sigmadsp-i2c.c
@@ -6,29 +6,59 @@
6 * Licensed under the GPL-2 or later. 6 * Licensed under the GPL-2 or later.
7 */ 7 */
8 8
9#include <linux/i2c.h>
10#include <linux/export.h> 9#include <linux/export.h>
10#include <linux/i2c.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/slab.h>
13#include <asm/unaligned.h>
12 14
13#include "sigmadsp.h" 15#include "sigmadsp.h"
14 16
15static int sigma_action_write_i2c(void *control_data, 17static int sigmadsp_write_i2c(void *control_data,
16 const struct sigma_action *sa, size_t len) 18 unsigned int addr, const uint8_t data[], size_t len)
17{ 19{
18 return i2c_master_send(control_data, (const unsigned char *)&sa->addr, 20 uint8_t *buf;
19 len); 21 int ret;
22
23 buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA);
24 if (!buf)
25 return -ENOMEM;
26
27 put_unaligned_be16(addr, buf);
28 memcpy(buf + 2, data, len);
29
30 ret = i2c_master_send(control_data, buf, len + 2);
31
32 kfree(buf);
33
34 return ret;
20} 35}
21 36
22int process_sigma_firmware(struct i2c_client *client, const char *name) 37/**
38 * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
39 * @client: The parent I2C device
40 * @ops: The sigmadsp_ops to use for this instance
41 * @firmware_name: Name of the firmware file to load
42 *
43 * Allocates a SigmaDSP instance and loads the specified firmware file.
44 *
45 * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
46 */
47struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
48 const struct sigmadsp_ops *ops, const char *firmware_name)
23{ 49{
24 struct sigma_firmware ssfw; 50 struct sigmadsp *sigmadsp;
51
52 sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name);
53 if (IS_ERR(sigmadsp))
54 return sigmadsp;
25 55
26 ssfw.control_data = client; 56 sigmadsp->control_data = client;
27 ssfw.write = sigma_action_write_i2c; 57 sigmadsp->write = sigmadsp_write_i2c;
28 58
29 return _process_sigma_firmware(&client->dev, &ssfw, name); 59 return sigmadsp;
30} 60}
31EXPORT_SYMBOL(process_sigma_firmware); 61EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c);
32 62
33MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 63MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
34MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); 64MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c
index f78ed8d2cfb2..cdc5dda47b88 100644
--- a/sound/soc/codecs/sigmadsp-regmap.c
+++ b/sound/soc/codecs/sigmadsp-regmap.c
@@ -12,24 +12,40 @@
12 12
13#include "sigmadsp.h" 13#include "sigmadsp.h"
14 14
15static int sigma_action_write_regmap(void *control_data, 15static int sigmadsp_write_regmap(void *control_data,
16 const struct sigma_action *sa, size_t len) 16 unsigned int addr, const uint8_t data[], size_t len)
17{ 17{
18 return regmap_raw_write(control_data, be16_to_cpu(sa->addr), 18 return regmap_raw_write(control_data, addr,
19 sa->payload, len - 2); 19 data, len);
20} 20}
21 21
22int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, 22/**
23 const char *name) 23 * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
24 * @dev: The parent device
25 * @regmap: Regmap instance to use
26 * @ops: The sigmadsp_ops to use for this instance
27 * @firmware_name: Name of the firmware file to load
28 *
29 * Allocates a SigmaDSP instance and loads the specified firmware file.
30 *
31 * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
32 */
33struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
34 struct regmap *regmap, const struct sigmadsp_ops *ops,
35 const char *firmware_name)
24{ 36{
25 struct sigma_firmware ssfw; 37 struct sigmadsp *sigmadsp;
38
39 sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name);
40 if (IS_ERR(sigmadsp))
41 return sigmadsp;
26 42
27 ssfw.control_data = regmap; 43 sigmadsp->control_data = regmap;
28 ssfw.write = sigma_action_write_regmap; 44 sigmadsp->write = sigmadsp_write_regmap;
29 45
30 return _process_sigma_firmware(dev, &ssfw, name); 46 return sigmadsp;
31} 47}
32EXPORT_SYMBOL(process_sigma_firmware_regmap); 48EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap);
33 49
34MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 50MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
35MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); 51MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index 4fd31434276b..34e63b554c31 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Load Analog Devices SigmaStudio firmware files 2 * Load Analog Devices SigmaStudio firmware files
3 * 3 *
4 * Copyright 2009-2011 Analog Devices Inc. 4 * Copyright 2009-2014 Analog Devices Inc.
5 * 5 *
6 * Licensed under the GPL-2 or later. 6 * Licensed under the GPL-2 or later.
7 */ 7 */
@@ -12,11 +12,21 @@
12#include <linux/i2c.h> 12#include <linux/i2c.h>
13#include <linux/regmap.h> 13#include <linux/regmap.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/slab.h>
16
17#include <sound/soc.h>
15 18
16#include "sigmadsp.h" 19#include "sigmadsp.h"
17 20
18#define SIGMA_MAGIC "ADISIGM" 21#define SIGMA_MAGIC "ADISIGM"
19 22
23struct sigmadsp_data {
24 struct list_head head;
25 unsigned int addr;
26 unsigned int length;
27 uint8_t data[];
28};
29
20struct sigma_firmware_header { 30struct sigma_firmware_header {
21 unsigned char magic[7]; 31 unsigned char magic[7];
22 u8 version; 32 u8 version;
@@ -30,6 +40,20 @@ enum {
30 SIGMA_ACTION_END, 40 SIGMA_ACTION_END,
31}; 41};
32 42
43struct sigma_action {
44 u8 instr;
45 u8 len_hi;
46 __le16 len;
47 __be16 addr;
48 unsigned char payload[];
49} __packed;
50
51static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr,
52 const uint8_t data[], size_t len)
53{
54 return sigmadsp->write(sigmadsp->control_data, addr, data, len);
55}
56
33static inline u32 sigma_action_len(struct sigma_action *sa) 57static inline u32 sigma_action_len(struct sigma_action *sa)
34{ 58{
35 return (sa->len_hi << 16) | le16_to_cpu(sa->len); 59 return (sa->len_hi << 16) | le16_to_cpu(sa->len);
@@ -58,11 +82,11 @@ static size_t sigma_action_size(struct sigma_action *sa)
58 * Returns a negative error value in case of an error, 0 if processing of 82 * Returns a negative error value in case of an error, 0 if processing of
59 * the firmware should be stopped after this action, 1 otherwise. 83 * the firmware should be stopped after this action, 1 otherwise.
60 */ 84 */
61static int 85static int process_sigma_action(struct sigmadsp *sigmadsp,
62process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) 86 struct sigma_action *sa)
63{ 87{
64 size_t len = sigma_action_len(sa); 88 size_t len = sigma_action_len(sa);
65 int ret; 89 struct sigmadsp_data *data;
66 90
67 pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, 91 pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
68 sa->instr, sa->addr, len); 92 sa->instr, sa->addr, len);
@@ -71,9 +95,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
71 case SIGMA_ACTION_WRITEXBYTES: 95 case SIGMA_ACTION_WRITEXBYTES:
72 case SIGMA_ACTION_WRITESINGLE: 96 case SIGMA_ACTION_WRITESINGLE:
73 case SIGMA_ACTION_WRITESAFELOAD: 97 case SIGMA_ACTION_WRITESAFELOAD:
74 ret = ssfw->write(ssfw->control_data, sa, len); 98 if (len < 3)
75 if (ret < 0)
76 return -EINVAL; 99 return -EINVAL;
100
101 data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL);
102 if (!data)
103 return -ENOMEM;
104
105 data->addr = be16_to_cpu(sa->addr);
106 data->length = len - 2;
107 memcpy(data->data, sa->payload, data->length);
108 list_add_tail(&data->head, &sigmadsp->data_list);
77 break; 109 break;
78 case SIGMA_ACTION_END: 110 case SIGMA_ACTION_END:
79 return 0; 111 return 0;
@@ -84,22 +116,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
84 return 1; 116 return 1;
85} 117}
86 118
87static int 119static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp,
88process_sigma_actions(struct sigma_firmware *ssfw) 120 const struct firmware *fw)
89{ 121{
90 struct sigma_action *sa; 122 struct sigma_action *sa;
91 size_t size; 123 size_t size, pos;
92 int ret; 124 int ret;
93 125
94 while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { 126 pos = sizeof(struct sigma_firmware_header);
95 sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); 127
128 while (pos + sizeof(*sa) <= fw->size) {
129 sa = (struct sigma_action *)(fw->data + pos);
96 130
97 size = sigma_action_size(sa); 131 size = sigma_action_size(sa);
98 ssfw->pos += size; 132 pos += size;
99 if (ssfw->pos > ssfw->fw->size || size == 0) 133 if (pos > fw->size || size == 0)
100 break; 134 break;
101 135
102 ret = process_sigma_action(ssfw, sa); 136 ret = process_sigma_action(sigmadsp, sa);
103 137
104 pr_debug("%s: action returned %i\n", __func__, ret); 138 pr_debug("%s: action returned %i\n", __func__, ret);
105 139
@@ -107,29 +141,40 @@ process_sigma_actions(struct sigma_firmware *ssfw)
107 return ret; 141 return ret;
108 } 142 }
109 143
110 if (ssfw->pos != ssfw->fw->size) 144 if (pos != fw->size)
111 return -EINVAL; 145 return -EINVAL;
112 146
113 return 0; 147 return 0;
114} 148}
115 149
116int _process_sigma_firmware(struct device *dev, 150static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp)
117 struct sigma_firmware *ssfw, const char *name)
118{ 151{
119 int ret; 152 struct sigmadsp_data *data, *_data;
120 struct sigma_firmware_header *ssfw_head; 153
154 list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head)
155 kfree(data);
156
157 INIT_LIST_HEAD(&sigmadsp->data_list);
158}
159
160static void devm_sigmadsp_release(struct device *dev, void *res)
161{
162 sigmadsp_firmware_release((struct sigmadsp *)res);
163}
164
165static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
166{
167 const struct sigma_firmware_header *ssfw_head;
121 const struct firmware *fw; 168 const struct firmware *fw;
169 int ret;
122 u32 crc; 170 u32 crc;
123 171
124 pr_debug("%s: loading firmware %s\n", __func__, name);
125
126 /* first load the blob */ 172 /* first load the blob */
127 ret = request_firmware(&fw, name, dev); 173 ret = request_firmware(&fw, name, sigmadsp->dev);
128 if (ret) { 174 if (ret) {
129 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); 175 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
130 return ret; 176 goto done;
131 } 177 }
132 ssfw->fw = fw;
133 178
134 /* then verify the header */ 179 /* then verify the header */
135 ret = -EINVAL; 180 ret = -EINVAL;
@@ -141,20 +186,13 @@ int _process_sigma_firmware(struct device *dev,
141 * overflows later in the loading process. 186 * overflows later in the loading process.
142 */ 187 */
143 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { 188 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
144 dev_err(dev, "Failed to load firmware: Invalid size\n"); 189 dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
145 goto done; 190 goto done;
146 } 191 }
147 192
148 ssfw_head = (void *)fw->data; 193 ssfw_head = (void *)fw->data;
149 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { 194 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
150 dev_err(dev, "Failed to load firmware: Invalid magic\n"); 195 dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
151 goto done;
152 }
153
154 if (ssfw_head->version != 1) {
155 dev_err(dev,
156 "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n",
157 ssfw_head->version);
158 goto done; 196 goto done;
159 } 197 }
160 198
@@ -162,23 +200,160 @@ int _process_sigma_firmware(struct device *dev,
162 fw->size - sizeof(*ssfw_head)); 200 fw->size - sizeof(*ssfw_head));
163 pr_debug("%s: crc=%x\n", __func__, crc); 201 pr_debug("%s: crc=%x\n", __func__, crc);
164 if (crc != le32_to_cpu(ssfw_head->crc)) { 202 if (crc != le32_to_cpu(ssfw_head->crc)) {
165 dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", 203 dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
166 le32_to_cpu(ssfw_head->crc), crc); 204 le32_to_cpu(ssfw_head->crc), crc);
167 goto done; 205 goto done;
168 } 206 }
169 207
170 ssfw->pos = sizeof(*ssfw_head); 208 switch (ssfw_head->version) {
209 case 1:
210 ret = sigmadsp_fw_load_v1(sigmadsp, fw);
211 break;
212 default:
213 dev_err(sigmadsp->dev,
214 "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n",
215 ssfw_head->version);
216 ret = -EINVAL;
217 break;
218 }
171 219
172 /* finally process all of the actions */ 220 if (ret)
173 ret = process_sigma_actions(ssfw); 221 sigmadsp_firmware_release(sigmadsp);
174 222
175 done: 223done:
176 release_firmware(fw); 224 release_firmware(fw);
177 225
178 pr_debug("%s: loaded %s\n", __func__, name); 226 return ret;
227}
228
229static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev,
230 const struct sigmadsp_ops *ops, const char *firmware_name)
231{
232 sigmadsp->ops = ops;
233 sigmadsp->dev = dev;
234
235 INIT_LIST_HEAD(&sigmadsp->data_list);
236
237 return sigmadsp_firmware_load(sigmadsp, firmware_name);
238}
239
240/**
241 * devm_sigmadsp_init() - Initialize SigmaDSP instance
242 * @dev: The parent device
243 * @ops: The sigmadsp_ops to use for this instance
244 * @firmware_name: Name of the firmware file to load
245 *
246 * Allocates a SigmaDSP instance and loads the specified firmware file.
247 *
248 * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
249 */
250struct sigmadsp *devm_sigmadsp_init(struct device *dev,
251 const struct sigmadsp_ops *ops, const char *firmware_name)
252{
253 struct sigmadsp *sigmadsp;
254 int ret;
255
256 sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp),
257 GFP_KERNEL);
258 if (!sigmadsp)
259 return ERR_PTR(-ENOMEM);
260
261 ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name);
262 if (ret) {
263 devres_free(sigmadsp);
264 return ERR_PTR(ret);
265 }
266
267 devres_add(dev, sigmadsp);
268
269 return sigmadsp;
270}
271EXPORT_SYMBOL_GPL(devm_sigmadsp_init);
272
273/**
274 * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component
275 * @sigmadsp: The sigmadsp instance to attach
276 * @component: The component to attach to
277 *
278 * Typically called in the components probe callback.
279 *
280 * Note, once this function has been called the firmware must not be released
281 * until after the ALSA snd_card that the component belongs to has been
282 * disconnected, even if sigmadsp_attach() returns an error.
283 */
284int sigmadsp_attach(struct sigmadsp *sigmadsp,
285 struct snd_soc_component *component)
286{
287 sigmadsp->component = component;
288
289 return 0;
290}
291EXPORT_SYMBOL_GPL(sigmadsp_attach);
292
293/**
294 * sigmadsp_setup() - Setup the DSP for the specified samplerate
295 * @sigmadsp: The sigmadsp instance to configure
296 * @samplerate: The samplerate the DSP should be configured for
297 *
298 * Loads the appropriate firmware program and parameter memory (if not already
299 * loaded) and enables the controls for the specified samplerate. Any control
300 * parameter changes that have been made previously will be restored.
301 *
302 * Returns 0 on success, a negative error code otherwise.
303 */
304int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate)
305{
306 struct sigmadsp_data *data;
307 int ret;
308
309 if (sigmadsp->current_samplerate == samplerate)
310 return 0;
311
312 list_for_each_entry(data, &sigmadsp->data_list, head) {
313 ret = sigmadsp_write(sigmadsp, data->addr, data->data,
314 data->length);
315 if (ret)
316 goto err;
317 }
318
319 sigmadsp->current_samplerate = samplerate;
320
321 return 0;
322err:
323 sigmadsp_reset(sigmadsp);
179 324
180 return ret; 325 return ret;
181} 326}
182EXPORT_SYMBOL_GPL(_process_sigma_firmware); 327EXPORT_SYMBOL_GPL(sigmadsp_setup);
328
329/**
330 * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset
331 * @sigmadsp: The sigmadsp instance to reset
332 *
333 * Should be called whenever the DSP has been reset and parameter and program
334 * memory need to be re-loaded.
335 */
336void sigmadsp_reset(struct sigmadsp *sigmadsp)
337{
338 sigmadsp->current_samplerate = 0;
339}
340EXPORT_SYMBOL_GPL(sigmadsp_reset);
341
342/**
343 * sigmadsp_restrict_params() - Applies DSP firmware specific constraints
344 * @sigmadsp: The sigmadsp instance
345 * @substream: The substream to restrict
346 *
347 * Applies samplerate constraints that may be required by the firmware Should
348 * typically be called from the CODEC/component drivers startup callback.
349 *
350 * Returns 0 on success, a negative error code otherwise.
351 */
352int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
353 struct snd_pcm_substream *substream)
354{
355 return 0;
356}
357EXPORT_SYMBOL_GPL(sigmadsp_restrict_params);
183 358
184MODULE_LICENSE("GPL"); 359MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
index c47cd23e9827..a6be91a4c2dc 100644
--- a/sound/soc/codecs/sigmadsp.h
+++ b/sound/soc/codecs/sigmadsp.h
@@ -11,31 +11,50 @@
11 11
12#include <linux/device.h> 12#include <linux/device.h>
13#include <linux/regmap.h> 13#include <linux/regmap.h>
14#include <linux/list.h>
14 15
15struct sigma_action { 16#include <sound/pcm.h>
16 u8 instr;
17 u8 len_hi;
18 __le16 len;
19 __be16 addr;
20 unsigned char payload[];
21} __packed;
22 17
23struct sigma_firmware { 18struct sigmadsp;
24 const struct firmware *fw; 19struct snd_soc_component;
25 size_t pos; 20struct snd_pcm_substream;
21
22struct sigmadsp_ops {
23 int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr,
24 const uint8_t *data, size_t len);
25};
26
27struct sigmadsp {
28 const struct sigmadsp_ops *ops;
29
30 struct list_head data_list;
31
32 unsigned int current_samplerate;
33 struct snd_soc_component *component;
34 struct device *dev;
26 35
27 void *control_data; 36 void *control_data;
28 int (*write)(void *control_data, const struct sigma_action *sa, 37 int (*write)(void *, unsigned int, const uint8_t *, size_t);
29 size_t len);
30}; 38};
31 39
32int _process_sigma_firmware(struct device *dev, 40struct sigmadsp *devm_sigmadsp_init(struct device *dev,
33 struct sigma_firmware *ssfw, const char *name); 41 const struct sigmadsp_ops *ops, const char *firmware_name);
42void sigmadsp_reset(struct sigmadsp *sigmadsp);
43
44int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
45 struct snd_pcm_substream *substream);
34 46
35struct i2c_client; 47struct i2c_client;
36 48
37extern int process_sigma_firmware(struct i2c_client *client, const char *name); 49struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
38extern int process_sigma_firmware_regmap(struct device *dev, 50 struct regmap *regmap, const struct sigmadsp_ops *ops,
39 struct regmap *regmap, const char *name); 51 const char *firmware_name);
52struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
53 const struct sigmadsp_ops *ops, const char *firmware_name);
54
55int sigmadsp_attach(struct sigmadsp *sigmadsp,
56 struct snd_soc_component *component);
57int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate);
58void sigmadsp_reset(struct sigmadsp *sigmadsp);
40 59
41#endif 60#endif