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/cleanup.h> 11 #include <linux/device.h> 12 #include <linux/dev_printk.h> 13 #include <linux/soundwire/sdw.h> 14 #include <linux/soundwire/sdw_registers.h> 15 #include <linux/sprintf.h> 16 #include <linux/regmap.h> 17 #include <linux/rwsem.h> 18 #include <sound/asound.h> 19 #include <sound/control.h> 20 #include <sound/jack.h> 21 #include <sound/sdca.h> 22 #include <sound/sdca_function.h> 23 #include <sound/sdca_interrupts.h> 24 #include <sound/sdca_jack.h> 25 #include <sound/soc-component.h> 26 #include <sound/soc-jack.h> 27 #include <sound/soc.h> 28 29 /** 30 * sdca_jack_process - Process an SDCA jack event 31 * @interrupt: SDCA interrupt structure 32 * 33 * Return: Zero on success or a negative error code. 34 */ 35 int sdca_jack_process(struct sdca_interrupt *interrupt) 36 { 37 struct device *dev = interrupt->dev; 38 struct snd_soc_component *component = interrupt->component; 39 struct snd_soc_card *card = component->card; 40 struct rw_semaphore *rwsem = &card->snd_card->controls_rwsem; 41 struct jack_state *state = interrupt->priv; 42 struct snd_kcontrol *kctl = state->kctl; 43 struct snd_ctl_elem_value *ucontrol __free(kfree) = NULL; 44 struct soc_enum *soc_enum; 45 unsigned int reg, val; 46 int ret; 47 48 if (!kctl) { 49 const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s", 50 interrupt->entity->label, 51 SDCA_CTL_SELECTED_MODE_NAME); 52 53 if (!name) 54 return -ENOMEM; 55 56 kctl = snd_soc_component_get_kcontrol(component, name); 57 if (!kctl) { 58 dev_dbg(dev, "control not found: %s\n", name); 59 return -ENOENT; 60 } 61 62 state->kctl = kctl; 63 } 64 65 soc_enum = (struct soc_enum *)kctl->private_value; 66 67 reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, 68 interrupt->control->sel, 0); 69 70 ret = regmap_read(interrupt->function_regmap, reg, &val); 71 if (ret < 0) { 72 dev_err(dev, "failed to read detected mode: %d\n", ret); 73 return ret; 74 } 75 76 switch (val) { 77 case SDCA_DETECTED_MODE_DETECTION_IN_PROGRESS: 78 case SDCA_DETECTED_MODE_JACK_UNKNOWN: 79 reg = SDW_SDCA_CTL(interrupt->function->desc->adr, 80 interrupt->entity->id, 81 SDCA_CTL_GE_SELECTED_MODE, 0); 82 83 /* 84 * Selected mode is not normally marked as volatile register 85 * (RW), but here force a read from the hardware. If the 86 * detected mode is unknown we need to see what the device 87 * selected as a "safe" option. 88 */ 89 regcache_drop_region(interrupt->function_regmap, reg, reg); 90 91 ret = regmap_read(interrupt->function_regmap, reg, &val); 92 if (ret) { 93 dev_err(dev, "failed to re-check selected mode: %d\n", ret); 94 return ret; 95 } 96 break; 97 default: 98 break; 99 } 100 101 dev_dbg(dev, "%s: %#x\n", interrupt->name, val); 102 103 ucontrol = kzalloc(sizeof(*ucontrol), GFP_KERNEL); 104 if (!ucontrol) 105 return -ENOMEM; 106 107 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(soc_enum, val); 108 109 down_write(rwsem); 110 ret = kctl->put(kctl, ucontrol); 111 up_write(rwsem); 112 if (ret < 0) { 113 dev_err(dev, "failed to update selected mode: %d\n", ret); 114 return ret; 115 } 116 117 snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 118 119 return sdca_jack_report(interrupt); 120 } 121 EXPORT_SYMBOL_NS_GPL(sdca_jack_process, "SND_SOC_SDCA"); 122 123 /** 124 * sdca_jack_alloc_state - allocate state for a jack interrupt 125 * @interrupt: SDCA interrupt structure. 126 * 127 * Return: Zero on success or a negative error code. 128 */ 129 int sdca_jack_alloc_state(struct sdca_interrupt *interrupt) 130 { 131 struct device *dev = interrupt->dev; 132 struct jack_state *jack_state; 133 134 jack_state = devm_kzalloc(dev, sizeof(*jack_state), GFP_KERNEL); 135 if (!jack_state) 136 return -ENOMEM; 137 138 interrupt->priv = jack_state; 139 140 return 0; 141 } 142 EXPORT_SYMBOL_NS_GPL(sdca_jack_alloc_state, "SND_SOC_SDCA"); 143 144 /** 145 * sdca_jack_set_jack - attach an ASoC jack to SDCA 146 * @info: SDCA interrupt information. 147 * @jack: ASoC jack to be attached. 148 * 149 * Return: Zero on success or a negative error code. 150 */ 151 int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *jack) 152 { 153 int i, ret; 154 155 guard(mutex)(&info->irq_lock); 156 157 for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) { 158 struct sdca_interrupt *interrupt = &info->irqs[i]; 159 struct sdca_control *control = interrupt->control; 160 struct sdca_entity *entity = interrupt->entity; 161 struct jack_state *jack_state; 162 163 if (!interrupt->irq) 164 continue; 165 166 switch (SDCA_CTL_TYPE(entity->type, control->sel)) { 167 case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): 168 jack_state = interrupt->priv; 169 jack_state->jack = jack; 170 171 /* Report initial state in case IRQ was already handled */ 172 ret = sdca_jack_report(interrupt); 173 if (ret) 174 return ret; 175 break; 176 default: 177 break; 178 } 179 } 180 181 return 0; 182 } 183 EXPORT_SYMBOL_NS_GPL(sdca_jack_set_jack, "SND_SOC_SDCA"); 184 185 int sdca_jack_report(struct sdca_interrupt *interrupt) 186 { 187 struct jack_state *jack_state = interrupt->priv; 188 struct sdca_control_range *range; 189 enum sdca_terminal_type type; 190 unsigned int report = 0; 191 unsigned int reg, val; 192 int ret; 193 194 reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id, 195 SDCA_CTL_GE_SELECTED_MODE, 0); 196 197 ret = regmap_read(interrupt->function_regmap, reg, &val); 198 if (ret) { 199 dev_err(interrupt->dev, "failed to read selected mode: %d\n", ret); 200 return ret; 201 } 202 203 range = sdca_selector_find_range(interrupt->dev, interrupt->entity, 204 SDCA_CTL_GE_SELECTED_MODE, 205 SDCA_SELECTED_MODE_NCOLS, 0); 206 if (!range) 207 return -EINVAL; 208 209 type = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX, 210 val, SDCA_SELECTED_MODE_TERM_TYPE); 211 212 switch (type) { 213 case SDCA_TERM_TYPE_LINEIN_STEREO: 214 case SDCA_TERM_TYPE_LINEIN_FRONT_LR: 215 case SDCA_TERM_TYPE_LINEIN_CENTER_LFE: 216 case SDCA_TERM_TYPE_LINEIN_SURROUND_LR: 217 case SDCA_TERM_TYPE_LINEIN_REAR_LR: 218 report = SND_JACK_LINEIN; 219 break; 220 case SDCA_TERM_TYPE_LINEOUT_STEREO: 221 case SDCA_TERM_TYPE_LINEOUT_FRONT_LR: 222 case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE: 223 case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR: 224 case SDCA_TERM_TYPE_LINEOUT_REAR_LR: 225 report = SND_JACK_LINEOUT; 226 break; 227 case SDCA_TERM_TYPE_MIC_JACK: 228 report = SND_JACK_MICROPHONE; 229 break; 230 case SDCA_TERM_TYPE_HEADPHONE_JACK: 231 report = SND_JACK_HEADPHONE; 232 break; 233 case SDCA_TERM_TYPE_HEADSET_JACK: 234 report = SND_JACK_HEADSET; 235 break; 236 default: 237 break; 238 } 239 240 snd_soc_jack_report(jack_state->jack, report, 0xFFFF); 241 242 return 0; 243 } 244 EXPORT_SYMBOL_NS_GPL(sdca_jack_report, "SND_SOC_SDCA"); 245