wm831x-auxadc.c (6589B)
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 24struct wm831x_auxadc_req { 25 struct list_head list; 26 enum wm831x_auxadc input; 27 int val; 28 struct completion done; 29}; 30 31static 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 ret = req->val; 97 98out: 99 list_del(&req->list); 100 mutex_unlock(&wm831x->auxadc_lock); 101 102 kfree(req); 103 104 return ret; 105} 106 107static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) 108{ 109 struct wm831x *wm831x = irq_data; 110 struct wm831x_auxadc_req *req; 111 int ret, input, val; 112 113 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); 114 if (ret < 0) { 115 dev_err(wm831x->dev, 116 "Failed to read AUXADC data: %d\n", ret); 117 return IRQ_NONE; 118 } 119 120 input = ((ret & WM831X_AUX_DATA_SRC_MASK) 121 >> WM831X_AUX_DATA_SRC_SHIFT) - 1; 122 123 if (input == 14) 124 input = WM831X_AUX_CAL; 125 126 val = ret & WM831X_AUX_DATA_MASK; 127 128 mutex_lock(&wm831x->auxadc_lock); 129 130 /* Disable this conversion, we're about to complete all users */ 131 wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE, 132 1 << input, 0); 133 wm831x->auxadc_active &= ~(1 << input); 134 135 /* Turn off the entire convertor if idle */ 136 if (!wm831x->auxadc_active) 137 wm831x_reg_write(wm831x, WM831X_AUXADC_CONTROL, 0); 138 139 /* Wake up any threads waiting for this request */ 140 list_for_each_entry(req, &wm831x->auxadc_pending, list) { 141 if (req->input == input) { 142 req->val = val; 143 complete(&req->done); 144 } 145 } 146 147 mutex_unlock(&wm831x->auxadc_lock); 148 149 return IRQ_HANDLED; 150} 151 152static int wm831x_auxadc_read_polled(struct wm831x *wm831x, 153 enum wm831x_auxadc input) 154{ 155 int ret, src, timeout; 156 157 mutex_lock(&wm831x->auxadc_lock); 158 159 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, 160 WM831X_AUX_ENA, WM831X_AUX_ENA); 161 if (ret < 0) { 162 dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); 163 goto out; 164 } 165 166 /* We force a single source at present */ 167 src = input; 168 ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, 169 1 << src); 170 if (ret < 0) { 171 dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); 172 goto out; 173 } 174 175 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, 176 WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); 177 if (ret < 0) { 178 dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); 179 goto disable; 180 } 181 182 /* If we're not using interrupts then poll the 183 * interrupt status register */ 184 timeout = 5; 185 while (timeout) { 186 msleep(1); 187 188 ret = wm831x_reg_read(wm831x, 189 WM831X_INTERRUPT_STATUS_1); 190 if (ret < 0) { 191 dev_err(wm831x->dev, 192 "ISR 1 read failed: %d\n", ret); 193 goto disable; 194 } 195 196 /* Did it complete? */ 197 if (ret & WM831X_AUXADC_DATA_EINT) { 198 wm831x_reg_write(wm831x, 199 WM831X_INTERRUPT_STATUS_1, 200 WM831X_AUXADC_DATA_EINT); 201 break; 202 } else { 203 dev_err(wm831x->dev, 204 "AUXADC conversion timeout\n"); 205 ret = -EBUSY; 206 goto disable; 207 } 208 } 209 210 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); 211 if (ret < 0) { 212 dev_err(wm831x->dev, 213 "Failed to read AUXADC data: %d\n", ret); 214 goto disable; 215 } 216 217 src = ((ret & WM831X_AUX_DATA_SRC_MASK) 218 >> WM831X_AUX_DATA_SRC_SHIFT) - 1; 219 220 if (src == 14) 221 src = WM831X_AUX_CAL; 222 223 if (src != input) { 224 dev_err(wm831x->dev, "Data from source %d not %d\n", 225 src, input); 226 ret = -EINVAL; 227 } else { 228 ret &= WM831X_AUX_DATA_MASK; 229 } 230 231disable: 232 wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); 233out: 234 mutex_unlock(&wm831x->auxadc_lock); 235 return ret; 236} 237 238/** 239 * wm831x_auxadc_read: Read a value from the WM831x AUXADC 240 * 241 * @wm831x: Device to read from. 242 * @input: AUXADC input to read. 243 */ 244int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) 245{ 246 return wm831x->auxadc_read(wm831x, input); 247} 248EXPORT_SYMBOL_GPL(wm831x_auxadc_read); 249 250/** 251 * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC 252 * 253 * @wm831x: Device to read from. 254 * @input: AUXADC input to read. 255 */ 256int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) 257{ 258 int ret; 259 260 ret = wm831x_auxadc_read(wm831x, input); 261 if (ret < 0) 262 return ret; 263 264 ret *= 1465; 265 266 return ret; 267} 268EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); 269 270void wm831x_auxadc_init(struct wm831x *wm831x) 271{ 272 int ret; 273 274 mutex_init(&wm831x->auxadc_lock); 275 INIT_LIST_HEAD(&wm831x->auxadc_pending); 276 277 if (wm831x->irq) { 278 wm831x->auxadc_read = wm831x_auxadc_read_irq; 279 280 ret = request_threaded_irq(wm831x_irq(wm831x, 281 WM831X_IRQ_AUXADC_DATA), 282 NULL, wm831x_auxadc_irq, 283 IRQF_ONESHOT, 284 "auxadc", wm831x); 285 if (ret < 0) { 286 dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", 287 ret); 288 wm831x->auxadc_read = NULL; 289 } 290 } 291 292 if (!wm831x->auxadc_read) 293 wm831x->auxadc_read = wm831x_auxadc_read_polled; 294}