root/drivers/mfd/pcf50633-adc.c

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

DEFINITIONS

This source file includes following definitions.
  1. __to_adc
  2. adc_setup
  3. trigger_next_adc_job_if_any
  4. adc_enqueue_request
  5. pcf50633_adc_sync_read_callback
  6. pcf50633_adc_sync_read
  7. pcf50633_adc_async_read
  8. adc_result
  9. pcf50633_adc_irq
  10. pcf50633_adc_probe
  11. pcf50633_adc_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* NXP PCF50633 ADC Driver
   3  *
   4  * (C) 2006-2008 by Openmoko, Inc.
   5  * Author: Balaji Rao <balajirrao@openmoko.org>
   6  * All rights reserved.
   7  *
   8  * Broken down from monstrous PCF50633 driver mainly by
   9  * Harald Welte, Andy Green and Werner Almesberger
  10  *
  11  *  NOTE: This driver does not yet support subtractive ADC mode, which means
  12  *  you can do only one measurement per read request.
  13  */
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/slab.h>
  17 #include <linux/module.h>
  18 #include <linux/device.h>
  19 #include <linux/platform_device.h>
  20 #include <linux/completion.h>
  21 
  22 #include <linux/mfd/pcf50633/core.h>
  23 #include <linux/mfd/pcf50633/adc.h>
  24 
  25 struct pcf50633_adc_request {
  26         int mux;
  27         int avg;
  28         void (*callback)(struct pcf50633 *, void *, int);
  29         void *callback_param;
  30 };
  31 
  32 struct pcf50633_adc_sync_request {
  33         int result;
  34         struct completion completion;
  35 };
  36 
  37 #define PCF50633_MAX_ADC_FIFO_DEPTH 8
  38 
  39 struct pcf50633_adc {
  40         struct pcf50633 *pcf;
  41 
  42         /* Private stuff */
  43         struct pcf50633_adc_request *queue[PCF50633_MAX_ADC_FIFO_DEPTH];
  44         int queue_head;
  45         int queue_tail;
  46         struct mutex queue_mutex;
  47 };
  48 
  49 static inline struct pcf50633_adc *__to_adc(struct pcf50633 *pcf)
  50 {
  51         return platform_get_drvdata(pcf->adc_pdev);
  52 }
  53 
  54 static void adc_setup(struct pcf50633 *pcf, int channel, int avg)
  55 {
  56         channel &= PCF50633_ADCC1_ADCMUX_MASK;
  57 
  58         /* kill ratiometric, but enable ACCSW biasing */
  59         pcf50633_reg_write(pcf, PCF50633_REG_ADCC2, 0x00);
  60         pcf50633_reg_write(pcf, PCF50633_REG_ADCC3, 0x01);
  61 
  62         /* start ADC conversion on selected channel */
  63         pcf50633_reg_write(pcf, PCF50633_REG_ADCC1, channel | avg |
  64                     PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT);
  65 }
  66 
  67 static void trigger_next_adc_job_if_any(struct pcf50633 *pcf)
  68 {
  69         struct pcf50633_adc *adc = __to_adc(pcf);
  70         int head;
  71 
  72         head = adc->queue_head;
  73 
  74         if (!adc->queue[head])
  75                 return;
  76 
  77         adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg);
  78 }
  79 
  80 static int
  81 adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req)
  82 {
  83         struct pcf50633_adc *adc = __to_adc(pcf);
  84         int head, tail;
  85 
  86         mutex_lock(&adc->queue_mutex);
  87 
  88         head = adc->queue_head;
  89         tail = adc->queue_tail;
  90 
  91         if (adc->queue[tail]) {
  92                 mutex_unlock(&adc->queue_mutex);
  93                 dev_err(pcf->dev, "ADC queue is full, dropping request\n");
  94                 return -EBUSY;
  95         }
  96 
  97         adc->queue[tail] = req;
  98         if (head == tail)
  99                 trigger_next_adc_job_if_any(pcf);
 100         adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
 101 
 102         mutex_unlock(&adc->queue_mutex);
 103 
 104         return 0;
 105 }
 106 
 107 static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param,
 108         int result)
 109 {
 110         struct pcf50633_adc_sync_request *req = param;
 111 
 112         req->result = result;
 113         complete(&req->completion);
 114 }
 115 
 116 int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
 117 {
 118         struct pcf50633_adc_sync_request req;
 119         int ret;
 120 
 121         init_completion(&req.completion);
 122 
 123         ret = pcf50633_adc_async_read(pcf, mux, avg,
 124                 pcf50633_adc_sync_read_callback, &req);
 125         if (ret)
 126                 return ret;
 127 
 128         wait_for_completion(&req.completion);
 129 
 130         return req.result;
 131 }
 132 EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);
 133 
 134 int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
 135                              void (*callback)(struct pcf50633 *, void *, int),
 136                              void *callback_param)
 137 {
 138         struct pcf50633_adc_request *req;
 139 
 140         /* req is freed when the result is ready, in interrupt handler */
 141         req = kmalloc(sizeof(*req), GFP_KERNEL);
 142         if (!req)
 143                 return -ENOMEM;
 144 
 145         req->mux = mux;
 146         req->avg = avg;
 147         req->callback = callback;
 148         req->callback_param = callback_param;
 149 
 150         return adc_enqueue_request(pcf, req);
 151 }
 152 EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
 153 
 154 static int adc_result(struct pcf50633 *pcf)
 155 {
 156         u8 adcs1, adcs3;
 157         u16 result;
 158 
 159         adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1);
 160         adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3);
 161         result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK);
 162 
 163         dev_dbg(pcf->dev, "adc result = %d\n", result);
 164 
 165         return result;
 166 }
 167 
 168 static void pcf50633_adc_irq(int irq, void *data)
 169 {
 170         struct pcf50633_adc *adc = data;
 171         struct pcf50633 *pcf = adc->pcf;
 172         struct pcf50633_adc_request *req;
 173         int head, res;
 174 
 175         mutex_lock(&adc->queue_mutex);
 176         head = adc->queue_head;
 177 
 178         req = adc->queue[head];
 179         if (WARN_ON(!req)) {
 180                 dev_err(pcf->dev, "pcf50633-adc irq: ADC queue empty!\n");
 181                 mutex_unlock(&adc->queue_mutex);
 182                 return;
 183         }
 184         adc->queue[head] = NULL;
 185         adc->queue_head = (head + 1) &
 186                                       (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
 187 
 188         res = adc_result(pcf);
 189         trigger_next_adc_job_if_any(pcf);
 190 
 191         mutex_unlock(&adc->queue_mutex);
 192 
 193         req->callback(pcf, req->callback_param, res);
 194         kfree(req);
 195 }
 196 
 197 static int pcf50633_adc_probe(struct platform_device *pdev)
 198 {
 199         struct pcf50633_adc *adc;
 200 
 201         adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL);
 202         if (!adc)
 203                 return -ENOMEM;
 204 
 205         adc->pcf = dev_to_pcf50633(pdev->dev.parent);
 206         platform_set_drvdata(pdev, adc);
 207 
 208         pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY,
 209                                         pcf50633_adc_irq, adc);
 210 
 211         mutex_init(&adc->queue_mutex);
 212 
 213         return 0;
 214 }
 215 
 216 static int pcf50633_adc_remove(struct platform_device *pdev)
 217 {
 218         struct pcf50633_adc *adc = platform_get_drvdata(pdev);
 219         int i, head;
 220 
 221         pcf50633_free_irq(adc->pcf, PCF50633_IRQ_ADCRDY);
 222 
 223         mutex_lock(&adc->queue_mutex);
 224         head = adc->queue_head;
 225 
 226         if (WARN_ON(adc->queue[head]))
 227                 dev_err(adc->pcf->dev,
 228                         "adc driver removed with request pending\n");
 229 
 230         for (i = 0; i < PCF50633_MAX_ADC_FIFO_DEPTH; i++)
 231                 kfree(adc->queue[i]);
 232 
 233         mutex_unlock(&adc->queue_mutex);
 234 
 235         return 0;
 236 }
 237 
 238 static struct platform_driver pcf50633_adc_driver = {
 239         .driver = {
 240                 .name = "pcf50633-adc",
 241         },
 242         .probe = pcf50633_adc_probe,
 243         .remove = pcf50633_adc_remove,
 244 };
 245 
 246 module_platform_driver(pcf50633_adc_driver);
 247 
 248 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 249 MODULE_DESCRIPTION("PCF50633 adc driver");
 250 MODULE_LICENSE("GPL");
 251 MODULE_ALIAS("platform:pcf50633-adc");
 252 

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