root/sound/aoa/core/gpio-pmf.c

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

DEFINITIONS

This source file includes following definitions.
  1. pmf_gpio_set_hw_reset
  2. pmf_gpio_all_amps_off
  3. pmf_gpio_all_amps_restore
  4. pmf_handle_notify
  5. pmf_gpio_init
  6. pmf_gpio_exit
  7. pmf_handle_notify_irq
  8. pmf_set_notify
  9. pmf_get_detect

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Apple Onboard Audio pmf GPIOs
   4  *
   5  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
   6  */
   7 
   8 #include <linux/slab.h>
   9 #include <asm/pmac_feature.h>
  10 #include <asm/pmac_pfunc.h>
  11 #include "../aoa.h"
  12 
  13 #define PMF_GPIO(name, bit)                                     \
  14 static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\
  15 {                                                               \
  16         struct pmf_args args = { .count = 1, .u[0].v = !on };   \
  17         int rc;                                                 \
  18                                                         \
  19         if (unlikely(!rt)) return;                              \
  20         rc = pmf_call_function(rt->node, #name "-mute", &args); \
  21         if (rc && rc != -ENODEV)                                \
  22                 printk(KERN_WARNING "pmf_gpio_set_" #name       \
  23                 " failed, rc: %d\n", rc);                       \
  24         rt->implementation_private &= ~(1<<bit);                \
  25         rt->implementation_private |= (!!on << bit);            \
  26 }                                                               \
  27 static int pmf_gpio_get_##name(struct gpio_runtime *rt)         \
  28 {                                                               \
  29         if (unlikely(!rt)) return 0;                            \
  30         return (rt->implementation_private>>bit)&1;             \
  31 }
  32 
  33 PMF_GPIO(headphone, 0);
  34 PMF_GPIO(amp, 1);
  35 PMF_GPIO(lineout, 2);
  36 
  37 static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
  38 {
  39         struct pmf_args args = { .count = 1, .u[0].v = !!on };
  40         int rc;
  41 
  42         if (unlikely(!rt)) return;
  43         rc = pmf_call_function(rt->node, "hw-reset", &args);
  44         if (rc)
  45                 printk(KERN_WARNING "pmf_gpio_set_hw_reset"
  46                        " failed, rc: %d\n", rc);
  47 }
  48 
  49 static void pmf_gpio_all_amps_off(struct gpio_runtime *rt)
  50 {
  51         int saved;
  52 
  53         if (unlikely(!rt)) return;
  54         saved = rt->implementation_private;
  55         pmf_gpio_set_headphone(rt, 0);
  56         pmf_gpio_set_amp(rt, 0);
  57         pmf_gpio_set_lineout(rt, 0);
  58         rt->implementation_private = saved;
  59 }
  60 
  61 static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt)
  62 {
  63         int s;
  64 
  65         if (unlikely(!rt)) return;
  66         s = rt->implementation_private;
  67         pmf_gpio_set_headphone(rt, (s>>0)&1);
  68         pmf_gpio_set_amp(rt, (s>>1)&1);
  69         pmf_gpio_set_lineout(rt, (s>>2)&1);
  70 }
  71 
  72 static void pmf_handle_notify(struct work_struct *work)
  73 {
  74         struct gpio_notification *notif =
  75                 container_of(work, struct gpio_notification, work.work);
  76 
  77         mutex_lock(&notif->mutex);
  78         if (notif->notify)
  79                 notif->notify(notif->data);
  80         mutex_unlock(&notif->mutex);
  81 }
  82 
  83 static void pmf_gpio_init(struct gpio_runtime *rt)
  84 {
  85         pmf_gpio_all_amps_off(rt);
  86         rt->implementation_private = 0;
  87         INIT_DELAYED_WORK(&rt->headphone_notify.work, pmf_handle_notify);
  88         INIT_DELAYED_WORK(&rt->line_in_notify.work, pmf_handle_notify);
  89         INIT_DELAYED_WORK(&rt->line_out_notify.work, pmf_handle_notify);
  90         mutex_init(&rt->headphone_notify.mutex);
  91         mutex_init(&rt->line_in_notify.mutex);
  92         mutex_init(&rt->line_out_notify.mutex);
  93 }
  94 
  95 static void pmf_gpio_exit(struct gpio_runtime *rt)
  96 {
  97         pmf_gpio_all_amps_off(rt);
  98         rt->implementation_private = 0;
  99 
 100         if (rt->headphone_notify.gpio_private)
 101                 pmf_unregister_irq_client(rt->headphone_notify.gpio_private);
 102         if (rt->line_in_notify.gpio_private)
 103                 pmf_unregister_irq_client(rt->line_in_notify.gpio_private);
 104         if (rt->line_out_notify.gpio_private)
 105                 pmf_unregister_irq_client(rt->line_out_notify.gpio_private);
 106 
 107         /* make sure no work is pending before freeing
 108          * all things */
 109         cancel_delayed_work_sync(&rt->headphone_notify.work);
 110         cancel_delayed_work_sync(&rt->line_in_notify.work);
 111         cancel_delayed_work_sync(&rt->line_out_notify.work);
 112 
 113         mutex_destroy(&rt->headphone_notify.mutex);
 114         mutex_destroy(&rt->line_in_notify.mutex);
 115         mutex_destroy(&rt->line_out_notify.mutex);
 116 
 117         kfree(rt->headphone_notify.gpio_private);
 118         kfree(rt->line_in_notify.gpio_private);
 119         kfree(rt->line_out_notify.gpio_private);
 120 }
 121 
 122 static void pmf_handle_notify_irq(void *data)
 123 {
 124         struct gpio_notification *notif = data;
 125 
 126         schedule_delayed_work(&notif->work, 0);
 127 }
 128 
 129 static int pmf_set_notify(struct gpio_runtime *rt,
 130                           enum notify_type type,
 131                           notify_func_t notify,
 132                           void *data)
 133 {
 134         struct gpio_notification *notif;
 135         notify_func_t old;
 136         struct pmf_irq_client *irq_client;
 137         char *name;
 138         int err = -EBUSY;
 139 
 140         switch (type) {
 141         case AOA_NOTIFY_HEADPHONE:
 142                 notif = &rt->headphone_notify;
 143                 name = "headphone-detect";
 144                 break;
 145         case AOA_NOTIFY_LINE_IN:
 146                 notif = &rt->line_in_notify;
 147                 name = "linein-detect";
 148                 break;
 149         case AOA_NOTIFY_LINE_OUT:
 150                 notif = &rt->line_out_notify;
 151                 name = "lineout-detect";
 152                 break;
 153         default:
 154                 return -EINVAL;
 155         }
 156 
 157         mutex_lock(&notif->mutex);
 158 
 159         old = notif->notify;
 160 
 161         if (!old && !notify) {
 162                 err = 0;
 163                 goto out_unlock;
 164         }
 165 
 166         if (old && notify) {
 167                 if (old == notify && notif->data == data)
 168                         err = 0;
 169                 goto out_unlock;
 170         }
 171 
 172         if (old && !notify) {
 173                 irq_client = notif->gpio_private;
 174                 pmf_unregister_irq_client(irq_client);
 175                 kfree(irq_client);
 176                 notif->gpio_private = NULL;
 177         }
 178         if (!old && notify) {
 179                 irq_client = kzalloc(sizeof(struct pmf_irq_client),
 180                                      GFP_KERNEL);
 181                 if (!irq_client) {
 182                         err = -ENOMEM;
 183                         goto out_unlock;
 184                 }
 185                 irq_client->data = notif;
 186                 irq_client->handler = pmf_handle_notify_irq;
 187                 irq_client->owner = THIS_MODULE;
 188                 err = pmf_register_irq_client(rt->node,
 189                                               name,
 190                                               irq_client);
 191                 if (err) {
 192                         printk(KERN_ERR "snd-aoa: gpio layer failed to"
 193                                         " register %s irq (%d)\n", name, err);
 194                         kfree(irq_client);
 195                         goto out_unlock;
 196                 }
 197                 notif->gpio_private = irq_client;
 198         }
 199         notif->notify = notify;
 200         notif->data = data;
 201 
 202         err = 0;
 203  out_unlock:
 204         mutex_unlock(&notif->mutex);
 205         return err;
 206 }
 207 
 208 static int pmf_get_detect(struct gpio_runtime *rt,
 209                           enum notify_type type)
 210 {
 211         char *name;
 212         int err = -EBUSY, ret;
 213         struct pmf_args args = { .count = 1, .u[0].p = &ret };
 214 
 215         switch (type) {
 216         case AOA_NOTIFY_HEADPHONE:
 217                 name = "headphone-detect";
 218                 break;
 219         case AOA_NOTIFY_LINE_IN:
 220                 name = "linein-detect";
 221                 break;
 222         case AOA_NOTIFY_LINE_OUT:
 223                 name = "lineout-detect";
 224                 break;
 225         default:
 226                 return -EINVAL;
 227         }
 228 
 229         err = pmf_call_function(rt->node, name, &args);
 230         if (err)
 231                 return err;
 232         return ret;
 233 }
 234 
 235 static struct gpio_methods methods = {
 236         .init                   = pmf_gpio_init,
 237         .exit                   = pmf_gpio_exit,
 238         .all_amps_off           = pmf_gpio_all_amps_off,
 239         .all_amps_restore       = pmf_gpio_all_amps_restore,
 240         .set_headphone          = pmf_gpio_set_headphone,
 241         .set_speakers           = pmf_gpio_set_amp,
 242         .set_lineout            = pmf_gpio_set_lineout,
 243         .set_hw_reset           = pmf_gpio_set_hw_reset,
 244         .get_headphone          = pmf_gpio_get_headphone,
 245         .get_speakers           = pmf_gpio_get_amp,
 246         .get_lineout            = pmf_gpio_get_lineout,
 247         .set_notify             = pmf_set_notify,
 248         .get_detect             = pmf_get_detect,
 249 };
 250 
 251 struct gpio_methods *pmf_gpio_methods = &methods;
 252 EXPORT_SYMBOL_GPL(pmf_gpio_methods);

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