root/sound/soc/soc-jack.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_soc_card_jack_new
  2. snd_soc_jack_report
  3. snd_soc_jack_add_zones
  4. snd_soc_jack_get_type
  5. snd_soc_jack_add_pins
  6. snd_soc_jack_notifier_register
  7. snd_soc_jack_notifier_unregister
  8. snd_soc_jack_gpio_detect
  9. gpio_handler
  10. gpio_work
  11. snd_soc_jack_pm_notifier
  12. jack_free_gpios
  13. jack_devres_free_gpios
  14. snd_soc_jack_add_gpios
  15. snd_soc_jack_add_gpiods
  16. snd_soc_jack_free_gpios

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

/* [<][>][^][v][top][bottom][index][help] */