aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/sigmadsp.c75
-rw-r--r--sound/soc/codecs/sigmadsp.h5
2 files changed, 67 insertions, 13 deletions
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index aa223c56b2b6..5be42bf56996 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -11,6 +11,7 @@
11#include <linux/firmware.h> 11#include <linux/firmware.h>
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/i2c.h> 13#include <linux/i2c.h>
14#include <linux/regmap.h>
14#include <linux/module.h> 15#include <linux/module.h>
15 16
16#include "sigmadsp.h" 17#include "sigmadsp.h"
@@ -44,6 +45,10 @@ struct sigma_action {
44struct sigma_firmware { 45struct sigma_firmware {
45 const struct firmware *fw; 46 const struct firmware *fw;
46 size_t pos; 47 size_t pos;
48
49 void *control_data;
50 int (*write)(void *control_data, const struct sigma_action *sa,
51 size_t len);
47}; 52};
48 53
49static inline u32 sigma_action_len(struct sigma_action *sa) 54static inline u32 sigma_action_len(struct sigma_action *sa)
@@ -75,7 +80,7 @@ static size_t sigma_action_size(struct sigma_action *sa)
75 * the firmware should be stopped after this action, 1 otherwise. 80 * the firmware should be stopped after this action, 1 otherwise.
76 */ 81 */
77static int 82static int
78process_sigma_action(struct i2c_client *client, struct sigma_action *sa) 83process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
79{ 84{
80 size_t len = sigma_action_len(sa); 85 size_t len = sigma_action_len(sa);
81 int ret; 86 int ret;
@@ -87,7 +92,7 @@ process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
87 case SIGMA_ACTION_WRITEXBYTES: 92 case SIGMA_ACTION_WRITEXBYTES:
88 case SIGMA_ACTION_WRITESINGLE: 93 case SIGMA_ACTION_WRITESINGLE:
89 case SIGMA_ACTION_WRITESAFELOAD: 94 case SIGMA_ACTION_WRITESAFELOAD:
90 ret = i2c_master_send(client, (void *)&sa->addr, len); 95 ret = ssfw->write(ssfw->control_data, sa, len);
91 if (ret < 0) 96 if (ret < 0)
92 return -EINVAL; 97 return -EINVAL;
93 break; 98 break;
@@ -105,7 +110,7 @@ process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
105} 110}
106 111
107static int 112static int
108process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw) 113process_sigma_actions(struct sigma_firmware *ssfw)
109{ 114{
110 struct sigma_action *sa; 115 struct sigma_action *sa;
111 size_t size; 116 size_t size;
@@ -119,7 +124,7 @@ process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
119 if (ssfw->pos > ssfw->fw->size || size == 0) 124 if (ssfw->pos > ssfw->fw->size || size == 0)
120 break; 125 break;
121 126
122 ret = process_sigma_action(client, sa); 127 ret = process_sigma_action(ssfw, sa);
123 128
124 pr_debug("%s: action returned %i\n", __func__, ret); 129 pr_debug("%s: action returned %i\n", __func__, ret);
125 130
@@ -133,23 +138,23 @@ process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
133 return 0; 138 return 0;
134} 139}
135 140
136int process_sigma_firmware(struct i2c_client *client, const char *name) 141static int _process_sigma_firmware(struct device *dev,
142 struct sigma_firmware *ssfw, const char *name)
137{ 143{
138 int ret; 144 int ret;
139 struct sigma_firmware_header *ssfw_head; 145 struct sigma_firmware_header *ssfw_head;
140 struct sigma_firmware ssfw;
141 const struct firmware *fw; 146 const struct firmware *fw;
142 u32 crc; 147 u32 crc;
143 148
144 pr_debug("%s: loading firmware %s\n", __func__, name); 149 pr_debug("%s: loading firmware %s\n", __func__, name);
145 150
146 /* first load the blob */ 151 /* first load the blob */
147 ret = request_firmware(&fw, name, &client->dev); 152 ret = request_firmware(&fw, name, dev);
148 if (ret) { 153 if (ret) {
149 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); 154 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
150 return ret; 155 return ret;
151 } 156 }
152 ssfw.fw = fw; 157 ssfw->fw = fw;
153 158
154 /* then verify the header */ 159 /* then verify the header */
155 ret = -EINVAL; 160 ret = -EINVAL;
@@ -161,13 +166,13 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
161 * overflows later in the loading process. 166 * overflows later in the loading process.
162 */ 167 */
163 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { 168 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
164 dev_err(&client->dev, "Failed to load firmware: Invalid size\n"); 169 dev_err(dev, "Failed to load firmware: Invalid size\n");
165 goto done; 170 goto done;
166 } 171 }
167 172
168 ssfw_head = (void *)fw->data; 173 ssfw_head = (void *)fw->data;
169 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { 174 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
170 dev_err(&client->dev, "Failed to load firmware: Invalid magic\n"); 175 dev_err(dev, "Failed to load firmware: Invalid magic\n");
171 goto done; 176 goto done;
172 } 177 }
173 178
@@ -175,15 +180,15 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
175 fw->size - sizeof(*ssfw_head)); 180 fw->size - sizeof(*ssfw_head));
176 pr_debug("%s: crc=%x\n", __func__, crc); 181 pr_debug("%s: crc=%x\n", __func__, crc);
177 if (crc != le32_to_cpu(ssfw_head->crc)) { 182 if (crc != le32_to_cpu(ssfw_head->crc)) {
178 dev_err(&client->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", 183 dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
179 le32_to_cpu(ssfw_head->crc), crc); 184 le32_to_cpu(ssfw_head->crc), crc);
180 goto done; 185 goto done;
181 } 186 }
182 187
183 ssfw.pos = sizeof(*ssfw_head); 188 ssfw->pos = sizeof(*ssfw_head);
184 189
185 /* finally process all of the actions */ 190 /* finally process all of the actions */
186 ret = process_sigma_actions(client, &ssfw); 191 ret = process_sigma_actions(ssfw);
187 192
188 done: 193 done:
189 release_firmware(fw); 194 release_firmware(fw);
@@ -192,6 +197,50 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
192 197
193 return ret; 198 return ret;
194} 199}
200
201#if IS_ENABLED(CONFIG_I2C)
202
203static int sigma_action_write_i2c(void *control_data,
204 const struct sigma_action *sa, size_t len)
205{
206 return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
207 len);
208}
209
210int process_sigma_firmware(struct i2c_client *client, const char *name)
211{
212 struct sigma_firmware ssfw;
213
214 ssfw.control_data = client;
215 ssfw.write = sigma_action_write_i2c;
216
217 return _process_sigma_firmware(&client->dev, &ssfw, name);
218}
195EXPORT_SYMBOL(process_sigma_firmware); 219EXPORT_SYMBOL(process_sigma_firmware);
196 220
221#endif
222
223#if IS_ENABLED(CONFIG_REGMAP)
224
225static int sigma_action_write_regmap(void *control_data,
226 const struct sigma_action *sa, size_t len)
227{
228 return regmap_raw_write(control_data, le16_to_cpu(sa->addr),
229 sa->payload, len - 2);
230}
231
232int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
233 const char *name)
234{
235 struct sigma_firmware ssfw;
236
237 ssfw.control_data = regmap;
238 ssfw.write = sigma_action_write_regmap;
239
240 return _process_sigma_firmware(dev, &ssfw, name);
241}
242EXPORT_SYMBOL(process_sigma_firmware_regmap);
243
244#endif
245
197MODULE_LICENSE("GPL"); 246MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
index 99a609157b2e..e439cbd7af7d 100644
--- a/sound/soc/codecs/sigmadsp.h
+++ b/sound/soc/codecs/sigmadsp.h
@@ -9,8 +9,13 @@
9#ifndef __SIGMA_FIRMWARE_H__ 9#ifndef __SIGMA_FIRMWARE_H__
10#define __SIGMA_FIRMWARE_H__ 10#define __SIGMA_FIRMWARE_H__
11 11
12#include <linux/device.h>
13#include <linux/regmap.h>
14
12struct i2c_client; 15struct i2c_client;
13 16
14extern int process_sigma_firmware(struct i2c_client *client, const char *name); 17extern int process_sigma_firmware(struct i2c_client *client, const char *name);
18extern int process_sigma_firmware_regmap(struct device *dev,
19 struct regmap *regmap, const char *name);
15 20
16#endif 21#endif