1 /* 2 * soc-jack.c -- ALSA SoC jack handling 3 * 4 * Copyright 2008 Wolfson Microelectronics PLC. 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14 #include <sound/jack.h> 15 #include <sound/soc.h> 16 #include <linux/gpio.h> 17 #include <linux/gpio/consumer.h> 18 #include <linux/interrupt.h> 19 #include <linux/workqueue.h> 20 #include <linux/delay.h> 21 #include <linux/export.h> 22 #include <trace/events/asoc.h> 23 24 /** 25 * snd_soc_card_jack_new - Create a new jack 26 * @card: ASoC card 27 * @id: an identifying string for this jack 28 * @type: a bitmask of enum snd_jack_type values that can be detected by 29 * this jack 30 * @jack: structure to use for the jack 31 * @pins: Array of jack pins to be added to the jack or NULL 32 * @num_pins: Number of elements in the @pins array 33 * 34 * Creates a new jack object. 35 * 36 * Returns zero if successful, or a negative error code on failure. 37 * On success jack will be initialised. 38 */ 39 int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, 40 struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins, 41 unsigned int num_pins) 42 { 43 int ret; 44 45 mutex_init(&jack->mutex); 46 jack->card = card; 47 INIT_LIST_HEAD(&jack->pins); 48 INIT_LIST_HEAD(&jack->jack_zones); 49 BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); 50 51 ret = snd_jack_new(card->snd_card, id, type, &jack->jack); 52 if (ret) 53 return ret; 54 55 if (num_pins) 56 return snd_soc_jack_add_pins(jack, num_pins, pins); 57 58 return 0; 59 } 60 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); 61 62 /** 63 * snd_soc_jack_report - Report the current status for a jack 64 * 65 * @jack: the jack 66 * @status: a bitmask of enum snd_jack_type values that are currently detected. 67 * @mask: a bitmask of enum snd_jack_type values that being reported. 68 * 69 * If configured using snd_soc_jack_add_pins() then the associated 70 * DAPM pins will be enabled or disabled as appropriate and DAPM 71 * synchronised. 72 * 73 * Note: This function uses mutexes and should be called from a 74 * context which can sleep (such as a workqueue). 75 */ 76 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) 77 { 78 struct snd_soc_dapm_context *dapm; 79 struct snd_soc_jack_pin *pin; 80 unsigned int sync = 0; 81 int enable; 82 83 trace_snd_soc_jack_report(jack, mask, status); 84 85 if (!jack) 86 return; 87 88 dapm = &jack->card->dapm; 89 90 mutex_lock(&jack->mutex); 91 92 jack->status &= ~mask; 93 jack->status |= status & mask; 94 95 trace_snd_soc_jack_notify(jack, status); 96 97 list_for_each_entry(pin, &jack->pins, list) { 98 enable = pin->mask & jack->status; 99 100 if (pin->invert) 101 enable = !enable; 102 103 if (enable) 104 snd_soc_dapm_enable_pin(dapm, pin->pin); 105 else 106 snd_soc_dapm_disable_pin(dapm, pin->pin); 107 108 /* we need to sync for this case only */ 109 sync = 1; 110 } 111 112 /* Report before the DAPM sync to help users updating micbias status */ 113 blocking_notifier_call_chain(&jack->notifier, jack->status, jack); 114 115 if (sync) 116 snd_soc_dapm_sync(dapm); 117 118 snd_jack_report(jack->jack, jack->status); 119 120 mutex_unlock(&jack->mutex); 121 } 122 EXPORT_SYMBOL_GPL(snd_soc_jack_report); 123 124 /** 125 * snd_soc_jack_add_zones - Associate voltage zones with jack 126 * 127 * @jack: ASoC jack 128 * @count: Number of zones 129 * @zones: Array of zones 130 * 131 * After this function has been called the zones specified in the 132 * array will be associated with the jack. 133 */ 134 int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count, 135 struct snd_soc_jack_zone *zones) 136 { 137 int i; 138 139 for (i = 0; i < count; i++) { 140 INIT_LIST_HEAD(&zones[i].list); 141 list_add(&(zones[i].list), &jack->jack_zones); 142 } 143 return 0; 144 } 145 EXPORT_SYMBOL_GPL(snd_soc_jack_add_zones); 146 147 /** 148 * snd_soc_jack_get_type - Based on the mic bias value, this function returns 149 * the type of jack from the zones declared in the jack type 150 * 151 * @jack: ASoC jack 152 * @micbias_voltage: mic bias voltage at adc channel when jack is plugged in 153 * 154 * Based on the mic bias value passed, this function helps identify 155 * the type of jack from the already declared jack zones 156 */ 157 int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage) 158 { 159 struct snd_soc_jack_zone *zone; 160 161 list_for_each_entry(zone, &jack->jack_zones, list) { 162 if (micbias_voltage >= zone->min_mv && 163 micbias_voltage < zone->max_mv) 164 return zone->jack_type; 165 } 166 return 0; 167 } 168 EXPORT_SYMBOL_GPL(snd_soc_jack_get_type); 169 170 /** 171 * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack 172 * 173 * @jack: ASoC jack 174 * @count: Number of pins 175 * @pins: Array of pins 176 * 177 * After this function has been called the DAPM pins specified in the 178 * pins array will have their status updated to reflect the current 179 * state of the jack whenever the jack status is updated. 180 */ 181 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count, 182 struct snd_soc_jack_pin *pins) 183 { 184 int i; 185 186 for (i = 0; i < count; i++) { 187 if (!pins[i].pin) { 188 dev_err(jack->card->dev, "ASoC: No name for pin %d\n", 189 i); 190 return -EINVAL; 191 } 192 if (!pins[i].mask) { 193 dev_err(jack->card->dev, "ASoC: No mask for pin %d" 194 " (%s)\n", i, pins[i].pin); 195 return -EINVAL; 196 } 197 198 INIT_LIST_HEAD(&pins[i].list); 199 list_add(&(pins[i].list), &jack->pins); 200 } 201 202 /* Update to reflect the last reported status; canned jack 203 * implementations are likely to set their state before the 204 * card has an opportunity to associate pins. 205 */ 206 snd_soc_jack_report(jack, 0, 0); 207 208 return 0; 209 } 210 EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins); 211 212 /** 213 * snd_soc_jack_notifier_register - Register a notifier for jack status 214 * 215 * @jack: ASoC jack 216 * @nb: Notifier block to register 217 * 218 * Register for notification of the current status of the jack. Note 219 * that it is not possible to report additional jack events in the 220 * callback from the notifier, this is intended to support 221 * applications such as enabling electrical detection only when a 222 * mechanical detection event has occurred. 223 */ 224 void snd_soc_jack_notifier_register(struct snd_soc_jack *jack, 225 struct notifier_block *nb) 226 { 227 blocking_notifier_chain_register(&jack->notifier, nb); 228 } 229 EXPORT_SYMBOL_GPL(snd_soc_jack_notifier_register); 230 231 /** 232 * snd_soc_jack_notifier_unregister - Unregister a notifier for jack status 233 * 234 * @jack: ASoC jack 235 * @nb: Notifier block to unregister 236 * 237 * Stop notifying for status changes. 238 */ 239 void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack, 240 struct notifier_block *nb) 241 { 242 blocking_notifier_chain_unregister(&jack->notifier, nb); 243 } 244 EXPORT_SYMBOL_GPL(snd_soc_jack_notifier_unregister); 245 246 #ifdef CONFIG_GPIOLIB 247 /* gpio detect */ 248 static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) 249 { 250 struct snd_soc_jack *jack = gpio->jack; 251 int enable; 252 int report; 253 254 enable = gpiod_get_value_cansleep(gpio->desc); 255 if (gpio->invert) 256 enable = !enable; 257 258 if (enable) 259 report = gpio->report; 260 else 261 report = 0; 262 263 if (gpio->jack_status_check) 264 report = gpio->jack_status_check(gpio->data); 265 266 snd_soc_jack_report(jack, report, gpio->report); 267 } 268 269 /* irq handler for gpio pin */ 270 static irqreturn_t gpio_handler(int irq, void *data) 271 { 272 struct snd_soc_jack_gpio *gpio = data; 273 struct device *dev = gpio->jack->card->dev; 274 275 trace_snd_soc_jack_irq(gpio->name); 276 277 if (device_may_wakeup(dev)) 278 pm_wakeup_event(dev, gpio->debounce_time + 50); 279 280 queue_delayed_work(system_power_efficient_wq, &gpio->work, 281 msecs_to_jiffies(gpio->debounce_time)); 282 283 return IRQ_HANDLED; 284 } 285 286 /* gpio work */ 287 static void gpio_work(struct work_struct *work) 288 { 289 struct snd_soc_jack_gpio *gpio; 290 291 gpio = container_of(work, struct snd_soc_jack_gpio, work.work); 292 snd_soc_jack_gpio_detect(gpio); 293 } 294 295 /** 296 * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack 297 * 298 * @jack: ASoC jack 299 * @count: number of pins 300 * @gpios: array of gpio pins 301 * 302 * This function will request gpio, set data direction and request irq 303 * for each gpio in the array. 304 */ 305 int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, 306 struct snd_soc_jack_gpio *gpios) 307 { 308 int i, ret; 309 310 for (i = 0; i < count; i++) { 311 if (!gpios[i].name) { 312 dev_err(jack->card->dev, 313 "ASoC: No name for gpio at index %d\n", i); 314 ret = -EINVAL; 315 goto undo; 316 } 317 318 if (gpios[i].gpiod_dev) { 319 /* GPIO descriptor */ 320 gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, 321 gpios[i].name, 322 gpios[i].idx, GPIOD_IN); 323 if (IS_ERR(gpios[i].desc)) { 324 ret = PTR_ERR(gpios[i].desc); 325 dev_err(gpios[i].gpiod_dev, 326 "ASoC: Cannot get gpio at index %d: %d", 327 i, ret); 328 goto undo; 329 } 330 } else { 331 /* legacy GPIO number */ 332 if (!gpio_is_valid(gpios[i].gpio)) { 333 dev_err(jack->card->dev, 334 "ASoC: Invalid gpio %d\n", 335 gpios[i].gpio); 336 ret = -EINVAL; 337 goto undo; 338 } 339 340 ret = gpio_request_one(gpios[i].gpio, GPIOF_IN, 341 gpios[i].name); 342 if (ret) 343 goto undo; 344 345 gpios[i].desc = gpio_to_desc(gpios[i].gpio); 346 } 347 348 INIT_DELAYED_WORK(&gpios[i].work, gpio_work); 349 gpios[i].jack = jack; 350 351 ret = request_any_context_irq(gpiod_to_irq(gpios[i].desc), 352 gpio_handler, 353 IRQF_TRIGGER_RISING | 354 IRQF_TRIGGER_FALLING, 355 gpios[i].name, 356 &gpios[i]); 357 if (ret < 0) 358 goto err; 359 360 if (gpios[i].wake) { 361 ret = irq_set_irq_wake(gpiod_to_irq(gpios[i].desc), 1); 362 if (ret != 0) 363 dev_err(jack->card->dev, 364 "ASoC: Failed to mark GPIO at index %d as wake source: %d\n", 365 i, ret); 366 } 367 368 /* Expose GPIO value over sysfs for diagnostic purposes */ 369 gpiod_export(gpios[i].desc, false); 370 371 /* Update initial jack status */ 372 schedule_delayed_work(&gpios[i].work, 373 msecs_to_jiffies(gpios[i].debounce_time)); 374 } 375 376 return 0; 377 378 err: 379 gpio_free(gpios[i].gpio); 380 undo: 381 snd_soc_jack_free_gpios(jack, i, gpios); 382 383 return ret; 384 } 385 EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios); 386 387 /** 388 * snd_soc_jack_add_gpiods - Associate GPIO descriptor pins with an ASoC jack 389 * 390 * @gpiod_dev: GPIO consumer device 391 * @jack: ASoC jack 392 * @count: number of pins 393 * @gpios: array of gpio pins 394 * 395 * This function will request gpio, set data direction and request irq 396 * for each gpio in the array. 397 */ 398 int snd_soc_jack_add_gpiods(struct device *gpiod_dev, 399 struct snd_soc_jack *jack, 400 int count, struct snd_soc_jack_gpio *gpios) 401 { 402 int i; 403 404 for (i = 0; i < count; i++) 405 gpios[i].gpiod_dev = gpiod_dev; 406 407 return snd_soc_jack_add_gpios(jack, count, gpios); 408 } 409 EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpiods); 410 411 /** 412 * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack 413 * 414 * @jack: ASoC jack 415 * @count: number of pins 416 * @gpios: array of gpio pins 417 * 418 * Release gpio and irq resources for gpio pins associated with an ASoC jack. 419 */ 420 void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, 421 struct snd_soc_jack_gpio *gpios) 422 { 423 int i; 424 425 for (i = 0; i < count; i++) { 426 gpiod_unexport(gpios[i].desc); 427 free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]); 428 cancel_delayed_work_sync(&gpios[i].work); 429 gpiod_put(gpios[i].desc); 430 gpios[i].jack = NULL; 431 } 432 } 433 EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios); 434 #endif /* CONFIG_GPIOLIB */ 435