@@ -33,6 +33,7 @@ struct sdca_function_data;
* @priv: Pointer to private data for use by the handler.
* @irq: IRQ number allocated to this interrupt, also used internally to track
* the IRQ being assigned.
+ * @early_request: Flag to indicate this IRQ was requested at bus probe time.
*/
struct sdca_interrupt {
const char *name;
@@ -48,6 +49,7 @@ struct sdca_interrupt {
void *priv;
int irq;
+ bool early_request;
};
/**
@@ -86,6 +88,9 @@ int sdca_irq_populate(struct sdca_function_data *function,
void sdca_irq_cleanup(struct device *dev,
struct sdca_function_data *function,
struct sdca_interrupt_info *info);
+void sdca_irq_cleanup_late(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_interrupt_info *info);
struct sdca_interrupt_info *devm_sdca_irq_allocate(struct device *dev,
struct regmap *regmap, int irq);
@@ -415,7 +415,7 @@ static void class_function_remove(struct auxiliary_device *auxdev)
{
struct class_function_drv *drv = auxiliary_get_drvdata(auxdev);
- sdca_irq_cleanup(drv->dev, drv->function, drv->core->irq_info);
+ sdca_irq_cleanup_late(drv->dev, drv->function, drv->core->irq_info);
}
static int class_function_runtime_suspend(struct device *dev)
@@ -447,6 +447,8 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
if (ret)
return ret;
+ interrupt->early_request = true;
+
ret = sdca_fdl_alloc_state(interrupt);
if (ret)
return ret;
@@ -553,17 +555,10 @@ int sdca_irq_populate(struct sdca_function_data *function,
}
EXPORT_SYMBOL_NS_GPL(sdca_irq_populate, "SND_SOC_SDCA");
-/**
- * sdca_irq_cleanup - Free all the individual IRQs for an SDCA Function
- * @sdev: Device pointer against which the sdca_interrupt_info was allocated.
- * @function: Pointer to the SDCA Function.
- * @info: Pointer to the SDCA interrupt info for this device.
- *
- * Typically this would be called from the driver for a single SDCA Function.
- */
-void sdca_irq_cleanup(struct device *dev,
- struct sdca_function_data *function,
- struct sdca_interrupt_info *info)
+static void sdca_irq_cleanup_flags(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_interrupt_info *info,
+ bool late_cleanup)
{
int i;
@@ -575,13 +570,49 @@ void sdca_irq_cleanup(struct device *dev,
if (interrupt->function != function || !interrupt->irq)
continue;
+ if (interrupt->early_request && !late_cleanup)
+ continue;
+
sdca_irq_free_locked(dev, info, i, interrupt->name, interrupt);
kfree(interrupt->name);
}
}
+
+/**
+ * sdca_irq_cleanup - Free the regular IRQs for an SDCA Function
+ * @dev: Device pointer against which the sdca_interrupt_info was allocated.
+ * @function: Pointer to the SDCA Function.
+ * @info: Pointer to the SDCA interrupt info for this device.
+ *
+ * Typically this would be called from the driver for a single SDCA Function
+ * from component remove.
+ */
+void sdca_irq_cleanup(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_interrupt_info *info)
+{
+ sdca_irq_cleanup_flags(dev, function, info, false);
+}
EXPORT_SYMBOL_NS_GPL(sdca_irq_cleanup, "SND_SOC_SDCA");
+/**
+ * sdca_irq_cleanup_late - Free the early IRQs for an SDCA Function
+ * @dev: Device pointer against which the sdca_interrupt_info was allocated.
+ * @function: Pointer to the SDCA Function.
+ * @info: Pointer to the SDCA interrupt info for this device.
+ *
+ * Typically this would be called from the driver for a single SDCA Function
+ * from bus remove.
+ */
+void sdca_irq_cleanup_late(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_interrupt_info *info)
+{
+ sdca_irq_cleanup_flags(dev, function, info, true);
+}
+EXPORT_SYMBOL_NS_GPL(sdca_irq_cleanup_late, "SND_SOC_SDCA");
+
/**
* devm_sdca_irq_allocate - allocate an SDCA interrupt structure for a device
* @sdev: Device pointer against which things should be allocated.