xref: /linux/sound/soc/sdca/sdca_interrupts.c (revision bb2ea74eeb6735eed29bd74695f90f0e5af09f5c)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2025 Cirrus Logic, Inc. and
3 //                    Cirrus Logic International Semiconductor Ltd.
4 
5 /*
6  * The MIPI SDCA specification is available for public downloads at
7  * https://www.mipi.org/mipi-sdca-v1-0-download
8  */
9 
10 #include <linux/bitmap.h>
11 #include <linux/bits.h>
12 #include <linux/cleanup.h>
13 #include <linux/device.h>
14 #include <linux/dev_printk.h>
15 #include <linux/interrupt.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/regmap.h>
18 #include <linux/soundwire/sdw.h>
19 #include <linux/soundwire/sdw_registers.h>
20 #include <sound/sdca.h>
21 #include <sound/sdca_fdl.h>
22 #include <sound/sdca_function.h>
23 #include <sound/sdca_hid.h>
24 #include <sound/sdca_interrupts.h>
25 #include <sound/sdca_jack.h>
26 #include <sound/sdca_ump.h>
27 #include <sound/soc-component.h>
28 #include <sound/soc.h>
29 
30 #define IRQ_SDCA(number) REGMAP_IRQ_REG(number, ((number) / BITS_PER_BYTE), \
31 					SDW_SCP_SDCA_INTMASK_SDCA_##number)
32 
33 static const struct regmap_irq regmap_irqs[SDCA_MAX_INTERRUPTS] = {
34 	IRQ_SDCA(0),
35 	IRQ_SDCA(1),
36 	IRQ_SDCA(2),
37 	IRQ_SDCA(3),
38 	IRQ_SDCA(4),
39 	IRQ_SDCA(5),
40 	IRQ_SDCA(6),
41 	IRQ_SDCA(7),
42 	IRQ_SDCA(8),
43 	IRQ_SDCA(9),
44 	IRQ_SDCA(10),
45 	IRQ_SDCA(11),
46 	IRQ_SDCA(12),
47 	IRQ_SDCA(13),
48 	IRQ_SDCA(14),
49 	IRQ_SDCA(15),
50 	IRQ_SDCA(16),
51 	IRQ_SDCA(17),
52 	IRQ_SDCA(18),
53 	IRQ_SDCA(19),
54 	IRQ_SDCA(20),
55 	IRQ_SDCA(21),
56 	IRQ_SDCA(22),
57 	IRQ_SDCA(23),
58 	IRQ_SDCA(24),
59 	IRQ_SDCA(25),
60 	IRQ_SDCA(26),
61 	IRQ_SDCA(27),
62 	IRQ_SDCA(28),
63 	IRQ_SDCA(29),
64 	IRQ_SDCA(30),
65 };
66 
67 static const struct regmap_irq_chip sdca_irq_chip = {
68 	.name = "sdca_irq",
69 
70 	.status_base = SDW_SCP_SDCA_INT1,
71 	.unmask_base = SDW_SCP_SDCA_INTMASK1,
72 	.ack_base = SDW_SCP_SDCA_INT1,
73 	.num_regs = 4,
74 
75 	.irqs = regmap_irqs,
76 	.num_irqs = SDCA_MAX_INTERRUPTS,
77 
78 	.runtime_pm = true,
79 };
80 
base_handler(int irq,void * data)81 static irqreturn_t base_handler(int irq, void *data)
82 {
83 	struct sdca_interrupt *interrupt = data;
84 	struct device *dev = interrupt->dev;
85 
86 	dev_info(dev, "%s irq without full handling\n", interrupt->name);
87 
88 	return IRQ_HANDLED;
89 }
90 
function_status_handler(int irq,void * data)91 static irqreturn_t function_status_handler(int irq, void *data)
92 {
93 	struct sdca_interrupt *interrupt = data;
94 	struct device *dev = interrupt->dev;
95 	irqreturn_t irqret = IRQ_NONE;
96 	unsigned int reg, val;
97 	unsigned long status;
98 	unsigned int mask;
99 	int ret;
100 
101 	ret = pm_runtime_get_sync(dev);
102 	if (ret < 0) {
103 		dev_err(dev, "failed to resume for function status: %d\n", ret);
104 		goto error;
105 	}
106 
107 	reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
108 			   interrupt->control->sel, 0);
109 
110 	ret = regmap_read(interrupt->function_regmap, reg, &val);
111 	if (ret < 0) {
112 		dev_err(dev, "failed to read function status: %d\n", ret);
113 		goto error;
114 	}
115 
116 	dev_dbg(dev, "function status: %#x\n", val);
117 
118 	status = val;
119 	for_each_set_bit(mask, &status, BITS_PER_BYTE) {
120 		switch (BIT(mask)) {
121 		case SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION:
122 			//FIXME: Add init writes
123 			break;
124 		case SDCA_CTL_ENTITY_0_FUNCTION_FAULT:
125 			dev_err(dev, "function fault\n");
126 			break;
127 		case SDCA_CTL_ENTITY_0_UMP_SEQUENCE_FAULT:
128 			dev_err(dev, "ump sequence fault\n");
129 			break;
130 		case SDCA_CTL_ENTITY_0_FUNCTION_BUSY:
131 			dev_info(dev, "unexpected function busy\n");
132 			break;
133 		case SDCA_CTL_ENTITY_0_DEVICE_NEWLY_ATTACHED:
134 		case SDCA_CTL_ENTITY_0_INTS_DISABLED_ABNORMALLY:
135 		case SDCA_CTL_ENTITY_0_STREAMING_STOPPED_ABNORMALLY:
136 		case SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET:
137 			break;
138 		}
139 	}
140 
141 	ret = regmap_write(interrupt->function_regmap, reg, val & 0x7F);
142 	if (ret < 0) {
143 		dev_err(dev, "failed to clear function status: %d\n", ret);
144 		goto error;
145 	}
146 
147 	irqret = IRQ_HANDLED;
148 error:
149 	pm_runtime_put(dev);
150 	return irqret;
151 }
152 
detected_mode_handler(int irq,void * data)153 static irqreturn_t detected_mode_handler(int irq, void *data)
154 {
155 	struct sdca_interrupt *interrupt = data;
156 	struct device *dev = interrupt->dev;
157 	irqreturn_t irqret = IRQ_NONE;
158 	int ret;
159 
160 	ret = pm_runtime_get_sync(dev);
161 	if (ret < 0) {
162 		dev_err(dev, "failed to resume for detected mode: %d\n", ret);
163 		goto error;
164 	}
165 
166 	ret = sdca_jack_process(interrupt);
167 	if (ret)
168 		goto error;
169 
170 	irqret = IRQ_HANDLED;
171 error:
172 	pm_runtime_put(dev);
173 	return irqret;
174 }
175 
hid_handler(int irq,void * data)176 static irqreturn_t hid_handler(int irq, void *data)
177 {
178 	struct sdca_interrupt *interrupt = data;
179 	struct device *dev = interrupt->dev;
180 	irqreturn_t irqret = IRQ_NONE;
181 	int ret;
182 
183 	ret = pm_runtime_get_sync(dev);
184 	if (ret < 0) {
185 		dev_err(dev, "failed to resume for hid: %d\n", ret);
186 		goto error;
187 	}
188 
189 	ret = sdca_hid_process_report(interrupt);
190 	if (ret)
191 		goto error;
192 
193 	irqret = IRQ_HANDLED;
194 error:
195 	pm_runtime_put(dev);
196 	return irqret;
197 }
198 
199 #ifdef CONFIG_PM_SLEEP
no_pm_in_progress(struct device * dev)200 static bool no_pm_in_progress(struct device *dev)
201 {
202 	return completion_done(&dev->power.completion);
203 }
204 #else
no_pm_in_progress(struct device * dev)205 static bool no_pm_in_progress(struct device *dev)
206 {
207 	return true;
208 }
209 #endif
210 
fdl_owner_handler(int irq,void * data)211 static irqreturn_t fdl_owner_handler(int irq, void *data)
212 {
213 	struct sdca_interrupt *interrupt = data;
214 	struct device *dev = interrupt->dev;
215 	irqreturn_t irqret = IRQ_NONE;
216 	int ret;
217 
218 	/*
219 	 * FDL has to run from the system resume handler, at which point
220 	 * we can't wait for the pm runtime.
221 	 */
222 	if (no_pm_in_progress(dev)) {
223 		ret = pm_runtime_get_sync(dev);
224 		if (ret < 0) {
225 			dev_err(dev, "failed to resume for fdl: %d\n", ret);
226 			goto error;
227 		}
228 	}
229 
230 	ret = sdca_fdl_process(interrupt);
231 	if (ret)
232 		goto error;
233 
234 	irqret = IRQ_HANDLED;
235 error:
236 	if (no_pm_in_progress(dev))
237 		pm_runtime_put(dev);
238 	return irqret;
239 }
240 
sdca_irq_request_locked(struct device * dev,struct sdca_interrupt_info * info,int sdca_irq,const char * name,irq_handler_t handler,void * data)241 static int sdca_irq_request_locked(struct device *dev,
242 				   struct sdca_interrupt_info *info,
243 				   int sdca_irq, const char *name,
244 				   irq_handler_t handler, void *data)
245 {
246 	int irq;
247 	int ret;
248 
249 	irq = regmap_irq_get_virq(info->irq_data, sdca_irq);
250 	if (irq < 0)
251 		return irq;
252 
253 	ret = request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT, name, data);
254 	if (ret)
255 		return ret;
256 
257 	info->irqs[sdca_irq].irq = irq;
258 
259 	dev_dbg(dev, "requested irq %d for %s\n", irq, name);
260 
261 	return 0;
262 }
263 
sdca_irq_free_locked(struct device * dev,struct sdca_interrupt_info * info,int sdca_irq,const char * name,void * data)264 static void sdca_irq_free_locked(struct device *dev, struct sdca_interrupt_info *info,
265 				 int sdca_irq, const char *name, void *data)
266 {
267 	int irq;
268 
269 	irq = regmap_irq_get_virq(info->irq_data, sdca_irq);
270 	if (irq < 0)
271 		return;
272 
273 	free_irq(irq, data);
274 
275 	info->irqs[sdca_irq].irq = 0;
276 
277 	dev_dbg(dev, "freed irq %d for %s\n", irq, name);
278 }
279 
280 /**
281  * sdca_irq_request - request an individual SDCA interrupt
282  * @dev: Pointer to the struct device against which things should be allocated.
283  * @info: Pointer to the interrupt information structure.
284  * @sdca_irq: SDCA interrupt position.
285  * @name: Name to be given to the IRQ.
286  * @handler: A callback thread function to be called for the IRQ.
287  * @data: Private data pointer that will be passed to the handler.
288  *
289  * Typically this is handled internally by sdca_irq_populate, however if
290  * a device requires custom IRQ handling this can be called manually before
291  * calling sdca_irq_populate, which will then skip that IRQ whilst processing.
292  *
293  * Return: Zero on success, and a negative error code on failure.
294  */
sdca_irq_request(struct device * dev,struct sdca_interrupt_info * info,int sdca_irq,const char * name,irq_handler_t handler,void * data)295 int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *info,
296 		     int sdca_irq, const char *name, irq_handler_t handler,
297 		     void *data)
298 {
299 	int ret;
300 
301 	if (sdca_irq < 0 || sdca_irq >= SDCA_MAX_INTERRUPTS) {
302 		dev_err(dev, "bad irq request: %d\n", sdca_irq);
303 		return -EINVAL;
304 	}
305 
306 	guard(mutex)(&info->irq_lock);
307 
308 	ret = sdca_irq_request_locked(dev, info, sdca_irq, name, handler, data);
309 	if (ret) {
310 		dev_err(dev, "failed to request irq %s: %d\n", name, ret);
311 		return ret;
312 	}
313 
314 	return 0;
315 }
316 EXPORT_SYMBOL_NS_GPL(sdca_irq_request, "SND_SOC_SDCA");
317 
318 /**
319  * sdca_irq_free - free an individual SDCA interrupt
320  * @dev: Pointer to the struct device.
321  * @info: Pointer to the interrupt information structure.
322  * @sdca_irq: SDCA interrupt position.
323  * @name: Name to be given to the IRQ.
324  * @data: Private data pointer that will be passed to the handler.
325  *
326  * Typically this is handled internally by sdca_irq_cleanup, however if
327  * a device requires custom IRQ handling this can be called manually before
328  * calling sdca_irq_cleanup, which will then skip that IRQ whilst processing.
329  */
sdca_irq_free(struct device * dev,struct sdca_interrupt_info * info,int sdca_irq,const char * name,void * data)330 void sdca_irq_free(struct device *dev, struct sdca_interrupt_info *info,
331 		   int sdca_irq, const char *name, void *data)
332 {
333 	if (sdca_irq < 0 || sdca_irq >= SDCA_MAX_INTERRUPTS)
334 		return;
335 
336 	guard(mutex)(&info->irq_lock);
337 
338 	sdca_irq_free_locked(dev, info, sdca_irq, name, data);
339 }
340 EXPORT_SYMBOL_NS_GPL(sdca_irq_free, "SND_SOC_SDCA");
341 
342 /**
343  * sdca_irq_data_populate - Populate common interrupt data
344  * @dev: Pointer to the Function device.
345  * @regmap: Pointer to the Function regmap.
346  * @component: Pointer to the ASoC component for the Function.
347  * @function: Pointer to the SDCA Function.
348  * @entity: Pointer to the SDCA Entity.
349  * @control: Pointer to the SDCA Control.
350  * @interrupt: Pointer to the SDCA interrupt for this IRQ.
351  *
352  * Return: Zero on success, and a negative error code on failure.
353  */
sdca_irq_data_populate(struct device * dev,struct regmap * regmap,struct snd_soc_component * component,struct sdca_function_data * function,struct sdca_entity * entity,struct sdca_control * control,struct sdca_interrupt * interrupt)354 int sdca_irq_data_populate(struct device *dev, struct regmap *regmap,
355 			   struct snd_soc_component *component,
356 			   struct sdca_function_data *function,
357 			   struct sdca_entity *entity,
358 			   struct sdca_control *control,
359 			   struct sdca_interrupt *interrupt)
360 {
361 	const char *name;
362 
363 	if (!dev && component)
364 		dev = component->dev;
365 	if (!dev)
366 		return -ENODEV;
367 
368 	name = kasprintf(GFP_KERNEL, "%s %s %s", function->desc->name,
369 			 entity->label, control->label);
370 	if (!name)
371 		return -ENOMEM;
372 
373 	interrupt->name = name;
374 	interrupt->dev = dev;
375 	if (!regmap && component)
376 		interrupt->function_regmap = component->regmap;
377 	else
378 		interrupt->function_regmap = regmap;
379 	interrupt->component = component;
380 	interrupt->function = function;
381 	interrupt->entity = entity;
382 	interrupt->control = control;
383 
384 	return 0;
385 }
386 EXPORT_SYMBOL_NS_GPL(sdca_irq_data_populate, "SND_SOC_SDCA");
387 
get_interrupt_data(struct device * dev,int irq,struct sdca_interrupt_info * info)388 static struct sdca_interrupt *get_interrupt_data(struct device *dev, int irq,
389 						 struct sdca_interrupt_info *info)
390 {
391 	if (irq == SDCA_NO_INTERRUPT) {
392 		return NULL;
393 	} else if (irq < 0 || irq >= SDCA_MAX_INTERRUPTS) {
394 		dev_err(dev, "bad irq position: %d\n", irq);
395 		return ERR_PTR(-EINVAL);
396 	}
397 
398 	if (info->irqs[irq].irq) {
399 		dev_dbg(dev, "skipping irq %d, already requested\n", irq);
400 		return NULL;
401 	}
402 
403 	return &info->irqs[irq];
404 }
405 
406 /**
407  * sdca_irq_populate_early - process pre-audio card IRQ registrations
408  * @dev: Device pointer for SDCA Function.
409  * @regmap: Regmap pointer for the SDCA Function.
410  * @function: Pointer to the SDCA Function.
411  * @info: Pointer to the SDCA interrupt info for this device.
412  *
413  * This is intended to be used as part of the Function boot process. It
414  * can be called before the soundcard is registered (ie. doesn't depend
415  * on component) and will register the FDL interrupts.
416  *
417  * Return: Zero on success, and a negative error code on failure.
418  */
sdca_irq_populate_early(struct device * dev,struct regmap * regmap,struct sdca_function_data * function,struct sdca_interrupt_info * info)419 int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
420 			    struct sdca_function_data *function,
421 			    struct sdca_interrupt_info *info)
422 {
423 	int i, j;
424 
425 	guard(mutex)(&info->irq_lock);
426 
427 	for (i = 0; i < function->num_entities; i++) {
428 		struct sdca_entity *entity = &function->entities[i];
429 
430 		for (j = 0; j < entity->num_controls; j++) {
431 			struct sdca_control *control = &entity->controls[j];
432 			int irq = control->interrupt_position;
433 			struct sdca_interrupt *interrupt;
434 			int ret;
435 
436 			interrupt = get_interrupt_data(dev, irq, info);
437 			if (IS_ERR(interrupt))
438 				return PTR_ERR(interrupt);
439 			else if (!interrupt)
440 				continue;
441 
442 			switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
443 			case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
444 				ret = sdca_irq_data_populate(dev, regmap, NULL,
445 							     function, entity,
446 							     control, interrupt);
447 				if (ret)
448 					return ret;
449 
450 				ret = sdca_fdl_alloc_state(interrupt);
451 				if (ret)
452 					return ret;
453 
454 				ret = sdca_irq_request_locked(dev, info, irq,
455 							      interrupt->name,
456 							      fdl_owner_handler,
457 							      interrupt);
458 				if (ret) {
459 					dev_err(dev, "failed to request irq %s: %d\n",
460 						interrupt->name, ret);
461 					return ret;
462 				}
463 				break;
464 			default:
465 				break;
466 			}
467 		}
468 	}
469 
470 	return 0;
471 }
472 EXPORT_SYMBOL_NS_GPL(sdca_irq_populate_early, "SND_SOC_SDCA");
473 
474 /**
475  * sdca_irq_populate - Request all the individual IRQs for an SDCA Function
476  * @function: Pointer to the SDCA Function.
477  * @component: Pointer to the ASoC component for the Function.
478  * @info: Pointer to the SDCA interrupt info for this device.
479  *
480  * Typically this would be called from the driver for a single SDCA Function.
481  *
482  * Return: Zero on success, and a negative error code on failure.
483  */
sdca_irq_populate(struct sdca_function_data * function,struct snd_soc_component * component,struct sdca_interrupt_info * info)484 int sdca_irq_populate(struct sdca_function_data *function,
485 		      struct snd_soc_component *component,
486 		      struct sdca_interrupt_info *info)
487 {
488 	struct device *dev = component->dev;
489 	int i, j;
490 
491 	guard(mutex)(&info->irq_lock);
492 
493 	for (i = 0; i < function->num_entities; i++) {
494 		struct sdca_entity *entity = &function->entities[i];
495 
496 		for (j = 0; j < entity->num_controls; j++) {
497 			struct sdca_control *control = &entity->controls[j];
498 			int irq = control->interrupt_position;
499 			struct sdca_interrupt *interrupt;
500 			irq_handler_t handler;
501 			int ret;
502 
503 			interrupt = get_interrupt_data(dev, irq, info);
504 			if (IS_ERR(interrupt))
505 				return PTR_ERR(interrupt);
506 			else if (!interrupt)
507 				continue;
508 
509 			ret = sdca_irq_data_populate(dev, NULL, component,
510 						     function, entity, control,
511 						     interrupt);
512 			if (ret)
513 				return ret;
514 
515 			handler = base_handler;
516 
517 			switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
518 			case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS):
519 				handler = function_status_handler;
520 				break;
521 			case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
522 				ret = sdca_jack_alloc_state(interrupt);
523 				if (ret)
524 					return ret;
525 
526 				handler = detected_mode_handler;
527 				break;
528 			case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
529 				ret = sdca_fdl_alloc_state(interrupt);
530 				if (ret)
531 					return ret;
532 
533 				handler = fdl_owner_handler;
534 				break;
535 			case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
536 				handler = hid_handler;
537 				break;
538 			default:
539 				break;
540 			}
541 
542 			ret = sdca_irq_request_locked(dev, info, irq, interrupt->name,
543 						      handler, interrupt);
544 			if (ret) {
545 				dev_err(dev, "failed to request irq %s: %d\n",
546 					interrupt->name, ret);
547 				return ret;
548 			}
549 		}
550 	}
551 
552 	return 0;
553 }
554 EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA");
555 
556 /**
557  * sdca_irq_cleanup - Free all the individual IRQs for an SDCA Function
558  * @sdev: Device pointer against which the sdca_interrupt_info was allocated.
559  * @function: Pointer to the SDCA Function.
560  * @info: Pointer to the SDCA interrupt info for this device.
561  *
562  * Typically this would be called from the driver for a single SDCA Function.
563  */
sdca_irq_cleanup(struct device * dev,struct sdca_function_data * function,struct sdca_interrupt_info * info)564 void sdca_irq_cleanup(struct device *dev,
565 		      struct sdca_function_data *function,
566 		      struct sdca_interrupt_info *info)
567 {
568 	int i;
569 
570 	guard(mutex)(&info->irq_lock);
571 
572 	for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
573 		struct sdca_interrupt *interrupt = &info->irqs[i];
574 
575 		if (interrupt->function != function || !interrupt->irq)
576 			continue;
577 
578 		sdca_irq_free_locked(dev, info, i, interrupt->name, interrupt);
579 
580 		kfree(interrupt->name);
581 	}
582 }
583 EXPORT_SYMBOL_NS_GPL(sdca_irq_cleanup, "SND_SOC_SDCA");
584 
585 /**
586  * sdca_irq_allocate - allocate an SDCA interrupt structure for a device
587  * @sdev: Device pointer against which things should be allocated.
588  * @regmap: regmap to be used for accessing the SDCA IRQ registers.
589  * @irq: The interrupt number.
590  *
591  * Typically this would be called from the top level driver for the whole
592  * SDCA device, as only a single instance is required across all Functions
593  * on the device.
594  *
595  * Return: A pointer to the allocated sdca_interrupt_info struct, or an
596  * error code.
597  */
sdca_irq_allocate(struct device * sdev,struct regmap * regmap,int irq)598 struct sdca_interrupt_info *sdca_irq_allocate(struct device *sdev,
599 					      struct regmap *regmap, int irq)
600 {
601 	struct sdca_interrupt_info *info;
602 	int ret, i;
603 
604 	info = devm_kzalloc(sdev, sizeof(*info), GFP_KERNEL);
605 	if (!info)
606 		return ERR_PTR(-ENOMEM);
607 
608 	info->irq_chip = sdca_irq_chip;
609 
610 	for (i = 0; i < ARRAY_SIZE(info->irqs); i++)
611 		info->irqs[i].device_regmap = regmap;
612 
613 	ret = devm_mutex_init(sdev, &info->irq_lock);
614 	if (ret)
615 		return ERR_PTR(ret);
616 
617 	ret = devm_regmap_add_irq_chip(sdev, regmap, irq, IRQF_ONESHOT, 0,
618 				       &info->irq_chip, &info->irq_data);
619 	if (ret) {
620 		dev_err(sdev, "failed to register irq chip: %d\n", ret);
621 		return ERR_PTR(ret);
622 	}
623 
624 	dev_dbg(sdev, "registered on irq %d\n", irq);
625 
626 	return info;
627 }
628 EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA");
629 
irq_enable_flags(struct sdca_function_data * function,struct sdca_interrupt_info * info,bool early)630 static void irq_enable_flags(struct sdca_function_data *function,
631 			     struct sdca_interrupt_info *info, bool early)
632 {
633 	struct sdca_interrupt *interrupt;
634 	int i;
635 
636 	for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
637 		interrupt = &info->irqs[i];
638 
639 		if (!interrupt || interrupt->function != function)
640 			continue;
641 
642 		switch (SDCA_CTL_TYPE(interrupt->entity->type,
643 				      interrupt->control->sel)) {
644 		case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
645 			if (early)
646 				enable_irq(interrupt->irq);
647 			break;
648 		default:
649 			if (!early)
650 				enable_irq(interrupt->irq);
651 			break;
652 		}
653 	}
654 }
655 
656 /**
657  * sdca_irq_enable_early - Re-enable early SDCA IRQs for a given function
658  * @function: Pointer to the SDCA Function.
659  * @info: Pointer to the SDCA interrupt info for this device.
660  *
661  * The early version of the IRQ enable allows enabling IRQs which may be
662  * necessary to bootstrap functionality for other IRQs, such as the FDL
663  * process.
664  */
sdca_irq_enable_early(struct sdca_function_data * function,struct sdca_interrupt_info * info)665 void sdca_irq_enable_early(struct sdca_function_data *function,
666 			   struct sdca_interrupt_info *info)
667 {
668 	irq_enable_flags(function, info, true);
669 }
670 EXPORT_SYMBOL_NS_GPL(sdca_irq_enable_early, "SND_SOC_SDCA");
671 
672 /**
673  * sdca_irq_enable - Re-enable SDCA IRQs for a given function
674  * @function: Pointer to the SDCA Function.
675  * @info: Pointer to the SDCA interrupt info for this device.
676  */
sdca_irq_enable(struct sdca_function_data * function,struct sdca_interrupt_info * info)677 void sdca_irq_enable(struct sdca_function_data *function,
678 		     struct sdca_interrupt_info *info)
679 {
680 	irq_enable_flags(function, info, false);
681 }
682 EXPORT_SYMBOL_NS_GPL(sdca_irq_enable, "SND_SOC_SDCA");
683 
684 /**
685  * sdca_irq_disable - Disable SDCA IRQs for a given function
686  * @function: Pointer to the SDCA Function.
687  * @info: Pointer to the SDCA interrupt info for this device.
688  */
sdca_irq_disable(struct sdca_function_data * function,struct sdca_interrupt_info * info)689 void sdca_irq_disable(struct sdca_function_data *function,
690 		      struct sdca_interrupt_info *info)
691 {
692 	struct sdca_interrupt *interrupt;
693 	int i;
694 
695 	for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
696 		interrupt = &info->irqs[i];
697 
698 		if (!interrupt || interrupt->function != function)
699 			continue;
700 
701 		disable_irq(interrupt->irq);
702 	}
703 }
704 EXPORT_SYMBOL_NS_GPL(sdca_irq_disable, "SND_SOC_SDCA");
705