Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: Add SDCA IRQ support and some misc fixups

Merge series from Charles Keepax <ckeepax@opensource.cirrus.com>:

Add a maintainers entry for SDCA, do a couple of small fixups for
previous chains, and then adding the beginnings of the SDCA IRQ
handling. This is based around a regmap IRQ chip and a few helper
functions that can be called from the client drivers to setup the
IRQs.

Mark Brown c1d10f4c 29ddce17

+564 -8
+11
MAINTAINERS
··· 22298 22298 S: Maintained 22299 22299 F: drivers/clocksource/scx200_hrt.c 22300 22300 22301 + SDCA LIBRARY AND CLASS DRIVER 22302 + M: Charles Keepax <ckeepax@opensource.cirrus.com> 22303 + M: Maciej Strozek <mstrozek@opensource.cirrus.com> 22304 + R: Bard Liao <yung-chuan.liao@linux.intel.com> 22305 + R: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> 22306 + L: linux-sound@vger.kernel.org 22307 + L: patches@opensource.cirrus.com 22308 + S: Maintained 22309 + F: include/sound/sdca* 22310 + F: sound/soc/sdca/* 22311 + 22301 22312 SDRICOH_CS MMC/SD HOST CONTROLLER INTERFACE DRIVER 22302 22313 M: Sascha Sommer <saschasommer@freenet.de> 22303 22314 L: sdricohcs-devel@lists.sourceforge.net (subscribers-only)
+11
include/sound/sdca_function.h
··· 17 17 struct sdca_entity; 18 18 struct sdca_function_desc; 19 19 20 + #define SDCA_NO_INTERRUPT -1 21 + 20 22 /* 21 23 * The addressing space for SDCA relies on 7 bits for Entities, so a 22 24 * maximum of 128 Entities per function can be represented. ··· 319 317 SDCA_SELECTED_MODE_INDEX = 0, 320 318 SDCA_SELECTED_MODE_TERM_TYPE = 1, 321 319 SDCA_SELECTED_MODE_NCOLS = 2, 320 + }; 321 + 322 + /** 323 + * enum sdca_detected_mode_values - Predefined GE Detected Mode values 324 + */ 325 + enum sdca_detected_mode_values { 326 + SDCA_DETECTED_MODE_JACK_UNPLUGGED = 0, 327 + SDCA_DETECTED_MODE_JACK_UNKNOWN = 1, 328 + SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS = 2, 322 329 }; 323 330 324 331 /**
+78
include/sound/sdca_interrupts.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * The MIPI SDCA specification is available for public downloads at 4 + * https://www.mipi.org/mipi-sdca-v1-0-download 5 + * 6 + * Copyright (C) 2025 Cirrus Logic, Inc. and 7 + * Cirrus Logic International Semiconductor Ltd. 8 + */ 9 + 10 + #ifndef __SDCA_INTERRUPTS_H__ 11 + #define __SDCA_INTERRUPTS_H__ 12 + 13 + #include <linux/interrupt.h> 14 + #include <linux/mutex.h> 15 + #include <linux/regmap.h> 16 + 17 + struct device; 18 + struct snd_soc_component; 19 + struct sdca_function_data; 20 + 21 + #define SDCA_MAX_INTERRUPTS 31 /* the last bit is reserved for future extensions */ 22 + 23 + /** 24 + * struct sdca_interrupt - contains information about a single SDCA interrupt 25 + * @name: The name of the interrupt. 26 + * @component: Pointer to the ASoC component owns the interrupt. 27 + * @function: Pointer to the Function that the interrupt is associated with. 28 + * @entity: Pointer to the Entity that the interrupt is associated with. 29 + * @control: Pointer to the Control that the interrupt is associated with. 30 + * @priv: Pointer to private data for use by the handler. 31 + * @externally_requested: Internal flag used to check if a client driver has 32 + * already requested the interrupt, for custom handling, allowing the core to 33 + * skip handling this interrupt. 34 + */ 35 + struct sdca_interrupt { 36 + const char *name; 37 + 38 + struct snd_soc_component *component; 39 + struct sdca_function_data *function; 40 + struct sdca_entity *entity; 41 + struct sdca_control *control; 42 + 43 + void *priv; 44 + 45 + bool externally_requested; 46 + }; 47 + 48 + /** 49 + * struct sdca_interrupt_info - contains top-level SDCA interrupt information 50 + * @irq_chip: regmap irq chip structure. 51 + * @irq_data: regmap irq chip data structure. 52 + * @irqs: Array of data for each individual IRQ. 53 + * @irq_lock: Protects access to the list of sdca_interrupt structures. 54 + */ 55 + struct sdca_interrupt_info { 56 + struct regmap_irq_chip irq_chip; 57 + struct regmap_irq_chip_data *irq_data; 58 + 59 + struct sdca_interrupt irqs[SDCA_MAX_INTERRUPTS]; 60 + 61 + struct mutex irq_lock; /* Protect irqs list across functions */ 62 + }; 63 + 64 + int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *interrupt_info, 65 + int sdca_irq, const char *name, irq_handler_t handler, 66 + void *data); 67 + int sdca_irq_data_populate(struct snd_soc_component *component, 68 + struct sdca_function_data *function, 69 + struct sdca_entity *entity, 70 + struct sdca_control *control, 71 + struct sdca_interrupt *interrupt); 72 + int sdca_irq_populate(struct sdca_function_data *function, 73 + struct snd_soc_component *component, 74 + struct sdca_interrupt_info *info); 75 + struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, 76 + struct regmap *regmap, int irq); 77 + 78 + #endif
+7
sound/soc/sdca/Kconfig
··· 15 15 tristate "SDCA HID support" 16 16 depends on SND_SOC_SDCA && HID 17 17 18 + config SND_SOC_SDCA_IRQ 19 + tristate 20 + select REGMAP 21 + select REGMAP_IRQ 22 + help 23 + This option enables support for SDCA IRQs. 24 + 18 25 endmenu
+3 -2
sound/soc/sdca/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 3 3 snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o 4 - 5 4 snd-soc-sdca-hid-y := sdca_hid.o 5 + snd-soc-sdca-irq-y := sdca_interrupts.o 6 6 7 - obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o 8 7 obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o 8 + obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o 9 + obj-$(CONFIG_SND_SOC_SDCA_IRQ) += snd-soc-sdca-irq.o
+13 -6
sound/soc/sdca/sdca_asoc.c
··· 93 93 94 94 /** 95 95 * sdca_asoc_count_component - count the various component parts 96 + * @dev: Pointer to the device against which allocations will be done. 96 97 * @function: Pointer to the Function information. 97 98 * @num_widgets: Output integer pointer, will be filled with the 98 99 * required number of DAPM widgets for the Function. ··· 246 245 if (!values) 247 246 return -ENOMEM; 248 247 249 - texts[0] = "No Jack"; 248 + texts[0] = "Jack Unplugged"; 250 249 texts[1] = "Jack Unknown"; 251 250 texts[2] = "Detection in Progress"; 252 - values[0] = 0; 253 - values[1] = 1; 254 - values[2] = 2; 251 + values[0] = SDCA_DETECTED_MODE_JACK_UNPLUGGED; 252 + values[1] = SDCA_DETECTED_MODE_JACK_UNKNOWN; 253 + values[2] = SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS; 255 254 for (i = 0; i < range->rows; i++) { 256 255 enum sdca_terminal_type type; 257 256 ··· 398 397 from = widget->off_val; 399 398 to = widget->on_val; 400 399 break; 400 + default: 401 + return 0; 401 402 } 402 403 403 404 for (i = 0; i < entity->pde.num_max_delay; i++) { ··· 998 995 * sdca_asoc_populate_controls - fill in an array of ALSA controls for a Function 999 996 * @dev: Pointer to the device against which allocations will be done. 1000 997 * @function: Pointer to the Function information. 1001 - * @route: Array of ALSA controls to be populated. 998 + * @kctl: Array of ALSA controls to be populated. 1002 999 * 1003 1000 * This function populates an array of ALSA controls from the DisCo 1004 1001 * information for a particular SDCA Function. Typically, ··· 1245 1242 * sdca_asoc_populate_component - fill in a component driver for a Function 1246 1243 * @dev: Pointer to the device against which allocations will be done. 1247 1244 * @function: Pointer to the Function information. 1248 - * @copmonent_drv: Pointer to the component driver to be populated. 1245 + * @component_drv: Pointer to the component driver to be populated. 1246 + * @dai_drv: Pointer to the DAI driver array to be allocated and populated. 1247 + * @num_dai_drv: Pointer to integer that will be populated with the number of 1248 + * DAI drivers. 1249 + * @ops: DAI ops pointer that will be used for each DAI driver. 1249 1250 * 1250 1251 * This function populates a snd_soc_component_driver structure based 1251 1252 * on the DisCo information for a particular SDCA Function. It does
+2
sound/soc/sdca/sdca_functions.c
··· 912 912 &tmp); 913 913 if (!ret) 914 914 control->interrupt_position = tmp; 915 + else 916 + control->interrupt_position = SDCA_NO_INTERRUPT; 915 917 916 918 control->label = find_sdca_control_label(dev, entity, control); 917 919 if (!control->label)
+439
sound/soc/sdca/sdca_interrupts.c
··· 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/interrupt.h> 15 + #include <linux/regmap.h> 16 + #include <linux/soundwire/sdw.h> 17 + #include <linux/soundwire/sdw_registers.h> 18 + #include <sound/sdca.h> 19 + #include <sound/sdca_function.h> 20 + #include <sound/sdca_interrupts.h> 21 + #include <sound/soc-component.h> 22 + #include <sound/soc.h> 23 + 24 + #define IRQ_SDCA(number) REGMAP_IRQ_REG(number, ((number) / BITS_PER_BYTE), \ 25 + SDW_SCP_SDCA_INTMASK_SDCA_##number) 26 + 27 + static const struct regmap_irq regmap_irqs[SDCA_MAX_INTERRUPTS] = { 28 + IRQ_SDCA(0), 29 + IRQ_SDCA(1), 30 + IRQ_SDCA(2), 31 + IRQ_SDCA(3), 32 + IRQ_SDCA(4), 33 + IRQ_SDCA(5), 34 + IRQ_SDCA(6), 35 + IRQ_SDCA(7), 36 + IRQ_SDCA(8), 37 + IRQ_SDCA(9), 38 + IRQ_SDCA(10), 39 + IRQ_SDCA(11), 40 + IRQ_SDCA(12), 41 + IRQ_SDCA(13), 42 + IRQ_SDCA(14), 43 + IRQ_SDCA(15), 44 + IRQ_SDCA(16), 45 + IRQ_SDCA(17), 46 + IRQ_SDCA(18), 47 + IRQ_SDCA(19), 48 + IRQ_SDCA(20), 49 + IRQ_SDCA(21), 50 + IRQ_SDCA(22), 51 + IRQ_SDCA(23), 52 + IRQ_SDCA(24), 53 + IRQ_SDCA(25), 54 + IRQ_SDCA(26), 55 + IRQ_SDCA(27), 56 + IRQ_SDCA(28), 57 + IRQ_SDCA(29), 58 + IRQ_SDCA(30), 59 + }; 60 + 61 + static const struct regmap_irq_chip sdca_irq_chip = { 62 + .name = "sdca_irq", 63 + 64 + .status_base = SDW_SCP_SDCA_INT1, 65 + .unmask_base = SDW_SCP_SDCA_INTMASK1, 66 + .ack_base = SDW_SCP_SDCA_INT1, 67 + .num_regs = 4, 68 + 69 + .irqs = regmap_irqs, 70 + .num_irqs = SDCA_MAX_INTERRUPTS, 71 + 72 + .runtime_pm = true, 73 + }; 74 + 75 + static irqreturn_t base_handler(int irq, void *data) 76 + { 77 + struct sdca_interrupt *interrupt = data; 78 + struct device *dev = interrupt->component->dev; 79 + 80 + dev_info(dev, "%s irq without full handling\n", interrupt->name); 81 + 82 + return IRQ_HANDLED; 83 + } 84 + 85 + static irqreturn_t function_status_handler(int irq, void *data) 86 + { 87 + struct sdca_interrupt *interrupt = data; 88 + struct device *dev = interrupt->component->dev; 89 + unsigned int reg, val; 90 + unsigned long status; 91 + unsigned int mask; 92 + int ret; 93 + 94 + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, 95 + interrupt->control->sel, 0); 96 + 97 + ret = regmap_read(interrupt->component->regmap, reg, &val); 98 + if (ret < 0) { 99 + dev_err(dev, "failed to read function status: %d\n", ret); 100 + return IRQ_NONE; 101 + } 102 + 103 + dev_dbg(dev, "function status: %#x\n", val); 104 + 105 + status = val; 106 + for_each_set_bit(mask, &status, BITS_PER_BYTE) { 107 + mask = 1 << mask; 108 + 109 + switch (mask) { 110 + case SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION: 111 + //FIXME: Add init writes 112 + break; 113 + case SDCA_CTL_ENTITY_0_FUNCTION_FAULT: 114 + dev_err(dev, "function fault\n"); 115 + break; 116 + case SDCA_CTL_ENTITY_0_UMP_SEQUENCE_FAULT: 117 + dev_err(dev, "ump sequence fault\n"); 118 + break; 119 + case SDCA_CTL_ENTITY_0_FUNCTION_BUSY: 120 + dev_info(dev, "unexpected function busy\n"); 121 + break; 122 + case SDCA_CTL_ENTITY_0_DEVICE_NEWLY_ATTACHED: 123 + case SDCA_CTL_ENTITY_0_INTS_DISABLED_ABNORMALLY: 124 + case SDCA_CTL_ENTITY_0_STREAMING_STOPPED_ABNORMALLY: 125 + case SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET: 126 + break; 127 + } 128 + } 129 + 130 + ret = regmap_write(interrupt->component->regmap, reg, val); 131 + if (ret < 0) { 132 + dev_err(dev, "failed to clear function status: %d\n", ret); 133 + return IRQ_NONE; 134 + } 135 + 136 + return IRQ_HANDLED; 137 + } 138 + 139 + static irqreturn_t detected_mode_handler(int irq, void *data) 140 + { 141 + struct sdca_interrupt *interrupt = data; 142 + struct snd_soc_component *component = interrupt->component; 143 + struct device *dev = component->dev; 144 + struct snd_soc_card *card = component->card; 145 + struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; 146 + struct snd_kcontrol *kctl = interrupt->priv; 147 + struct snd_ctl_elem_value ucontrol; 148 + struct soc_enum *soc_enum; 149 + unsigned int reg, val; 150 + int ret; 151 + 152 + if (!kctl) { 153 + const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s", 154 + interrupt->entity->label, 155 + SDCA_CTL_SELECTED_MODE_NAME); 156 + 157 + if (!name) 158 + return -ENOMEM; 159 + 160 + kctl = snd_soc_component_get_kcontrol(component, name); 161 + if (!kctl) { 162 + dev_dbg(dev, "control not found: %s\n", name); 163 + return IRQ_NONE; 164 + } 165 + 166 + interrupt->priv = kctl; 167 + } 168 + 169 + soc_enum = (struct soc_enum *)kctl->private_value; 170 + 171 + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, 172 + interrupt->control->sel, 0); 173 + 174 + ret = regmap_read(component->regmap, reg, &val); 175 + if (ret < 0) { 176 + dev_err(dev, "failed to read detected mode: %d\n", ret); 177 + return IRQ_NONE; 178 + } 179 + 180 + switch (val) { 181 + case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS: 182 + case SDCA_DETECTED_MODE_JACK_UNKNOWN: 183 + reg = SDW_SDCA_CTL(interrupt->function->desc->adr, 184 + interrupt->entity->id, 185 + SDCA_CTL_GE_SELECTED_MODE, 0); 186 + 187 + /* 188 + * Selected mode is not normally marked as volatile register 189 + * (RW), but here force a read from the hardware. If the 190 + * detected mode is unknown we need to see what the device 191 + * selected as a "safe" option. 192 + */ 193 + regcache_drop_region(component->regmap, reg, reg); 194 + 195 + ret = regmap_read(component->regmap, reg, &val); 196 + if (ret) { 197 + dev_err(dev, "failed to re-check selected mode: %d\n", ret); 198 + return IRQ_NONE; 199 + } 200 + break; 201 + default: 202 + break; 203 + } 204 + 205 + dev_dbg(dev, "%s: %#x\n", interrupt->name, val); 206 + 207 + ucontrol.value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); 208 + 209 + down_write(rwsem); 210 + ret = kctl->put(kctl, &ucontrol); 211 + up_write(rwsem); 212 + if (ret < 0) { 213 + dev_err(dev, "failed to update selected mode: %d\n", ret); 214 + return IRQ_NONE; 215 + } 216 + 217 + snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 218 + 219 + return IRQ_HANDLED; 220 + } 221 + 222 + static int sdca_irq_request_locked(struct device *dev, 223 + struct sdca_interrupt_info *info, 224 + int sdca_irq, const char *name, 225 + irq_handler_t handler, void *data) 226 + { 227 + int irq; 228 + int ret; 229 + 230 + irq = regmap_irq_get_virq(info->irq_data, sdca_irq); 231 + if (irq < 0) 232 + return irq; 233 + 234 + ret = devm_request_threaded_irq(dev, irq, NULL, handler, 235 + IRQF_ONESHOT, name, data); 236 + if (ret) 237 + return ret; 238 + 239 + dev_dbg(dev, "requested irq %d for %s\n", irq, name); 240 + 241 + return 0; 242 + } 243 + 244 + /** 245 + * sdca_request_irq - request an individual SDCA interrupt 246 + * @dev: Pointer to the struct device against which things should be allocated. 247 + * @interrupt_info: Pointer to the interrupt information structure. 248 + * @sdca_irq: SDCA interrupt position. 249 + * @name: Name to be given to the IRQ. 250 + * @handler: A callback thread function to be called for the IRQ. 251 + * @data: Private data pointer that will be passed to the handler. 252 + * 253 + * Typically this is handled internally by sdca_irq_populate, however if 254 + * a device requires custom IRQ handling this can be called manually before 255 + * calling sdca_irq_populate, which will then skip that IRQ whilst processing. 256 + * 257 + * Return: Zero on success, and a negative error code on failure. 258 + */ 259 + int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *info, 260 + int sdca_irq, const char *name, irq_handler_t handler, 261 + void *data) 262 + { 263 + int ret; 264 + 265 + if (sdca_irq < 0 || sdca_irq > SDCA_MAX_INTERRUPTS) { 266 + dev_err(dev, "bad irq request: %d\n", sdca_irq); 267 + return -EINVAL; 268 + } 269 + 270 + guard(mutex)(&info->irq_lock); 271 + 272 + ret = sdca_irq_request_locked(dev, info, sdca_irq, name, handler, data); 273 + if (ret) { 274 + dev_err(dev, "failed to request irq %s: %d\n", name, ret); 275 + return ret; 276 + } 277 + 278 + info->irqs[sdca_irq].externally_requested = true; 279 + 280 + return 0; 281 + } 282 + EXPORT_SYMBOL_NS_GPL(sdca_irq_request, "SND_SOC_SDCA_IRQ"); 283 + 284 + /** 285 + * sdca_irq_data_populate - Populate common interrupt data 286 + * @component: Pointer to the ASoC component for the Function. 287 + * @function: Pointer to the SDCA Function. 288 + * @entity: Pointer to the SDCA Entity. 289 + * @control: Pointer to the SDCA Control. 290 + * @interrupt: Pointer to the SDCA interrupt for this IRQ. 291 + * 292 + * Return: Zero on success, and a negative error code on failure. 293 + */ 294 + int sdca_irq_data_populate(struct snd_soc_component *component, 295 + struct sdca_function_data *function, 296 + struct sdca_entity *entity, 297 + struct sdca_control *control, 298 + struct sdca_interrupt *interrupt) 299 + { 300 + struct device *dev = component->dev; 301 + const char *name; 302 + 303 + name = devm_kasprintf(dev, GFP_KERNEL, "%s %s %s", function->desc->name, 304 + entity->label, control->label); 305 + if (!name) 306 + return -ENOMEM; 307 + 308 + interrupt->name = name; 309 + interrupt->component = component; 310 + interrupt->function = function; 311 + interrupt->entity = entity; 312 + interrupt->control = control; 313 + 314 + return 0; 315 + } 316 + EXPORT_SYMBOL_NS_GPL(sdca_irq_data_populate, "SND_SOC_SDCA_IRQ"); 317 + 318 + /** 319 + * sdca_irq_populate - Request all the individual IRQs for an SDCA Function 320 + * @function: Pointer to the SDCA Function. 321 + * @component: Pointer to the ASoC component for the Function. 322 + * @info: Pointer to the SDCA interrupt info for this device. 323 + * 324 + * Typically this would be called from the driver for a single SDCA Function. 325 + * 326 + * Return: Zero on success, and a negative error code on failure. 327 + */ 328 + int sdca_irq_populate(struct sdca_function_data *function, 329 + struct snd_soc_component *component, 330 + struct sdca_interrupt_info *info) 331 + { 332 + struct device *dev = component->dev; 333 + int i, j; 334 + 335 + guard(mutex)(&info->irq_lock); 336 + 337 + for (i = 0; i < function->num_entities; i++) { 338 + struct sdca_entity *entity = &function->entities[i]; 339 + 340 + for (j = 0; j < entity->num_controls; j++) { 341 + struct sdca_control *control = &entity->controls[j]; 342 + int irq = control->interrupt_position; 343 + struct sdca_interrupt *interrupt; 344 + irq_handler_t handler; 345 + const char *name; 346 + int ret; 347 + 348 + if (irq == SDCA_NO_INTERRUPT) { 349 + continue; 350 + } else if (irq < 0 || irq >= SDCA_MAX_INTERRUPTS) { 351 + dev_err(dev, "bad irq position: %d\n", irq); 352 + return -EINVAL; 353 + } 354 + 355 + interrupt = &info->irqs[irq]; 356 + 357 + if (interrupt->externally_requested) { 358 + dev_dbg(dev, 359 + "skipping irq %d, externally requested\n", 360 + irq); 361 + continue; 362 + } 363 + 364 + ret = sdca_irq_data_populate(component, function, entity, 365 + control, interrupt); 366 + if (ret) 367 + return ret; 368 + 369 + handler = base_handler; 370 + 371 + switch (entity->type) { 372 + case SDCA_ENTITY_TYPE_ENTITY_0: 373 + if (control->sel == SDCA_CTL_ENTITY_0_FUNCTION_STATUS) 374 + handler = function_status_handler; 375 + break; 376 + case SDCA_ENTITY_TYPE_GE: 377 + if (control->sel == SDCA_CTL_GE_DETECTED_MODE) 378 + handler = detected_mode_handler; 379 + break; 380 + default: 381 + break; 382 + } 383 + 384 + ret = sdca_irq_request_locked(dev, info, irq, interrupt->name, 385 + handler, interrupt); 386 + if (ret) { 387 + dev_err(dev, "failed to request irq %s: %d\n", 388 + name, ret); 389 + return ret; 390 + } 391 + } 392 + } 393 + 394 + return 0; 395 + } 396 + EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA_IRQ"); 397 + 398 + /** 399 + * sdca_irq_allocate - allocate an SDCA interrupt structure for a device 400 + * @dev: Device pointer against which things should be allocated. 401 + * @regmap: regmap to be used for accessing the SDCA IRQ registers. 402 + * @irq: The interrupt number. 403 + * 404 + * Typically this would be called from the top level driver for the whole 405 + * SDCA device, as only a single instance is required across all Functions 406 + * on the device. 407 + * 408 + * Return: A pointer to the allocated sdca_interrupt_info struct, or an 409 + * error code. 410 + */ 411 + struct sdca_interrupt_info *sdca_irq_allocate(struct device *dev, 412 + struct regmap *regmap, int irq) 413 + { 414 + struct sdca_interrupt_info *info; 415 + int ret; 416 + 417 + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 418 + if (!info) 419 + return ERR_PTR(-ENOMEM); 420 + 421 + info->irq_chip = sdca_irq_chip; 422 + 423 + devm_mutex_init(dev, &info->irq_lock); 424 + 425 + ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0, 426 + &info->irq_chip, &info->irq_data); 427 + if (ret) { 428 + dev_err(dev, "failed to register irq chip: %d\n", ret); 429 + return ERR_PTR(ret); 430 + } 431 + 432 + dev_dbg(dev, "registered on irq %d\n", irq); 433 + 434 + return info; 435 + } 436 + EXPORT_SYMBOL_NS_GPL(sdca_irq_allocate, "SND_SOC_SDCA_IRQ"); 437 + 438 + MODULE_LICENSE("GPL"); 439 + MODULE_DESCRIPTION("SDCA IRQ library");