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