Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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