cregit-Linux how code gets into the kernel

Release 4.7 drivers/mfd/pcf50633-adc.c

Directory: drivers/mfd
/* NXP PCF50633 ADC Driver
 *
 * (C) 2006-2008 by Openmoko, Inc.
 * Author: Balaji Rao <balajirrao@openmoko.org>
 * All rights reserved.
 *
 * Broken down from monstrous PCF50633 driver mainly by
 * Harald Welte, Andy Green and Werner Almesberger
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 *  NOTE: This driver does not yet support subtractive ADC mode, which means
 *  you can do only one measurement per read request.
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/completion.h>

#include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/adc.h>


struct pcf50633_adc_request {
	
int mux;
	
int avg;
	
void (*callback)(struct pcf50633 *, void *, int);
	
void *callback_param;
};


struct pcf50633_adc_sync_request {
	
int result;
	
struct completion completion;
};


#define PCF50633_MAX_ADC_FIFO_DEPTH 8


struct pcf50633_adc {
	
struct pcf50633 *pcf;

	/* Private stuff */
	
struct pcf50633_adc_request *queue[PCF50633_MAX_ADC_FIFO_DEPTH];
	
int queue_head;
	
int queue_tail;
	
struct mutex queue_mutex;
};


static inline struct pcf50633_adc *__to_adc(struct pcf50633 *pcf) { return platform_get_drvdata(pcf->adc_pdev); }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao22100.00%1100.00%
Total22100.00%1100.00%


static void adc_setup(struct pcf50633 *pcf, int channel, int avg) { channel &= PCF50633_ADCC1_ADCMUX_MASK; /* kill ratiometric, but enable ACCSW biasing */ pcf50633_reg_write(pcf, PCF50633_REG_ADCC2, 0x00); pcf50633_reg_write(pcf, PCF50633_REG_ADCC3, 0x01); /* start ADC conversion on selected channel */ pcf50633_reg_write(pcf, PCF50633_REG_ADCC1, channel | avg | PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT); }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao56100.00%1100.00%
Total56100.00%1100.00%


static void trigger_next_adc_job_if_any(struct pcf50633 *pcf) { struct pcf50633_adc *adc = __to_adc(pcf); int head; head = adc->queue_head; if (!adc->queue[head]) return; adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg); }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao64100.00%1100.00%
Total64100.00%1100.00%


static int adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req) { struct pcf50633_adc *adc = __to_adc(pcf); int head, tail; mutex_lock(&adc->queue_mutex); head = adc->queue_head; tail = adc->queue_tail; if (adc->queue[tail]) { mutex_unlock(&adc->queue_mutex); dev_err(pcf->dev, "ADC queue is full, dropping request\n"); return -EBUSY; } adc->queue[tail] = req; if (head == tail) trigger_next_adc_job_if_any(pcf); adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1); mutex_unlock(&adc->queue_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao11084.62%150.00%
paul fertserpaul fertser2015.38%150.00%
Total130100.00%2100.00%


static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) { struct pcf50633_adc_sync_request *req = param; req->result = result; complete(&req->completion); }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao3897.44%150.00%
lars-peter clausenlars-peter clausen12.56%150.00%
Total39100.00%2100.00%


int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) { struct pcf50633_adc_sync_request req; int ret; init_completion(&req.completion); ret = pcf50633_adc_async_read(pcf, mux, avg, pcf50633_adc_sync_read_callback, &req); if (ret) return ret; wait_for_completion(&req.completion); return req.result; }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao4364.18%133.33%
lars-peter clausenlars-peter clausen1623.88%133.33%
paul fertserpaul fertser811.94%133.33%
Total67100.00%3100.00%

EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);
int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg, void (*callback)(struct pcf50633 *, void *, int), void *callback_param) { struct pcf50633_adc_request *req; /* req is freed when the result is ready, in interrupt handler */ req = kmalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; req->mux = mux; req->avg = avg; req->callback = callback; req->callback_param = callback_param; return adc_enqueue_request(pcf, req); }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao9598.96%150.00%
paul fertserpaul fertser11.04%150.00%
Total96100.00%2100.00%

EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
static int adc_result(struct pcf50633 *pcf) { u8 adcs1, adcs3; u16 result; adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1); adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3); result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK); dev_dbg(pcf->dev, "adc result = %d\n", result); return result; }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao65100.00%1100.00%
Total65100.00%1100.00%


static void pcf50633_adc_irq(int irq, void *data) { struct pcf50633_adc *adc = data; struct pcf50633 *pcf = adc->pcf; struct pcf50633_adc_request *req; int head, res; mutex_lock(&adc->queue_mutex); head = adc->queue_head; req = adc->queue[head]; if (WARN_ON(!req)) { dev_err(pcf->dev, "pcf50633-adc irq: ADC queue empty!\n"); mutex_unlock(&adc->queue_mutex); return; } adc->queue[head] = NULL; adc->queue_head = (head + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1); res = adc_result(pcf); trigger_next_adc_job_if_any(pcf); mutex_unlock(&adc->queue_mutex); req->callback(pcf, req->callback_param, res); kfree(req); }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao13890.20%150.00%
paul fertserpaul fertser159.80%150.00%
Total153100.00%2100.00%


static int pcf50633_adc_probe(struct platform_device *pdev) { struct pcf50633_adc *adc; adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL); if (!adc) return -ENOMEM; adc->pcf = dev_to_pcf50633(pdev->dev.parent); platform_set_drvdata(pdev, adc); pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY, pcf50633_adc_irq, adc); mutex_init(&adc->queue_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao7383.91%133.33%
lars-peter clausenlars-peter clausen89.20%133.33%
jingoo hanjingoo han66.90%133.33%
Total87100.00%3100.00%


static int pcf50633_adc_remove(struct platform_device *pdev) { struct pcf50633_adc *adc = platform_get_drvdata(pdev); int i, head; pcf50633_free_irq(adc->pcf, PCF50633_IRQ_ADCRDY); mutex_lock(&adc->queue_mutex); head = adc->queue_head; if (WARN_ON(adc->queue[head])) dev_err(adc->pcf->dev, "adc driver removed with request pending\n"); for (i = 0; i < PCF50633_MAX_ADC_FIFO_DEPTH; i++) kfree(adc->queue[i]); mutex_unlock(&adc->queue_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao106100.00%1100.00%
Total106100.00%1100.00%

static struct platform_driver pcf50633_adc_driver = { .driver = { .name = "pcf50633-adc", }, .probe = pcf50633_adc_probe, .remove = pcf50633_adc_remove, }; module_platform_driver(pcf50633_adc_driver); MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); MODULE_DESCRIPTION("PCF50633 adc driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:pcf50633-adc");

Overall Contributors

PersonTokensPropCommitsCommitProp
balaji raobalaji rao96191.70%114.29%
paul fertserpaul fertser444.20%114.29%
lars-peter clausenlars-peter clausen333.15%228.57%
jingoo hanjingoo han60.57%114.29%
tejun heotejun heo30.29%114.29%
mark brownmark brown10.10%114.29%
Total1048100.00%7100.00%
Directory: drivers/mfd
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}