aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-11-28 03:44:17 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-11-29 07:01:10 -0500
commit40216ce7aa88c2e70869723a0f5929fdbd4a91c5 (patch)
tree58591841674e312f96317621843b365b8fd9fed2 /sound/soc/codecs
parent1db7c89c62b3c0a0ebf8c07975ae907fa404116a (diff)
ASoC: Move SigmaDSP firmware loader to ASoC
It has been pointed out previously, that the firmware subsystem is not the right place for the SigmaDSP firmware loader. Furthermore the SigmaDSP is currently only used in audio products and we are aiming for better integration into the ASoC framework in the future, with support for ALSA controls for firmware parameters and support dynamic power management as well. So the natural choice for the SigmaDSP firmware loader is the ASoC subsystem. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig6
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/adau1701.c2
-rw-r--r--sound/soc/codecs/sigmadsp.c154
-rw-r--r--sound/soc/codecs/sigmadsp.h55
5 files changed, 217 insertions, 2 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 686f45a07f34..593174c78d7b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -141,7 +141,7 @@ config SND_SOC_AD73311
141 tristate 141 tristate
142 142
143config SND_SOC_ADAU1701 143config SND_SOC_ADAU1701
144 select SIGMA 144 select SND_SOC_SIGMADSP
145 tristate 145 tristate
146 146
147config SND_SOC_ADAU1373 147config SND_SOC_ADAU1373
@@ -234,6 +234,10 @@ config SND_SOC_RT5631
234config SND_SOC_SGTL5000 234config SND_SOC_SGTL5000
235 tristate 235 tristate
236 236
237config SND_SOC_SIGMADSP
238 tristate
239 select CRC32
240
237config SND_SOC_SN95031 241config SND_SOC_SN95031
238 tristate 242 tristate
239 243
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 62b01e4e7983..fa15006fcac5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -33,6 +33,7 @@ snd-soc-rt5631-objs := rt5631.o
33snd-soc-sgtl5000-objs := sgtl5000.o 33snd-soc-sgtl5000-objs := sgtl5000.o
34snd-soc-alc5623-objs := alc5623.o 34snd-soc-alc5623-objs := alc5623.o
35snd-soc-alc5632-objs := alc5632.o 35snd-soc-alc5632-objs := alc5632.o
36snd-soc-sigmadsp-objs := sigmadsp.o
36snd-soc-sn95031-objs := sn95031.o 37snd-soc-sn95031-objs := sn95031.o
37snd-soc-spdif-objs := spdif_transciever.o 38snd-soc-spdif-objs := spdif_transciever.o
38snd-soc-ssm2602-objs := ssm2602.o 39snd-soc-ssm2602-objs := ssm2602.o
@@ -134,6 +135,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
134obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 135obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
135obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o 136obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
136obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o 137obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
138obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
137obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o 139obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
138obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o 140obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
139obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o 141obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 8b7e1c50d6e9..6a6af567f02a 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -12,13 +12,13 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/i2c.h> 13#include <linux/i2c.h>
14#include <linux/delay.h> 14#include <linux/delay.h>
15#include <linux/sigma.h>
16#include <linux/slab.h> 15#include <linux/slab.h>
17#include <sound/core.h> 16#include <sound/core.h>
18#include <sound/pcm.h> 17#include <sound/pcm.h>
19#include <sound/pcm_params.h> 18#include <sound/pcm_params.h>
20#include <sound/soc.h> 19#include <sound/soc.h>
21 20
21#include "sigmadsp.h"
22#include "adau1701.h" 22#include "adau1701.h"
23 23
24#define ADAU1701_DSPCTRL 0x1c 24#define ADAU1701_DSPCTRL 0x1c
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
new file mode 100644
index 000000000000..acb97a9834aa
--- /dev/null
+++ b/sound/soc/codecs/sigmadsp.c
@@ -0,0 +1,154 @@
1/*
2 * Load Analog Devices SigmaStudio firmware files
3 *
4 * Copyright 2009-2011 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/crc32.h>
10#include <linux/delay.h>
11#include <linux/firmware.h>
12#include <linux/kernel.h>
13#include <linux/i2c.h>
14#include <linux/module.h>
15
16#include "sigmadsp.h"
17
18static size_t sigma_action_size(struct sigma_action *sa)
19{
20 size_t payload = 0;
21
22 switch (sa->instr) {
23 case SIGMA_ACTION_WRITEXBYTES:
24 case SIGMA_ACTION_WRITESINGLE:
25 case SIGMA_ACTION_WRITESAFELOAD:
26 payload = sigma_action_len(sa);
27 break;
28 default:
29 break;
30 }
31
32 payload = ALIGN(payload, 2);
33
34 return payload + sizeof(struct sigma_action);
35}
36
37/*
38 * Returns a negative error value in case of an error, 0 if processing of
39 * the firmware should be stopped after this action, 1 otherwise.
40 */
41static int
42process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
43{
44 size_t len = sigma_action_len(sa);
45 int ret;
46
47 pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
48 sa->instr, sa->addr, len);
49
50 switch (sa->instr) {
51 case SIGMA_ACTION_WRITEXBYTES:
52 case SIGMA_ACTION_WRITESINGLE:
53 case SIGMA_ACTION_WRITESAFELOAD:
54 ret = i2c_master_send(client, (void *)&sa->addr, len);
55 if (ret < 0)
56 return -EINVAL;
57 break;
58 case SIGMA_ACTION_DELAY:
59 udelay(len);
60 len = 0;
61 break;
62 case SIGMA_ACTION_END:
63 return 0;
64 default:
65 return -EINVAL;
66 }
67
68 return 1;
69}
70
71static int
72process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
73{
74 struct sigma_action *sa;
75 size_t size;
76 int ret;
77
78 while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
79 sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
80
81 size = sigma_action_size(sa);
82 ssfw->pos += size;
83 if (ssfw->pos > ssfw->fw->size || size == 0)
84 break;
85
86 ret = process_sigma_action(client, sa);
87
88 pr_debug("%s: action returned %i\n", __func__, ret);
89
90 if (ret <= 0)
91 return ret;
92 }
93
94 if (ssfw->pos != ssfw->fw->size)
95 return -EINVAL;
96
97 return 0;
98}
99
100int process_sigma_firmware(struct i2c_client *client, const char *name)
101{
102 int ret;
103 struct sigma_firmware_header *ssfw_head;
104 struct sigma_firmware ssfw;
105 const struct firmware *fw;
106 u32 crc;
107
108 pr_debug("%s: loading firmware %s\n", __func__, name);
109
110 /* first load the blob */
111 ret = request_firmware(&fw, name, &client->dev);
112 if (ret) {
113 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
114 return ret;
115 }
116 ssfw.fw = fw;
117
118 /* then verify the header */
119 ret = -EINVAL;
120
121 /*
122 * Reject too small or unreasonable large files. The upper limit has been
123 * chosen a bit arbitrarily, but it should be enough for all practical
124 * purposes and having the limit makes it easier to avoid integer
125 * overflows later in the loading process.
126 */
127 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000)
128 goto done;
129
130 ssfw_head = (void *)fw->data;
131 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
132 goto done;
133
134 crc = crc32(0, fw->data + sizeof(*ssfw_head),
135 fw->size - sizeof(*ssfw_head));
136 pr_debug("%s: crc=%x\n", __func__, crc);
137 if (crc != le32_to_cpu(ssfw_head->crc))
138 goto done;
139
140 ssfw.pos = sizeof(*ssfw_head);
141
142 /* finally process all of the actions */
143 ret = process_sigma_actions(client, &ssfw);
144
145 done:
146 release_firmware(fw);
147
148 pr_debug("%s: loaded %s\n", __func__, name);
149
150 return ret;
151}
152EXPORT_SYMBOL(process_sigma_firmware);
153
154MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
new file mode 100644
index 000000000000..d0de882c0d96
--- /dev/null
+++ b/sound/soc/codecs/sigmadsp.h
@@ -0,0 +1,55 @@
1/*
2 * Load firmware files from Analog Devices SigmaStudio
3 *
4 * Copyright 2009-2011 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#ifndef __SIGMA_FIRMWARE_H__
10#define __SIGMA_FIRMWARE_H__
11
12#include <linux/firmware.h>
13#include <linux/types.h>
14
15struct i2c_client;
16
17#define SIGMA_MAGIC "ADISIGM"
18
19struct sigma_firmware {
20 const struct firmware *fw;
21 size_t pos;
22};
23
24struct sigma_firmware_header {
25 unsigned char magic[7];
26 u8 version;
27 __le32 crc;
28};
29
30enum {
31 SIGMA_ACTION_WRITEXBYTES = 0,
32 SIGMA_ACTION_WRITESINGLE,
33 SIGMA_ACTION_WRITESAFELOAD,
34 SIGMA_ACTION_DELAY,
35 SIGMA_ACTION_PLLWAIT,
36 SIGMA_ACTION_NOOP,
37 SIGMA_ACTION_END,
38};
39
40struct sigma_action {
41 u8 instr;
42 u8 len_hi;
43 __le16 len;
44 __be16 addr;
45 unsigned char payload[];
46};
47
48static inline u32 sigma_action_len(struct sigma_action *sa)
49{
50 return (sa->len_hi << 16) | le16_to_cpu(sa->len);
51}
52
53extern int process_sigma_firmware(struct i2c_client *client, const char *name);
54
55#endif