1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2017 Intel Corporation. All rights reserved.
4 //
5 // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
6 //         Liam Girdwood <liam.r.girdwood@linux.intel.com>
7 //         Keyon Jie <yang.jie@linux.intel.com>
8 
9 #include <sof/audio/eq_fir/eq_fir.h>
10 #include <sof/audio/buffer.h>
11 #include <sof/audio/component.h>
12 #include <sof/audio/pipeline.h>
13 #include <sof/audio/ipc-config.h>
14 #include <sof/common.h>
15 #include <sof/debug/panic.h>
16 #include <sof/ipc/msg.h>
17 #include <sof/lib/alloc.h>
18 #include <sof/lib/memory.h>
19 #include <sof/lib/uuid.h>
20 #include <sof/list.h>
21 #include <sof/math/fir_config.h>
22 #include <sof/platform.h>
23 #include <sof/string.h>
24 #include <sof/ut.h>
25 #include <sof/trace/trace.h>
26 #include <ipc/control.h>
27 #include <ipc/stream.h>
28 #include <ipc/topology.h>
29 #include <kernel/abi.h>
30 #include <user/eq.h>
31 #include <user/fir.h>
32 #include <user/trace.h>
33 #include <errno.h>
34 #include <stddef.h>
35 #include <stdint.h>
36 
37 static const struct comp_driver comp_eq_fir;
38 
39 /* 43a90ce7-f3a5-41df-ac06-ba98651ae6a3 */
40 DECLARE_SOF_RT_UUID("eq-fir", eq_fir_uuid, 0x43a90ce7, 0xf3a5, 0x41df,
41 		 0xac, 0x06, 0xba, 0x98, 0x65, 0x1a, 0xe6, 0xa3);
42 
43 DECLARE_TR_CTX(eq_fir_tr, SOF_UUID(eq_fir_uuid), LOG_LEVEL_INFO);
44 
45 /* src component private data */
46 struct comp_data {
47 	struct fir_state_32x16 fir[PLATFORM_MAX_CHANNELS]; /**< filters state */
48 	struct comp_data_blob_handler *model_handler;
49 	struct sof_eq_fir_config *config;
50 	int32_t *fir_delay;			/**< pointer to allocated RAM */
51 	size_t fir_delay_size;			/**< allocated size */
52 	void (*eq_fir_func)(struct fir_state_32x16 fir[],
53 			    const struct audio_stream *source,
54 			    struct audio_stream *sink,
55 			    int frames, int nch);
56 };
57 
58 /*
59  * The optimized FIR functions variants need to be updated into function
60  * set_fir_func.
61  */
62 
63 #if FIR_HIFI3 || FIR_HIFIEP
64 #if CONFIG_FORMAT_S16LE
set_s16_fir(struct comp_data * cd)65 static inline void set_s16_fir(struct comp_data *cd)
66 {
67 	cd->eq_fir_func = eq_fir_2x_s16;
68 }
69 #endif /* CONFIG_FORMAT_S16LE */
70 #if CONFIG_FORMAT_S24LE
set_s24_fir(struct comp_data * cd)71 static inline void set_s24_fir(struct comp_data *cd)
72 {
73 	cd->eq_fir_func = eq_fir_2x_s24;
74 }
75 #endif /* CONFIG_FORMAT_S24LE */
76 #if CONFIG_FORMAT_S32LE
set_s32_fir(struct comp_data * cd)77 static inline void set_s32_fir(struct comp_data *cd)
78 {
79 	cd->eq_fir_func = eq_fir_2x_s32;
80 }
81 #endif /* CONFIG_FORMAT_S32LE */
82 
83 #else
84 /* FIR_GENERIC */
85 #if CONFIG_FORMAT_S16LE
set_s16_fir(struct comp_data * cd)86 static inline void set_s16_fir(struct comp_data *cd)
87 {
88 	cd->eq_fir_func = eq_fir_s16;
89 }
90 #endif /* CONFIG_FORMAT_S16LE */
91 #if CONFIG_FORMAT_S24LE
set_s24_fir(struct comp_data * cd)92 static inline void set_s24_fir(struct comp_data *cd)
93 {
94 	cd->eq_fir_func = eq_fir_s24;
95 }
96 #endif /* CONFIG_FORMAT_S24LE */
97 #if CONFIG_FORMAT_S32LE
set_s32_fir(struct comp_data * cd)98 static inline void set_s32_fir(struct comp_data *cd)
99 {
100 	cd->eq_fir_func = eq_fir_s32;
101 }
102 #endif /* CONFIG_FORMAT_S32LE */
103 #endif
104 
set_fir_func(struct comp_dev * dev)105 static inline int set_fir_func(struct comp_dev *dev)
106 {
107 	struct comp_data *cd = comp_get_drvdata(dev);
108 	struct comp_buffer *sourceb;
109 
110 	sourceb = list_first_item(&dev->bsource_list, struct comp_buffer,
111 				  sink_list);
112 
113 	switch (sourceb->stream.frame_fmt) {
114 #if CONFIG_FORMAT_S16LE
115 	case SOF_IPC_FRAME_S16_LE:
116 		comp_info(dev, "set_fir_func(), SOF_IPC_FRAME_S16_LE");
117 		set_s16_fir(cd);
118 		break;
119 #endif /* CONFIG_FORMAT_S16LE */
120 #if CONFIG_FORMAT_S24LE
121 	case SOF_IPC_FRAME_S24_4LE:
122 		comp_info(dev, "set_fir_func(), SOF_IPC_FRAME_S24_4LE");
123 		set_s24_fir(cd);
124 		break;
125 #endif /* CONFIG_FORMAT_S24LE */
126 #if CONFIG_FORMAT_S32LE
127 	case SOF_IPC_FRAME_S32_LE:
128 		comp_info(dev, "set_fir_func(), SOF_IPC_FRAME_S32_LE");
129 		set_s32_fir(cd);
130 		break;
131 #endif /* CONFIG_FORMAT_S32LE */
132 	default:
133 		comp_err(dev, "set_fir_func(), invalid frame_fmt");
134 		return -EINVAL;
135 	}
136 	return 0;
137 }
138 
139 /* Pass-through functions to replace FIR core while not configured for
140  * response.
141  */
142 
eq_fir_passthrough(struct fir_state_32x16 fir[],const struct audio_stream * source,struct audio_stream * sink,int frames,int nch)143 static void eq_fir_passthrough(struct fir_state_32x16 fir[],
144 			       const struct audio_stream *source,
145 			       struct audio_stream *sink,
146 			       int frames, int nch)
147 {
148 	audio_stream_copy(source, 0, sink, 0, frames * nch);
149 }
150 
eq_fir_free_delaylines(struct comp_data * cd)151 static void eq_fir_free_delaylines(struct comp_data *cd)
152 {
153 	struct fir_state_32x16 *fir = cd->fir;
154 	int i = 0;
155 
156 	/* Free the common buffer for all EQs and point then
157 	 * each FIR channel delay line to NULL.
158 	 */
159 	rfree(cd->fir_delay);
160 	cd->fir_delay = NULL;
161 	cd->fir_delay_size = 0;
162 	for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
163 		fir[i].delay = NULL;
164 }
165 
eq_fir_init_coef(struct sof_eq_fir_config * config,struct fir_state_32x16 * fir,int nch)166 static int eq_fir_init_coef(struct sof_eq_fir_config *config,
167 			    struct fir_state_32x16 *fir, int nch)
168 {
169 	struct sof_fir_coef_data *lookup[SOF_EQ_FIR_MAX_RESPONSES];
170 	struct sof_fir_coef_data *eq;
171 	int16_t *assign_response;
172 	int16_t *coef_data;
173 	size_t size_sum = 0;
174 	int resp = 0;
175 	int i;
176 	int j;
177 	int s;
178 
179 	comp_cl_info(&comp_eq_fir, "eq_fir_init_coef(), response assign for %u channels, %u responses",
180 		     config->channels_in_config,
181 		     config->number_of_responses);
182 
183 	/* Sanity checks */
184 	if (nch > PLATFORM_MAX_CHANNELS ||
185 	    config->channels_in_config > PLATFORM_MAX_CHANNELS ||
186 	    !config->channels_in_config) {
187 		comp_cl_err(&comp_eq_fir, "eq_fir_init_coef(), invalid channels count");
188 		return -EINVAL;
189 	}
190 	if (config->number_of_responses > SOF_EQ_FIR_MAX_RESPONSES) {
191 		comp_cl_err(&comp_eq_fir, "eq_fir_init_coef(), # of resp exceeds max");
192 		return -EINVAL;
193 	}
194 
195 	/* Collect index of respose start positions in all_coefficients[]  */
196 	j = 0;
197 	assign_response = ASSUME_ALIGNED(&config->data[0], 4);
198 	coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config],
199 				   4);
200 	for (i = 0; i < SOF_EQ_FIR_MAX_RESPONSES; i++) {
201 		if (i < config->number_of_responses) {
202 			eq = (struct sof_fir_coef_data *)&coef_data[j];
203 			lookup[i] = eq;
204 			j += SOF_FIR_COEF_NHEADER + coef_data[j];
205 		} else {
206 			lookup[i] = NULL;
207 		}
208 	}
209 
210 	/* Initialize 1st phase */
211 	for (i = 0; i < nch; i++) {
212 		/* Check for not reading past blob response to channel assign
213 		 * map. The previous channel response is assigned for any
214 		 * additional channels in the stream. It allows to use single
215 		 * channel configuration to setup multi channel equalization
216 		 * with the same response.
217 		 */
218 		if (i < config->channels_in_config)
219 			resp = assign_response[i];
220 
221 		if (resp < 0) {
222 			/* Initialize EQ channel to bypass and continue with
223 			 * next channel response.
224 			 */
225 			comp_cl_info(&comp_eq_fir, "eq_fir_init_coef(), ch %d is set to bypass",
226 				     i);
227 			fir_reset(&fir[i]);
228 			continue;
229 		}
230 
231 		if (resp >= config->number_of_responses) {
232 			comp_cl_err(&comp_eq_fir, "eq_fir_init_coef(), requested response %d exceeds what has been defined",
233 				    resp);
234 			return -EINVAL;
235 		}
236 
237 		/* Initialize EQ coefficients. */
238 		eq = lookup[resp];
239 		s = fir_delay_size(eq);
240 		if (s > 0) {
241 			size_sum += s;
242 		} else {
243 			comp_cl_info(&comp_eq_fir, "eq_fir_init_coef(), FIR length %d is invalid",
244 				     eq->length);
245 			return -EINVAL;
246 		}
247 
248 #if defined FIR_MAX_LENGTH_BUILD_SPECIFIC
249 		if (fir[i].taps * nch > FIR_MAX_LENGTH_BUILD_SPECIFIC) {
250 			comp_cl_err(&comp_eq_fir, "Filter length %d exceeds limitation for build.",
251 				    fir[i].taps);
252 			return -EINVAL;
253 		}
254 #endif
255 
256 		fir_init_coef(&fir[i], eq);
257 		comp_cl_info(&comp_eq_fir, "eq_fir_init_coef(), ch %d is set to response = %d",
258 			     i, resp);
259 	}
260 
261 	return size_sum;
262 }
263 
eq_fir_init_delay(struct fir_state_32x16 * fir,int32_t * delay_start,int nch)264 static void eq_fir_init_delay(struct fir_state_32x16 *fir,
265 			      int32_t *delay_start, int nch)
266 {
267 	int32_t *fir_delay = delay_start;
268 	int i;
269 
270 	/* Initialize 2nd phase to set EQ delay lines pointers */
271 	for (i = 0; i < nch; i++) {
272 		if (fir[i].length > 0)
273 			fir_init_delay(&fir[i], &fir_delay);
274 	}
275 }
276 
eq_fir_setup(struct comp_data * cd,int nch)277 static int eq_fir_setup(struct comp_data *cd, int nch)
278 {
279 	int delay_size;
280 
281 	/* Free existing FIR channels data if it was allocated */
282 	eq_fir_free_delaylines(cd);
283 
284 	/* Set coefficients for each channel EQ from coefficient blob */
285 	delay_size = eq_fir_init_coef(cd->config, cd->fir, nch);
286 	if (delay_size < 0)
287 		return delay_size; /* Contains error code */
288 
289 	/* If all channels were set to bypass there's no need to
290 	 * allocate delay. Just return with success.
291 	 */
292 	if (!delay_size)
293 		return 0;
294 
295 	/* Allocate all FIR channels data in a big chunk and clear it */
296 	cd->fir_delay = rballoc(0, SOF_MEM_CAPS_RAM, delay_size);
297 	if (!cd->fir_delay) {
298 		comp_cl_err(&comp_eq_fir, "eq_fir_setup(), delay allocation failed for size %d",
299 			    delay_size);
300 		return -ENOMEM;
301 	}
302 
303 	memset(cd->fir_delay, 0, delay_size);
304 	cd->fir_delay_size = delay_size;
305 
306 	/* Assign delay line to each channel EQ */
307 	eq_fir_init_delay(cd->fir, cd->fir_delay, nch);
308 	return 0;
309 }
310 
311 /*
312  * End of algorithm code. Next the standard component methods.
313  */
314 
eq_fir_new(const struct comp_driver * drv,struct comp_ipc_config * config,void * spec)315 static struct comp_dev *eq_fir_new(const struct comp_driver *drv,
316 				   struct comp_ipc_config *config,
317 				   void *spec)
318 {
319 	struct comp_dev *dev = NULL;
320 	struct comp_data *cd = NULL;
321 	struct ipc_config_process *ipc_fir = spec;
322 	size_t bs = ipc_fir->size;
323 	int i;
324 	int ret;
325 
326 	comp_cl_info(&comp_eq_fir, "eq_fir_new()");
327 
328 	/* Check first before proceeding with dev and cd that coefficients
329 	 * blob size is sane.
330 	 */
331 	if (bs > SOF_EQ_FIR_MAX_SIZE) {
332 		comp_cl_err(&comp_eq_fir, "eq_fir_new(): coefficients blob size = %u > SOF_EQ_FIR_MAX_SIZE",
333 			    bs);
334 		return NULL;
335 	}
336 
337 	dev = comp_alloc(drv, sizeof(*dev));
338 	if (!dev)
339 		return NULL;
340 	dev->ipc_config = *config;
341 
342 	cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
343 	if (!cd)
344 		goto fail;
345 
346 	comp_set_drvdata(dev, cd);
347 
348 	cd->eq_fir_func = NULL;
349 	cd->fir_delay = NULL;
350 	cd->fir_delay_size = 0;
351 
352 	/* component model data handler */
353 	cd->model_handler = comp_data_blob_handler_new(dev);
354 	if (!cd->model_handler) {
355 		comp_cl_err(&comp_eq_fir, "eq_fir_new(): comp_data_blob_handler_new() failed.");
356 		goto cd_fail;
357 	}
358 
359 	/* Allocate and make a copy of the coefficients blob and reset FIR. If
360 	 * the EQ is configured later in run-time the size is zero.
361 	 */
362 	ret = comp_init_data_blob(cd->model_handler, bs, ipc_fir->data);
363 	if (ret < 0) {
364 		comp_cl_err(&comp_eq_fir, "eq_fir_new(): comp_init_data_blob() failed.");
365 		goto cd_fail;
366 	}
367 
368 	for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
369 		fir_reset(&cd->fir[i]);
370 
371 	dev->state = COMP_STATE_READY;
372 	return dev;
373 
374 cd_fail:
375 	comp_data_blob_handler_free(cd->model_handler);
376 	rfree(cd);
377 fail:
378 	rfree(dev);
379 	return NULL;
380 }
381 
eq_fir_free(struct comp_dev * dev)382 static void eq_fir_free(struct comp_dev *dev)
383 {
384 	struct comp_data *cd = comp_get_drvdata(dev);
385 
386 	comp_info(dev, "eq_fir_free()");
387 
388 	eq_fir_free_delaylines(cd);
389 	comp_data_blob_handler_free(cd->model_handler);
390 
391 	rfree(cd);
392 	rfree(dev);
393 }
394 
fir_cmd_get_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata,int max_size)395 static int fir_cmd_get_data(struct comp_dev *dev,
396 			    struct sof_ipc_ctrl_data *cdata, int max_size)
397 {
398 	struct comp_data *cd = comp_get_drvdata(dev);
399 	int ret = 0;
400 
401 	switch (cdata->cmd) {
402 	case SOF_CTRL_CMD_BINARY:
403 		comp_info(dev, "fir_cmd_get_data(), SOF_CTRL_CMD_BINARY");
404 		ret = comp_data_blob_get_cmd(cd->model_handler, cdata,
405 					     max_size);
406 		break;
407 	default:
408 		comp_err(dev, "fir_cmd_get_data(): invalid cdata->cmd");
409 		ret = -EINVAL;
410 		break;
411 	}
412 	return ret;
413 }
414 
fir_cmd_set_data(struct comp_dev * dev,struct sof_ipc_ctrl_data * cdata)415 static int fir_cmd_set_data(struct comp_dev *dev,
416 			    struct sof_ipc_ctrl_data *cdata)
417 {
418 	struct comp_data *cd = comp_get_drvdata(dev);
419 	int ret = 0;
420 
421 	switch (cdata->cmd) {
422 	case SOF_CTRL_CMD_BINARY:
423 		comp_info(dev, "fir_cmd_set_data(), SOF_CTRL_CMD_BINARY");
424 		ret = comp_data_blob_set_cmd(cd->model_handler, cdata);
425 		break;
426 	default:
427 		comp_err(dev, "fir_cmd_set_data(): invalid cdata->cmd");
428 		ret = -EINVAL;
429 		break;
430 	}
431 
432 	return ret;
433 }
434 
435 /* used to pass standard and bespoke commands (with data) to component */
eq_fir_cmd(struct comp_dev * dev,int cmd,void * data,int max_data_size)436 static int eq_fir_cmd(struct comp_dev *dev, int cmd, void *data,
437 		      int max_data_size)
438 {
439 	struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4);
440 	int ret = 0;
441 
442 	comp_info(dev, "eq_fir_cmd()");
443 
444 	switch (cmd) {
445 	case COMP_CMD_SET_DATA:
446 		ret = fir_cmd_set_data(dev, cdata);
447 		break;
448 	case COMP_CMD_GET_DATA:
449 		ret = fir_cmd_get_data(dev, cdata, max_data_size);
450 		break;
451 	default:
452 		comp_err(dev, "eq_fir_cmd(): invalid command");
453 		ret = -EINVAL;
454 	}
455 
456 	return ret;
457 }
458 
eq_fir_trigger(struct comp_dev * dev,int cmd)459 static int eq_fir_trigger(struct comp_dev *dev, int cmd)
460 {
461 	struct comp_data *cd = comp_get_drvdata(dev);
462 
463 	comp_info(dev, "eq_fir_trigger()");
464 
465 	if (cmd == COMP_TRIGGER_START || cmd == COMP_TRIGGER_RELEASE)
466 		assert(cd->eq_fir_func);
467 
468 	return comp_set_state(dev, cmd);
469 }
470 
eq_fir_process(struct comp_dev * dev,struct comp_buffer * source,struct comp_buffer * sink,int frames,uint32_t source_bytes,uint32_t sink_bytes)471 static void eq_fir_process(struct comp_dev *dev, struct comp_buffer *source,
472 			   struct comp_buffer *sink, int frames,
473 			   uint32_t source_bytes, uint32_t sink_bytes)
474 {
475 	struct comp_data *cd = comp_get_drvdata(dev);
476 
477 	buffer_invalidate(source, source_bytes);
478 
479 	cd->eq_fir_func(cd->fir, &source->stream, &sink->stream, frames,
480 			source->stream.channels);
481 
482 	buffer_writeback(sink, sink_bytes);
483 
484 	/* calc new free and available */
485 	comp_update_buffer_consume(source, source_bytes);
486 	comp_update_buffer_produce(sink, sink_bytes);
487 }
488 
489 /* copy and process stream data from source to sink buffers */
eq_fir_copy(struct comp_dev * dev)490 static int eq_fir_copy(struct comp_dev *dev)
491 {
492 	struct comp_copy_limits cl;
493 	struct comp_buffer *sourceb;
494 	struct comp_buffer *sinkb;
495 	struct comp_data *cd = comp_get_drvdata(dev);
496 	int ret;
497 	int n;
498 
499 	comp_dbg(dev, "eq_fir_copy()");
500 
501 	sourceb = list_first_item(&dev->bsource_list, struct comp_buffer,
502 				  sink_list);
503 
504 	/* Check for changed configuration */
505 	if (comp_is_new_data_blob_available(cd->model_handler)) {
506 		cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL);
507 		ret = eq_fir_setup(cd, sourceb->stream.channels);
508 		if (ret < 0) {
509 			comp_err(dev, "eq_fir_copy(), failed FIR setup");
510 			return ret;
511 		}
512 	}
513 
514 	sinkb = list_first_item(&dev->bsink_list, struct comp_buffer,
515 				source_list);
516 
517 	/* Get source, sink, number of frames etc. to process. */
518 	comp_get_copy_limits_with_lock(sourceb, sinkb, &cl);
519 
520 	/*
521 	 * Process only even number of frames with the FIR function. The
522 	 * optimized filter function loads the successive input samples from
523 	 * internal delay line with a 64 bit load operation. The other odd
524 	 * (or any) number of frames capable FIR version would permanently
525 	 * break the delay line alignment if called with odd number of frames
526 	 * so it can't be used here.
527 	 */
528 	if (cl.frames >= 2) {
529 		n = (cl.frames >> 1) << 1;
530 
531 		/* Run EQ function */
532 		eq_fir_process(dev, sourceb, sinkb, n,
533 			       n * cl.source_frame_bytes,
534 			       n * cl.sink_frame_bytes);
535 	}
536 
537 	return 0;
538 }
539 
eq_fir_prepare(struct comp_dev * dev)540 static int eq_fir_prepare(struct comp_dev *dev)
541 {
542 	struct comp_data *cd = comp_get_drvdata(dev);
543 	struct comp_buffer *sourceb;
544 	struct comp_buffer *sinkb;
545 	uint32_t sink_period_bytes;
546 	int ret;
547 
548 	comp_info(dev, "eq_fir_prepare()");
549 
550 	ret = comp_set_state(dev, COMP_TRIGGER_PREPARE);
551 	if (ret < 0)
552 		return ret;
553 
554 	if (ret == COMP_STATUS_STATE_ALREADY_SET)
555 		return PPL_STATUS_PATH_STOP;
556 
557 	/* EQ component will only ever have 1 source and 1 sink buffer. */
558 	sourceb = list_first_item(&dev->bsource_list,
559 				  struct comp_buffer, sink_list);
560 	sinkb = list_first_item(&dev->bsink_list,
561 				struct comp_buffer, source_list);
562 
563 	sink_period_bytes = audio_stream_period_bytes(&sinkb->stream,
564 						      dev->frames);
565 
566 	if (sinkb->stream.size < sink_period_bytes) {
567 		comp_err(dev, "eq_fir_prepare(): sink buffer size %d is insufficient < %d",
568 			 sinkb->stream.size, sink_period_bytes);
569 		ret = -ENOMEM;
570 		goto err;
571 	}
572 
573 	cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL);
574 
575 	if (cd->config) {
576 		ret = eq_fir_setup(cd, sourceb->stream.channels);
577 		if (ret < 0) {
578 			comp_err(dev, "eq_fir_prepare(): eq_fir_setup failed.");
579 			goto err;
580 		}
581 
582 		ret = set_fir_func(dev);
583 		return ret;
584 	}
585 
586 	cd->eq_fir_func = eq_fir_passthrough;
587 
588 	return ret;
589 
590 err:
591 	comp_set_state(dev, COMP_TRIGGER_RESET);
592 	return ret;
593 }
594 
eq_fir_reset(struct comp_dev * dev)595 static int eq_fir_reset(struct comp_dev *dev)
596 {
597 	int i;
598 	struct comp_data *cd = comp_get_drvdata(dev);
599 
600 	comp_info(dev, "eq_fir_reset()");
601 
602 	eq_fir_free_delaylines(cd);
603 
604 	cd->eq_fir_func = NULL;
605 	for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
606 		fir_reset(&cd->fir[i]);
607 
608 	comp_set_state(dev, COMP_TRIGGER_RESET);
609 	return 0;
610 }
611 
612 static const struct comp_driver comp_eq_fir = {
613 	.type = SOF_COMP_EQ_FIR,
614 	.uid = SOF_RT_UUID(eq_fir_uuid),
615 	.tctx = &eq_fir_tr,
616 	.ops = {
617 		.create = eq_fir_new,
618 		.free = eq_fir_free,
619 		.cmd = eq_fir_cmd,
620 		.trigger = eq_fir_trigger,
621 		.copy = eq_fir_copy,
622 		.prepare = eq_fir_prepare,
623 		.reset = eq_fir_reset,
624 	},
625 };
626 
627 static SHARED_DATA struct comp_driver_info comp_eq_fir_info = {
628 	.drv = &comp_eq_fir,
629 };
630 
sys_comp_eq_fir_init(void)631 UT_STATIC void sys_comp_eq_fir_init(void)
632 {
633 	comp_register(platform_shared_get(&comp_eq_fir_info,
634 					  sizeof(comp_eq_fir_info)));
635 }
636 
637 DECLARE_MODULE(sys_comp_eq_fir_init);
638