root/drivers/mfd/wm831x-auxadc.c

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

DEFINITIONS

This source file includes following definitions.
  1. wm831x_auxadc_read_irq
  2. wm831x_auxadc_irq
  3. wm831x_auxadc_read_polled
  4. wm831x_auxadc_read
  5. wm831x_auxadc_read_uv
  6. wm831x_auxadc_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * wm831x-auxadc.c  --  AUXADC for Wolfson WM831x PMICs
   4  *
   5  * Copyright 2009-2011 Wolfson Microelectronics PLC.
   6  *
   7  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/delay.h>
  13 #include <linux/mfd/core.h>
  14 #include <linux/slab.h>
  15 #include <linux/list.h>
  16 
  17 #include <linux/mfd/wm831x/core.h>
  18 #include <linux/mfd/wm831x/pdata.h>
  19 #include <linux/mfd/wm831x/irq.h>
  20 #include <linux/mfd/wm831x/auxadc.h>
  21 #include <linux/mfd/wm831x/otp.h>
  22 #include <linux/mfd/wm831x/regulator.h>
  23 
  24 struct wm831x_auxadc_req {
  25         struct list_head list;
  26         enum wm831x_auxadc input;
  27         int val;
  28         struct completion done;
  29 };
  30 
  31 static int wm831x_auxadc_read_irq(struct wm831x *wm831x,
  32                                   enum wm831x_auxadc input)
  33 {
  34         struct wm831x_auxadc_req *req;
  35         int ret;
  36         bool ena = false;
  37 
  38         req = kzalloc(sizeof(*req), GFP_KERNEL);
  39         if (!req)
  40                 return -ENOMEM;
  41 
  42         init_completion(&req->done);
  43         req->input = input;
  44         req->val = -ETIMEDOUT;
  45 
  46         mutex_lock(&wm831x->auxadc_lock);
  47 
  48         /* Enqueue the request */
  49         list_add(&req->list, &wm831x->auxadc_pending);
  50 
  51         ena = !wm831x->auxadc_active;
  52 
  53         if (ena) {
  54                 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
  55                                       WM831X_AUX_ENA, WM831X_AUX_ENA);
  56                 if (ret != 0) {
  57                         dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n",
  58                                 ret);
  59                         goto out;
  60                 }
  61         }
  62 
  63         /* Enable the conversion if not already running */
  64         if (!(wm831x->auxadc_active & (1 << input))) {
  65                 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE,
  66                                       1 << input, 1 << input);
  67                 if (ret != 0) {
  68                         dev_err(wm831x->dev,
  69                                 "Failed to set AUXADC source: %d\n", ret);
  70                         goto out;
  71                 }
  72 
  73                 wm831x->auxadc_active |= 1 << input;
  74         }
  75 
  76         /* We convert at the fastest rate possible */
  77         if (ena) {
  78                 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
  79                                       WM831X_AUX_CVT_ENA |
  80                                       WM831X_AUX_RATE_MASK,
  81                                       WM831X_AUX_CVT_ENA |
  82                                       WM831X_AUX_RATE_MASK);
  83                 if (ret != 0) {
  84                         dev_err(wm831x->dev, "Failed to start AUXADC: %d\n",
  85                                 ret);
  86                         goto out;
  87                 }
  88         }
  89 
  90         mutex_unlock(&wm831x->auxadc_lock);
  91 
  92         /* Wait for an interrupt */
  93         wait_for_completion_timeout(&req->done, msecs_to_jiffies(500));
  94 
  95         mutex_lock(&wm831x->auxadc_lock);
  96 
  97         list_del(&req->list);
  98         ret = req->val;
  99 
 100 out:
 101         mutex_unlock(&wm831x->auxadc_lock);
 102 
 103         kfree(req);
 104 
 105         return ret;
 106 }
 107 
 108 static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
 109 {
 110         struct wm831x *wm831x = irq_data;
 111         struct wm831x_auxadc_req *req;
 112         int ret, input, val;
 113 
 114         ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
 115         if (ret < 0) {
 116                 dev_err(wm831x->dev,
 117                         "Failed to read AUXADC data: %d\n", ret);
 118                 return IRQ_NONE;
 119         }
 120 
 121         input = ((ret & WM831X_AUX_DATA_SRC_MASK)
 122                  >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
 123 
 124         if (input == 14)
 125                 input = WM831X_AUX_CAL;
 126 
 127         val = ret & WM831X_AUX_DATA_MASK;
 128 
 129         mutex_lock(&wm831x->auxadc_lock);
 130 
 131         /* Disable this conversion, we're about to complete all users */
 132         wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE,
 133                         1 << input, 0);
 134         wm831x->auxadc_active &= ~(1 << input);
 135 
 136         /* Turn off the entire convertor if idle */
 137         if (!wm831x->auxadc_active)
 138                 wm831x_reg_write(wm831x, WM831X_AUXADC_CONTROL, 0);
 139 
 140         /* Wake up any threads waiting for this request */
 141         list_for_each_entry(req, &wm831x->auxadc_pending, list) {
 142                 if (req->input == input) {
 143                         req->val = val;
 144                         complete(&req->done);
 145                 }
 146         }
 147 
 148         mutex_unlock(&wm831x->auxadc_lock);
 149 
 150         return IRQ_HANDLED;
 151 }
 152 
 153 static int wm831x_auxadc_read_polled(struct wm831x *wm831x,
 154                                      enum wm831x_auxadc input)
 155 {
 156         int ret, src, timeout;
 157 
 158         mutex_lock(&wm831x->auxadc_lock);
 159 
 160         ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
 161                               WM831X_AUX_ENA, WM831X_AUX_ENA);
 162         if (ret < 0) {
 163                 dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
 164                 goto out;
 165         }
 166 
 167         /* We force a single source at present */
 168         src = input;
 169         ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
 170                                1 << src);
 171         if (ret < 0) {
 172                 dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
 173                 goto out;
 174         }
 175 
 176         ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
 177                               WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
 178         if (ret < 0) {
 179                 dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
 180                 goto disable;
 181         }
 182 
 183         /* If we're not using interrupts then poll the
 184          * interrupt status register */
 185         timeout = 5;
 186         while (timeout) {
 187                 msleep(1);
 188 
 189                 ret = wm831x_reg_read(wm831x,
 190                                       WM831X_INTERRUPT_STATUS_1);
 191                 if (ret < 0) {
 192                         dev_err(wm831x->dev,
 193                                 "ISR 1 read failed: %d\n", ret);
 194                         goto disable;
 195                 }
 196 
 197                 /* Did it complete? */
 198                 if (ret & WM831X_AUXADC_DATA_EINT) {
 199                         wm831x_reg_write(wm831x,
 200                                          WM831X_INTERRUPT_STATUS_1,
 201                                          WM831X_AUXADC_DATA_EINT);
 202                         break;
 203                 } else {
 204                         dev_err(wm831x->dev,
 205                                 "AUXADC conversion timeout\n");
 206                         ret = -EBUSY;
 207                         goto disable;
 208                 }
 209         }
 210 
 211         ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
 212         if (ret < 0) {
 213                 dev_err(wm831x->dev,
 214                         "Failed to read AUXADC data: %d\n", ret);
 215                 goto disable;
 216         }
 217 
 218         src = ((ret & WM831X_AUX_DATA_SRC_MASK)
 219                >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
 220 
 221         if (src == 14)
 222                 src = WM831X_AUX_CAL;
 223 
 224         if (src != input) {
 225                 dev_err(wm831x->dev, "Data from source %d not %d\n",
 226                         src, input);
 227                 ret = -EINVAL;
 228         } else {
 229                 ret &= WM831X_AUX_DATA_MASK;
 230         }
 231 
 232 disable:
 233         wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
 234 out:
 235         mutex_unlock(&wm831x->auxadc_lock);
 236         return ret;
 237 }
 238 
 239 /**
 240  * wm831x_auxadc_read: Read a value from the WM831x AUXADC
 241  *
 242  * @wm831x: Device to read from.
 243  * @input: AUXADC input to read.
 244  */
 245 int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
 246 {
 247         return wm831x->auxadc_read(wm831x, input);
 248 }
 249 EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
 250 
 251 /**
 252  * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
 253  *
 254  * @wm831x: Device to read from.
 255  * @input: AUXADC input to read.
 256  */
 257 int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
 258 {
 259         int ret;
 260 
 261         ret = wm831x_auxadc_read(wm831x, input);
 262         if (ret < 0)
 263                 return ret;
 264 
 265         ret *= 1465;
 266 
 267         return ret;
 268 }
 269 EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
 270 
 271 void wm831x_auxadc_init(struct wm831x *wm831x)
 272 {
 273         int ret;
 274 
 275         mutex_init(&wm831x->auxadc_lock);
 276         INIT_LIST_HEAD(&wm831x->auxadc_pending);
 277 
 278         if (wm831x->irq) {
 279                 wm831x->auxadc_read = wm831x_auxadc_read_irq;
 280 
 281                 ret = request_threaded_irq(wm831x_irq(wm831x,
 282                                                       WM831X_IRQ_AUXADC_DATA),
 283                                            NULL, wm831x_auxadc_irq,
 284                                            IRQF_ONESHOT,
 285                                            "auxadc", wm831x);
 286                 if (ret < 0) {
 287                         dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
 288                                 ret);
 289                         wm831x->auxadc_read = NULL;
 290                 }
 291         }
 292 
 293         if (!wm831x->auxadc_read)
 294                 wm831x->auxadc_read = wm831x_auxadc_read_polled;
 295 }

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