diff options
-rw-r--r-- | sound/soc/codecs/sigmadsp.c | 75 | ||||
-rw-r--r-- | sound/soc/codecs/sigmadsp.h | 5 |
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 { | |||
44 | struct sigma_firmware { | 45 | struct 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 | ||
49 | static inline u32 sigma_action_len(struct sigma_action *sa) | 54 | static 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 | */ |
77 | static int | 82 | static int |
78 | process_sigma_action(struct i2c_client *client, struct sigma_action *sa) | 83 | process_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 | ||
107 | static int | 112 | static int |
108 | process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw) | 113 | process_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 | ||
136 | int process_sigma_firmware(struct i2c_client *client, const char *name) | 141 | static 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 | |||
203 | static 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 | |||
210 | int 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 | } | ||
195 | EXPORT_SYMBOL(process_sigma_firmware); | 219 | EXPORT_SYMBOL(process_sigma_firmware); |
196 | 220 | ||
221 | #endif | ||
222 | |||
223 | #if IS_ENABLED(CONFIG_REGMAP) | ||
224 | |||
225 | static 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 | |||
232 | int 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 | } | ||
242 | EXPORT_SYMBOL(process_sigma_firmware_regmap); | ||
243 | |||
244 | #endif | ||
245 | |||
197 | MODULE_LICENSE("GPL"); | 246 | MODULE_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 | |||
12 | struct i2c_client; | 15 | struct i2c_client; |
13 | 16 | ||
14 | extern int process_sigma_firmware(struct i2c_client *client, const char *name); | 17 | extern int process_sigma_firmware(struct i2c_client *client, const char *name); |
18 | extern int process_sigma_firmware_regmap(struct device *dev, | ||
19 | struct regmap *regmap, const char *name); | ||
15 | 20 | ||
16 | #endif | 21 | #endif |