@@ -25,6 +25,7 @@ struct jack_state {
};
int sdca_jack_alloc_state(struct sdca_interrupt *interrupt);
+void sdca_jack_reset_state(struct sdca_interrupt *interrupt);
int sdca_jack_process(struct sdca_interrupt *interrupt);
int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *jack);
void sdca_jack_fixup_controls(struct sdca_interrupt_info *info);
@@ -519,9 +519,17 @@ int sdca_irq_populate(struct sdca_function_data *function,
handler = function_status_handler;
break;
case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
- ret = sdca_jack_alloc_state(interrupt);
- if (ret)
- return ret;
+ /*
+ * The state outlives the card, so on a rebind
+ * reuse the one already allocated against this
+ * device rather than leaking it and starting a
+ * new one.
+ */
+ if (!interrupt->priv) {
+ ret = sdca_jack_alloc_state(interrupt);
+ if (ret)
+ return ret;
+ }
handler = detected_mode_handler;
break;
@@ -577,6 +585,15 @@ void sdca_irq_cleanup(struct device *dev,
sdca_irq_free_locked(dev, info, i, interrupt->name, interrupt);
+ switch (SDCA_CTL_TYPE(interrupt->entity->type,
+ interrupt->control->sel)) {
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ sdca_jack_reset_state(interrupt);
+ break;
+ default:
+ break;
+ }
+
kfree(interrupt->name);
}
}
@@ -145,6 +145,27 @@ int sdca_jack_alloc_state(struct sdca_interrupt *interrupt)
}
EXPORT_SYMBOL_NS_GPL(sdca_jack_alloc_state, "SND_SOC_SDCA");
+/**
+ * sdca_jack_reset_state - drop state belonging to a card that is going away
+ * @interrupt: SDCA interrupt structure.
+ *
+ * The kcontrol and the ASoC jack are owned by the soundcard, not by the
+ * codec device the state is allocated against, so both are dangling once
+ * the card is torn down. Clear them, leaving the allocation in place to
+ * be reused if the card is bound again.
+ */
+void sdca_jack_reset_state(struct sdca_interrupt *interrupt)
+{
+ struct jack_state *jack_state = interrupt->priv;
+
+ if (!jack_state)
+ return;
+
+ jack_state->kctl = NULL;
+ jack_state->jack = NULL;
+}
+EXPORT_SYMBOL_NS_GPL(sdca_jack_reset_state, "SND_SOC_SDCA");
+
/**
* sdca_jack_set_jack - attach an ASoC jack to SDCA
* @info: SDCA interrupt information.