add adc driver(path: drivers/adc)

This commit is contained in:
kfx 2010-11-12 16:34:40 +08:00
parent 1cd9d57991
commit e94c69a05c
16 changed files with 892 additions and 2 deletions

View File

@ -561,7 +561,9 @@ static struct platform_device *devices[] __initdata = {
&rk29xx_device_spi0m,
&rk29xx_device_spi1m,
#endif
#ifdef CONFIG_ADC_RK29
&rk29_device_adc,
#endif
#ifdef CONFIG_I2C0_RK29
&rk29_device_i2c0,
#endif

View File

@ -21,6 +21,29 @@
#include <mach/rk29_iomap.h>
#include <mach/rk29-dma-pl330.h>
#include "devices.h"
#ifdef CONFIG_ADC_RK29
static struct resource rk29_adc_resource[] = {
{
.start = IRQ_SARADC,
.end = IRQ_SARADC,
.flags = IORESOURCE_IRQ,
},
{
.start = RK29_ADC_PHYS,
.end = RK29_ADC_PHYS + RK29_ADC_SIZE - 1,
.flags = IORESOURCE_MEM,
},
};
struct platform_device rk29_device_adc = {
.name = "rk29-adc",
.id = -1,
.num_resources = ARRAY_SIZE(rk29_adc_resource),
.resource = rk29_adc_resource,
};
#endif
#ifdef CONFIG_I2C_RK29
static struct resource resources_i2c0[] = {
{

View File

@ -39,5 +39,6 @@ extern struct rk29_sdmmc_platform_data default_sdmmc0_data;
extern struct rk29_sdmmc_platform_data default_sdmmc1_data;
extern struct platform_device rk29_device_sdmmc0;
extern struct platform_device rk29_device_sdmmc1;
extern struct platform_device rk29_device_adc;
#endif

View File

@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
source "drivers/adc/Kconfig"
source "drivers/fpga/Kconfig"
source "drivers/headset_observe/Kconfig"

View File

@ -74,6 +74,7 @@ obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-y += i2c/ media/
obj-y += adc/
obj-$(CONFIG_PPS) += pps/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/

12
drivers/adc/Kconfig Normal file
View File

@ -0,0 +1,12 @@
#
# ADC subsystem configuration
#
menuconfig ADC
bool "ADC support"
default y
if ADC
source drivers/adc/plat/Kconfig
endif # ADC

7
drivers/adc/Makefile Normal file
View File

@ -0,0 +1,7 @@
#
# Makefile for the adc core.
#
obj-$(CONFIG_ADC) += core.o
obj-y += plat/

211
drivers/adc/core.c Executable file
View File

@ -0,0 +1,211 @@
/* drivers/adc/core.c
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/adc.h>
static struct adc_host *g_adc = NULL;
struct adc_host *adc_alloc_host(int extra, struct device *dev)
{
struct adc_host *adc;
adc = kzalloc(sizeof(struct adc_host) + extra, GFP_KERNEL);
if (!adc)
return NULL;
adc->dev = dev;
g_adc = adc;
return adc;
}
EXPORT_SYMBOL(adc_alloc_host);
void adc_free_host(struct adc_host *adc)
{
kfree(adc);
adc = NULL;
return;
}
EXPORT_SYMBOL(adc_free_host);
struct adc_client *adc_register(int chn,
void (*callback)(struct adc_client *, void *, int),
void *callback_param)
{
struct adc_client *client;
if(!g_adc)
{
printk(KERN_ERR "adc host has not initialized\n");
return NULL;
}
if(chn >= MAX_ADC_CHN)
{
dev_err(g_adc->dev, "channel[%d] is greater than the maximum[%d]\n", chn, MAX_ADC_CHN);
return NULL;
}
client = kzalloc(sizeof(struct adc_client), GFP_KERNEL);
if(!client)
{
dev_err(g_adc->dev, "no memory for adc client\n");
return NULL;
}
client->callback = callback;
client->callback_param = callback_param;
client->chn = chn;
client->adc = g_adc;
return client;
}
EXPORT_SYMBOL(adc_register);
void adc_unregister(struct adc_client *client)
{
kfree(client);
client = NULL;
return;
}
EXPORT_SYMBOL(adc_unregister);
static void trigger_next_adc_job_if_any(struct adc_host *adc)
{
int head = adc->queue_head;
if (!adc->queue[head])
return;
adc->cur = adc->queue[head]->client;
adc->ops->start(adc);
return;
}
static int
adc_enqueue_request(struct adc_host *adc, struct adc_request *req)
{
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(adc->dev, "ADC queue is full, dropping request\n");
return -EBUSY;
}
adc->queue[tail] = req;
if (head == tail)
trigger_next_adc_job_if_any(adc);
adc->queue_tail = (tail + 1) & (MAX_ADC_FIFO_DEPTH - 1);
mutex_unlock(&adc->queue_mutex);
return 0;
}
static void
adc_sync_read_callback(struct adc_client *client, void *param, int result)
{
struct adc_request *req = param;
client->result = result;
complete(&req->completion);
}
int adc_sync_read(struct adc_client *client)
{
struct adc_request *req = NULL;
int err;
if(client == NULL) {
printk(KERN_ERR "client point is NULL");
return -EINVAL;
}
if(client->adc->is_suspended == 1) {
dev_dbg(client->adc->dev, "system enter sleep\n");
return -1;
}
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req){
dev_err(client->adc->dev, "no memory for adc request\n");
return -ENOMEM;
}
req->chn = client->chn;
req->callback = adc_sync_read_callback;
req->callback_param = req;
req->client = client;
init_completion(&req->completion);
err = adc_enqueue_request(client->adc, req);
if (err)
{
dev_err(client->adc->dev, "fail to enqueue request\n");
kfree(req);
return err;
}
wait_for_completion(&req->completion);
return client->result;
}
EXPORT_SYMBOL(adc_sync_read);
int adc_async_read(struct adc_client *client)
{
struct adc_request *req = NULL;
if(client == NULL) {
printk(KERN_ERR "client point is NULL");
return -EINVAL;
}
if(client->adc->is_suspended == 1) {
dev_dbg(client->adc->dev, "system enter sleep\n");
return -1;
}
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req) {
dev_err(client->adc->dev, "no memory for adc request\n");
return -ENOMEM;
}
req->chn = client->chn;
req->callback = client->callback;
req->callback_param = client->callback_param;
req->client = client;
return adc_enqueue_request(client->adc, req);
}
EXPORT_SYMBOL(adc_async_read);
void adc_core_irq_handle(struct adc_host *adc)
{
struct adc_request *req;
int head, res;
head = adc->queue_head;
req = adc->queue[head];
if (WARN_ON(!req)) {
dev_err(adc->dev, "adc irq: ADC queue empty!\n");
return;
}
adc->queue[head] = NULL;
adc->queue_head = (head + 1) & (MAX_ADC_FIFO_DEPTH - 1);
res = adc->ops->read(adc);
adc->ops->stop(adc);
trigger_next_adc_job_if_any(adc);
req->callback(adc->cur, req->callback_param, res);
kfree(req);
}
EXPORT_SYMBOL(adc_core_irq_handle);

16
drivers/adc/plat/Kconfig Normal file
View File

@ -0,0 +1,16 @@
#
# Adc hardware configuration
#
choice
prompt "ADC hardware drivers"
config ADC_RK28
bool "RK28 adc interface"
help
This supports the use of the ADC interface on rk28 processors.
config ADC_RK29
bool "RK29 adc interface"
help
This supports the use of the ADC interface on rk29 processors.
endchoice

View File

@ -0,0 +1,6 @@
#
# Makefile for the adc hardware drivers.
#
obj-$(CONFIG_ADC_RK28) += rk28_adc.o
obj-$(CONFIG_ADC_RK29) += rk29_adc.o

236
drivers/adc/plat/rk28_adc.c Executable file
View File

@ -0,0 +1,236 @@
/* drivers/adc/chips/rk28_adc.c
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/adc.h>
#include <linux/delay.h>
#include "rk28_adc.h"
//#define ADC_TEST
struct rk28_adc_device {
int irq;
void __iomem *regs;
struct clk * clk;
struct resource *ioarea;
struct adc_host *adc;
};
static void rk28_adc_start(struct adc_host *adc)
{
struct rk28_adc_device *dev = adc_priv(adc);
int chn = adc->cur->chn;
writel(ADC_CTRL_IRQ_ENABLE|ADC_CTRL_POWER_UP|ADC_CTRL_START|ADC_CTRL_CH(chn),
dev->regs + ADC_CTRL);
}
static void rk28_adc_stop(struct adc_host *adc)
{
struct rk28_adc_device *dev = adc_priv(adc);
writel(ADC_CTRL_IRQ_STATUS, dev->regs + ADC_CTRL);
}
static int rk28_adc_read(struct adc_host *adc)
{
struct rk28_adc_device *dev = adc_priv(adc);
udelay(SAMPLE_RATE);
return readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;
}
static irqreturn_t rk28_adc_irq(int irq, void *data)
{
struct rk28_adc_device *dev = data;
adc_core_irq_handle(dev->adc);
return IRQ_HANDLED;
}
static const struct adc_ops rk28_adc_ops = {
.start = rk28_adc_start,
.stop = rk28_adc_stop,
.read = rk28_adc_read,
};
#ifdef ADC_TEST
static void callback(struct adc_client *client, void *param, int result)
{
dev_info(client->adc->dev, "[chn%d] async_read = %d\n", client->chn, result);
return;
}
static int rk28_adc_test(void)
{
int sync_read = 0;
struct adc_client *client = adc_register(1, callback, NULL);
while(1)
{
adc_async_read(client);
udelay(20);
sync_read = adc_sync_read(client);
dev_info(client->adc->dev, "[chn%d] sync_read = %d\n", client->chn, sync_read);
udelay(20);
}
adc_unregister(client);
return 0;
}
#endif
static int rk28_adc_probe(struct platform_device *pdev)
{
struct adc_host *adc = NULL;
struct rk28_adc_device *dev;
struct resource *res;
int ret;
adc = adc_alloc_host(sizeof(struct rk28_adc_device), &pdev->dev);
if (!adc)
return -ENOMEM;
mutex_init(&adc->queue_mutex);
adc->dev = &pdev->dev;
adc->is_suspended = 0;
adc->ops = &rk28_adc_ops;
dev = adc_priv(adc);
dev->adc = adc;
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq <= 0) {
dev_err(&pdev->dev, "failed to get adc irq\n");
ret = -ENOENT;
goto err_alloc;
}
ret = request_irq(dev->irq, rk28_adc_irq, 0, pdev->name, dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to attach adc irq\n");
goto err_alloc;
}
dev->clk = clk_get(&pdev->dev, "saradc");
if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "failed to get adc clock\n");
ret = PTR_ERR(dev->clk);
goto err_irq;
}
ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);
if(ret < 0) {
dev_err(&pdev->dev, "failed to set adc clk\n");
goto err_clk;
}
clk_enable(dev->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
goto err_clk;
}
dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1,
pdev->name);
if(dev->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
goto err_clk;
}
dev->regs = ioremap(res->start, (res->end - res->start) + 1);
if (!dev->regs) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
goto err_ioarea;
}
platform_set_drvdata(pdev, dev);
dev_info(&pdev->dev, "rk28 adc: driver initialized\n");
#ifdef ADC_TEST
rk28_adc_test();
#endif
return 0;
// err_iomap:
// iounmap(dev->regs);
err_ioarea:
release_resource(dev->ioarea);
kfree(dev->ioarea);
clk_disable(dev->clk);
err_clk:
clk_put(dev->clk);
err_irq:
free_irq(dev->irq, dev);
err_alloc:
adc_free_host(dev->adc);
return ret;
}
static int rk28_adc_remove(struct platform_device *pdev)
{
struct rk28_adc_device *dev = platform_get_drvdata(pdev);
iounmap(dev->regs);
release_resource(dev->ioarea);
kfree(dev->ioarea);
free_irq(dev->irq, dev);
clk_disable(dev->clk);
clk_put(dev->clk);
adc_free_host(dev->adc);
return 0;
}
#ifdef CONFIG_PM
static int rk28_adc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct rk28_adc_device *dev = platform_get_drvdata(pdev);
dev->adc->is_suspended = 1;
return 0;
}
static int rk28_adc_resume(struct platform_device *pdev)
{
struct rk28_adc_device *dev = platform_get_drvdata(pdev);
dev->adc->is_suspended = 0;
return 0;
}
#else
#define rk28_adc_suspend NULL
#define rk28_adc_resume NULL
#endif
static struct platform_driver rk28_adc_driver = {
.driver = {
.name = "rk28-adc",
.owner = THIS_MODULE,
},
.probe = rk28_adc_probe,
.remove = __devexit_p(rk28_adc_remove),
.suspend = rk28_adc_suspend,
.resume = rk28_adc_resume,
};
static int __init rk28_adc_init(void)
{
return platform_driver_register(&rk28_adc_driver);
}
subsys_initcall(rk28_adc_init);
static void __exit rk28_adc_exit(void)
{
platform_driver_unregister(&rk28_adc_driver);
}
module_exit(rk28_adc_exit);
MODULE_DESCRIPTION("Driver for ADC");
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
MODULE_LICENSE("GPL");

32
drivers/adc/plat/rk28_adc.h Executable file
View File

@ -0,0 +1,32 @@
/* drivers/adc/chips/rk28_adc.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_RK29_ADC_H
#define __ASM_RK29_ADC_H
#define ADC_DATA 0x00
#define ADC_DATA_MASK 0x3ff
#define ADC_STAS 0x04
#define ADC_STAS_BUSY (1<<0)
#define ADC_CTRL 0x08
#define ADC_CTRL_CH(ch) ((ch)<<0)
#define ADC_CTRL_POWER_UP (1<<3)
#define ADC_CTRL_START (1<<4)
#define ADC_CTRL_IRQ_ENABLE (1<<5)
#define ADC_CTRL_IRQ_STATUS (1<<6)
#define ADC_CLK_RATE 1 //1M
/* maximum conversion rate of 100KSPS with 1MHZ ADC converter clock.
* SET: real conversion rate is half of maximum conversion rate
*/
#define SAMPLE_RATE ((1000/100) * 2 /(ADC_CLK_RATE))
#endif /* __ASM_RK29_ADC_H */

236
drivers/adc/plat/rk29_adc.c Executable file
View File

@ -0,0 +1,236 @@
/* drivers/adc/chips/rk29_adc.c
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/adc.h>
#include <linux/delay.h>
#include "rk29_adc.h"
//#define ADC_TEST
struct rk29_adc_device {
int irq;
void __iomem *regs;
struct clk * clk;
struct resource *ioarea;
struct adc_host *adc;
};
static void rk29_adc_start(struct adc_host *adc)
{
struct rk29_adc_device *dev = adc_priv(adc);
int chn = adc->cur->chn;
writel(ADC_CTRL_IRQ_ENABLE|ADC_CTRL_POWER_UP|ADC_CTRL_START|ADC_CTRL_CH(chn),
dev->regs + ADC_CTRL);
}
static void rk29_adc_stop(struct adc_host *adc)
{
struct rk29_adc_device *dev = adc_priv(adc);
writel(ADC_CTRL_IRQ_STATUS, dev->regs + ADC_CTRL);
}
static int rk29_adc_read(struct adc_host *adc)
{
struct rk29_adc_device *dev = adc_priv(adc);
udelay(SAMPLE_RATE);
return readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;
}
static irqreturn_t rk29_adc_irq(int irq, void *data)
{
struct rk29_adc_device *dev = data;
adc_core_irq_handle(dev->adc);
return IRQ_HANDLED;
}
static const struct adc_ops rk29_adc_ops = {
.start = rk29_adc_start,
.stop = rk29_adc_stop,
.read = rk29_adc_read,
};
#ifdef ADC_TEST
static void callback(struct adc_client *client, void *param, int result)
{
dev_info(client->adc->dev, "[chn%d] async_read = %d\n", client->chn, result);
return;
}
static int rk29_adc_test(void)
{
int sync_read = 0;
struct adc_client *client = adc_register(1, callback, NULL);
while(1)
{
adc_async_read(client);
udelay(20);
sync_read = adc_sync_read(client);
dev_info(client->adc->dev, "[chn%d] sync_read = %d\n", client->chn, sync_read);
udelay(20);
}
adc_unregister(client);
return 0;
}
#endif
static int rk29_adc_probe(struct platform_device *pdev)
{
struct adc_host *adc = NULL;
struct rk29_adc_device *dev;
struct resource *res;
int ret;
adc = adc_alloc_host(sizeof(struct rk29_adc_device), &pdev->dev);
if (!adc)
return -ENOMEM;
mutex_init(&adc->queue_mutex);
adc->dev = &pdev->dev;
adc->is_suspended = 0;
adc->ops = &rk29_adc_ops;
dev = adc_priv(adc);
dev->adc = adc;
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq <= 0) {
dev_err(&pdev->dev, "failed to get adc irq\n");
ret = -ENOENT;
goto err_alloc;
}
ret = request_irq(dev->irq, rk29_adc_irq, 0, pdev->name, dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to attach adc irq\n");
goto err_alloc;
}
dev->clk = clk_get(&pdev->dev, "saradc");
if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "failed to get adc clock\n");
ret = PTR_ERR(dev->clk);
goto err_irq;
}
ret = clk_set_rate(dev->clk, ADC_CLK_RATE * 1000 * 1000);
if(ret < 0) {
dev_err(&pdev->dev, "failed to set adc clk\n");
goto err_clk;
}
clk_enable(dev->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
goto err_clk;
}
dev->ioarea = request_mem_region(res->start, (res->end - res->start) + 1,
pdev->name);
if(dev->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
goto err_clk;
}
dev->regs = ioremap(res->start, (res->end - res->start) + 1);
if (!dev->regs) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
goto err_ioarea;
}
platform_set_drvdata(pdev, dev);
dev_info(&pdev->dev, "rk29 adc: driver initialized\n");
#ifdef ADC_TEST
rk29_adc_test();
#endif
return 0;
// err_iomap:
// iounmap(dev->regs);
err_ioarea:
release_resource(dev->ioarea);
kfree(dev->ioarea);
clk_disable(dev->clk);
err_clk:
clk_put(dev->clk);
err_irq:
free_irq(dev->irq, dev);
err_alloc:
adc_free_host(dev->adc);
return ret;
}
static int rk29_adc_remove(struct platform_device *pdev)
{
struct rk29_adc_device *dev = platform_get_drvdata(pdev);
iounmap(dev->regs);
release_resource(dev->ioarea);
kfree(dev->ioarea);
free_irq(dev->irq, dev);
clk_disable(dev->clk);
clk_put(dev->clk);
adc_free_host(dev->adc);
return 0;
}
#ifdef CONFIG_PM
static int rk29_adc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct rk29_adc_device *dev = platform_get_drvdata(pdev);
dev->adc->is_suspended = 1;
return 0;
}
static int rk29_adc_resume(struct platform_device *pdev)
{
struct rk29_adc_device *dev = platform_get_drvdata(pdev);
dev->adc->is_suspended = 0;
return 0;
}
#else
#define rk29_adc_suspend NULL
#define rk29_adc_resume NULL
#endif
static struct platform_driver rk29_adc_driver = {
.driver = {
.name = "rk29-adc",
.owner = THIS_MODULE,
},
.probe = rk29_adc_probe,
.remove = __devexit_p(rk29_adc_remove),
.suspend = rk29_adc_suspend,
.resume = rk29_adc_resume,
};
static int __init rk29_adc_init(void)
{
return platform_driver_register(&rk29_adc_driver);
}
subsys_initcall(rk29_adc_init);
static void __exit rk29_adc_exit(void)
{
platform_driver_unregister(&rk29_adc_driver);
}
module_exit(rk29_adc_exit);
MODULE_DESCRIPTION("Driver for ADC");
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
MODULE_LICENSE("GPL");

32
drivers/adc/plat/rk29_adc.h Executable file
View File

@ -0,0 +1,32 @@
/* drivers/adc/chips/rk29_adc.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_RK29_ADC_H
#define __ASM_RK29_ADC_H
#define ADC_DATA 0x00
#define ADC_DATA_MASK 0x3ff
#define ADC_STAS 0x04
#define ADC_STAS_BUSY (1<<0)
#define ADC_CTRL 0x08
#define ADC_CTRL_CH(ch) ((ch)<<0)
#define ADC_CTRL_POWER_UP (1<<3)
#define ADC_CTRL_START (1<<4)
#define ADC_CTRL_IRQ_ENABLE (1<<5)
#define ADC_CTRL_IRQ_STATUS (1<<6)
#define ADC_CLK_RATE 1 //1M
/* maximum conversion rate of 100KSPS with 1MHZ ADC converter clock.
* SET: real conversion rate is half of maximum conversion rate
*/
#define SAMPLE_RATE ((1000/100) * 2 /(ADC_CLK_RATE))
#endif /* __ASM_RK29_ADC_H */

View File

@ -478,7 +478,7 @@ static int rk29_xfer_msg(struct i2c_adapter *adap,
}
#endif
}
#endif
#endif
}
return ret;

73
include/linux/adc.h Executable file
View File

@ -0,0 +1,73 @@
/* include/linux/adc.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __ASM_ADC_CORE_H
#define __ASM_ADC_CORE_H
#define MAX_ADC_CHN 4
#define MAX_ADC_FIFO_DEPTH 8
struct adc_client {
int chn;
int time;
int result;
void (*callback)(struct adc_client *, void *, int);
void *callback_param;
struct adc_host *adc;
};
struct adc_request {
int result;
int chn;
void (*callback)(struct adc_client *, void *, int);
void *callback_param;
struct adc_client *client;
/* Used in case of sync requests */
struct completion completion;
};
struct adc_host;
struct adc_ops {
void (*start)(struct adc_host *);
void (*stop)(struct adc_host *);
int (*read)(struct adc_host *);
};
struct adc_host {
struct device *dev;
int is_suspended;
struct adc_request *queue[MAX_ADC_FIFO_DEPTH];
int queue_head;
int queue_tail;
struct mutex queue_mutex;
struct adc_client *cur;
const struct adc_ops *ops;
unsigned long private[0];
};
static inline void *adc_priv(struct adc_host *adc)
{
return (void *)adc->private;
}
extern struct adc_host *adc_alloc_host(int extra, struct device *dev);
extern void adc_free_host(struct adc_host *adc);
extern void adc_core_irq_handle(struct adc_host *adc);
extern struct adc_client *adc_register(int chn,
void (*callback)(struct adc_client *, void *, int),
void *callback_param);
extern void adc_unregister(struct adc_client *client);
extern int adc_sync_read(struct adc_client *client);
extern int adc_async_read(struct adc_client *client);
#endif