mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
drivers: remove unused adc driver
Change-Id: I71a79cf4372d2645537e3b8d19253487eb9039a2 Signed-off-by: Tao Huang <huangtao@rock-chips.com>
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# ADC subsystem configuration
|
||||
#
|
||||
|
||||
menuconfig ADC
|
||||
bool "ADC support"
|
||||
depends on PLAT_RK
|
||||
default y
|
||||
if ADC
|
||||
|
||||
source drivers/adc/plat/Kconfig
|
||||
|
||||
endif # ADC
|
||||
@@ -1,8 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the adc core.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ADC) += core.o
|
||||
obj-y += plat/
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/* 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_PRIV_H
|
||||
#define __ASM_ADC_PRIV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <mach/board.h>
|
||||
#ifdef CONFIG_ADC_RK28
|
||||
#include "plat/rk28_adc.h"
|
||||
#endif
|
||||
#ifdef CONFIG_ADC_RK29
|
||||
#include "plat/rk29_adc.h"
|
||||
#endif
|
||||
#ifdef CONFIG_ADC_RK30
|
||||
#include "plat/rk30_adc.h"
|
||||
#endif
|
||||
|
||||
#define ADC_READ_TMO 100 // ms
|
||||
|
||||
#define adc_writel writel_relaxed
|
||||
#define adc_readl readl_relaxed
|
||||
|
||||
#if 0
|
||||
#define adc_dbg(dev, format, arg...) \
|
||||
dev_printk(KERN_INFO , dev , format , ## arg)
|
||||
#else
|
||||
#define adc_dbg(dev, format, arg...)
|
||||
#endif
|
||||
|
||||
enum read_type{
|
||||
ADC_SYNC_READ = 0,
|
||||
ADC_ASYNC_READ,
|
||||
};
|
||||
|
||||
struct adc_request {
|
||||
struct list_head entry;
|
||||
struct adc_client *client;
|
||||
};
|
||||
struct adc_ops {
|
||||
void (*start)(struct adc_host *);
|
||||
void (*stop)(struct adc_host *);
|
||||
int (*read)(struct adc_host *);
|
||||
void (*dump)(struct adc_host *);
|
||||
};
|
||||
struct adc_host {
|
||||
struct list_head entry;
|
||||
struct list_head req_head;
|
||||
struct list_head callback_head;
|
||||
unsigned int is_suspended;
|
||||
enum host_chn_mask mask;
|
||||
struct device *dev;
|
||||
unsigned int chn;
|
||||
spinlock_t lock;
|
||||
struct mutex m_lock;
|
||||
unsigned int client_count;
|
||||
const struct adc_ops *ops;
|
||||
struct adc_client *base_client;
|
||||
struct adc_platform_data *pdata;
|
||||
unsigned long priv[0];
|
||||
};
|
||||
|
||||
static inline void *adc_priv(struct adc_host *adc)
|
||||
{
|
||||
return adc->priv;
|
||||
}
|
||||
extern struct adc_host *g_adc;
|
||||
struct adc_host *adc_alloc_host(struct device *dev, int extra, enum host_chn_mask mask);
|
||||
void adc_free_host(struct adc_host *adc);
|
||||
void adc_core_irq_handle(struct adc_host *adc);
|
||||
#endif
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
/* 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/adc.h>
|
||||
#include "adc_priv.h"
|
||||
|
||||
struct adc_host *g_adc = NULL;
|
||||
static LIST_HEAD(adc_host_head);
|
||||
|
||||
struct adc_host *adc_alloc_host(struct device *dev, int extra, enum host_chn_mask mask)
|
||||
{
|
||||
struct adc_host *adc;
|
||||
|
||||
adc = kzalloc(sizeof(struct adc_host) + extra, GFP_KERNEL);
|
||||
if (!adc)
|
||||
return NULL;
|
||||
adc->mask = mask;
|
||||
adc->dev = dev;
|
||||
adc->chn = -1;
|
||||
spin_lock_init(&adc->lock);
|
||||
mutex_init(&adc->m_lock);
|
||||
INIT_LIST_HEAD(&adc->req_head);
|
||||
INIT_LIST_HEAD(&adc->callback_head);
|
||||
|
||||
list_add_tail(&adc->entry, &adc_host_head);
|
||||
|
||||
return adc;
|
||||
}
|
||||
|
||||
void adc_free_host(struct adc_host *adc)
|
||||
{
|
||||
list_del(&adc->entry);
|
||||
kfree(adc);
|
||||
adc = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
struct adc_client *adc_register(int chn,
|
||||
void (*callback)(struct adc_client *, void *, int),
|
||||
void *callback_param)
|
||||
|
||||
{
|
||||
struct adc_client *client = NULL;
|
||||
struct adc_host *adc = NULL;
|
||||
|
||||
if(chn < 0)
|
||||
return NULL;
|
||||
list_for_each_entry(adc, &adc_host_head, entry) {
|
||||
if((chn == 0 && adc->mask == SARADC_CHN_MASK) ||
|
||||
(chn & adc->mask)){
|
||||
client = kzalloc(sizeof(struct adc_client), GFP_KERNEL);
|
||||
if(!client)
|
||||
return NULL;
|
||||
client->callback = callback;
|
||||
client->callback_param = callback_param;
|
||||
client->chn = chn;
|
||||
client->adc = adc;
|
||||
client->index = adc->client_count;
|
||||
init_waitqueue_head(&client->wait);
|
||||
adc->client_count++;
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
dev_err(adc->dev, "chn(%d) is not support\n", chn);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(adc_register);
|
||||
|
||||
void adc_unregister(struct adc_client *client)
|
||||
{
|
||||
struct adc_host *adc = client->adc;
|
||||
|
||||
adc->client_count--;
|
||||
kfree(client);
|
||||
client = NULL;
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(adc_unregister);
|
||||
|
||||
static inline void trigger_next_adc_job_if_any(struct adc_host *adc)
|
||||
{
|
||||
struct adc_request *req = NULL;
|
||||
|
||||
req = list_first_entry(&adc->req_head, struct adc_request, entry);
|
||||
if(req){
|
||||
if(req->client == NULL){
|
||||
dev_err(adc->dev, "Abnormal: client piont is NULL...............\n");
|
||||
return;
|
||||
}
|
||||
adc->chn = req->client->chn;
|
||||
adc->ops->start(adc);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int adc_request_add(struct adc_host *adc, struct adc_client *client)
|
||||
{
|
||||
struct adc_request *req = NULL;
|
||||
|
||||
req = kzalloc(sizeof(struct adc_request), GFP_ATOMIC);
|
||||
|
||||
if(unlikely(!req))
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&req->entry);
|
||||
req->client = client;
|
||||
list_add_tail(&req->entry, &adc->req_head);
|
||||
if(adc->chn == -1)
|
||||
trigger_next_adc_job_if_any(adc);
|
||||
return 0;
|
||||
}
|
||||
static void
|
||||
adc_sync_read_callback(struct adc_client *client, void *param, int result)
|
||||
{
|
||||
client->result = result;
|
||||
}
|
||||
|
||||
static void adc_callback(struct adc_host *adc)
|
||||
{
|
||||
struct adc_request *req = NULL, *n = NULL;
|
||||
|
||||
list_for_each_entry_safe(req, n, &adc->callback_head, entry) {
|
||||
if(req->client->flags & (1<<ADC_ASYNC_READ)){
|
||||
req->client->callback(req->client, req->client->callback_param, req->client->result);
|
||||
}
|
||||
if(req->client->flags & (1<<ADC_SYNC_READ)){
|
||||
adc_sync_read_callback(req->client, NULL, req->client->result);
|
||||
req->client->is_finished = 1;
|
||||
wake_up(&req->client->wait);
|
||||
}
|
||||
req->client->flags = 0;
|
||||
list_del_init(&req->entry);
|
||||
kfree(req);
|
||||
}
|
||||
}
|
||||
|
||||
void adc_finished(struct adc_host *adc, int result)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct adc_request *req = NULL, *n = NULL;
|
||||
|
||||
adc->ops->stop(adc);
|
||||
udelay(SAMPLE_RATE);
|
||||
spin_lock_irqsave(&adc->lock, flags);
|
||||
list_for_each_entry_safe(req, n, &adc->req_head, entry) {
|
||||
if(req->client->chn == adc->chn){
|
||||
req->client->result = result;
|
||||
list_move_tail(&req->entry, &adc->callback_head);
|
||||
}
|
||||
}
|
||||
adc->chn = -1;
|
||||
if(!list_empty(&adc->req_head))
|
||||
trigger_next_adc_job_if_any(adc);
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
|
||||
adc_callback(adc);
|
||||
}
|
||||
|
||||
void adc_core_irq_handle(struct adc_host *adc)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
WARN_ON(adc->chn == -1);
|
||||
|
||||
mutex_lock(&adc->m_lock);
|
||||
|
||||
result = adc->ops->read(adc);
|
||||
adc_dbg(adc->dev, "chn[%d] read value: %d\n", adc->chn, result);
|
||||
|
||||
adc_finished(adc, result);
|
||||
|
||||
mutex_unlock(&adc->m_lock);
|
||||
}
|
||||
|
||||
int adc_host_read(struct adc_client *client, enum read_type type)
|
||||
{
|
||||
int tmo, ret = 0;
|
||||
unsigned long flags;
|
||||
struct adc_host *adc = NULL;
|
||||
|
||||
if(client == NULL) {
|
||||
printk(KERN_ERR "client is NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
adc = client->adc;
|
||||
if(adc->is_suspended == 1) {
|
||||
dev_err(adc->dev, "adc is in suspend state\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&adc->lock, flags);
|
||||
if(client->flags & (1<<type)){
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
adc_dbg(adc->dev, "req is exist: %s, client->index: %d\n",
|
||||
(type == ADC_ASYNC_READ)?"async_read":"sync_read", client->index);
|
||||
return -EEXIST;
|
||||
}else if(client->flags != 0){
|
||||
client->flags |= 1<<type;
|
||||
}else{
|
||||
client->flags = 1<<type;
|
||||
ret = adc_request_add(adc, client);
|
||||
if(ret < 0){
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
dev_err(adc->dev, "fail to add request\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if(type == ADC_ASYNC_READ){
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
client->is_finished = 0;
|
||||
spin_unlock_irqrestore(&adc->lock, flags);
|
||||
|
||||
tmo = wait_event_timeout(client->wait, ( client->is_finished == 1 ), msecs_to_jiffies(ADC_READ_TMO));
|
||||
mutex_lock(&adc->m_lock);
|
||||
if(unlikely((tmo <= 0) && (client->is_finished == 0))) {
|
||||
dev_err(adc->dev, "get adc value timeout.................................\n");
|
||||
if(adc->ops->dump)
|
||||
adc->ops->dump(adc);
|
||||
adc_finished(adc, -1);
|
||||
mutex_unlock(&adc->m_lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
mutex_unlock(&adc->m_lock);
|
||||
|
||||
return client->result;
|
||||
}
|
||||
|
||||
int adc_sync_read(struct adc_client *client)
|
||||
{
|
||||
return adc_host_read(client, ADC_SYNC_READ);
|
||||
}
|
||||
EXPORT_SYMBOL(adc_sync_read);
|
||||
|
||||
int adc_async_read(struct adc_client *client)
|
||||
{
|
||||
return adc_host_read(client, ADC_ASYNC_READ);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(adc_async_read);
|
||||
|
||||
int adc_get_def_ref_volt(void)
|
||||
{
|
||||
return g_adc->pdata->ref_volt;
|
||||
}
|
||||
EXPORT_SYMBOL(adc_get_def_ref_volt);
|
||||
|
||||
int adc_get_curr_ref_volt(void)
|
||||
{
|
||||
int v = 0, volt = 0;
|
||||
|
||||
if(!g_adc)
|
||||
return -EINVAL;
|
||||
if(!g_adc->base_client)
|
||||
return g_adc->pdata->ref_volt;
|
||||
|
||||
volt = g_adc->pdata->get_base_volt();
|
||||
if(volt < 0)
|
||||
return g_adc->pdata->ref_volt;
|
||||
|
||||
v = adc_sync_read(g_adc->base_client);
|
||||
if(v < 0)
|
||||
return v;
|
||||
|
||||
return volt * 1024 / v;
|
||||
}
|
||||
EXPORT_SYMBOL(adc_get_curr_ref_volt);
|
||||
@@ -1,31 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Adc hardware configuration
|
||||
#
|
||||
|
||||
choice
|
||||
prompt "ADC hardware drivers"
|
||||
default ADC_RK29 if ARCH_RK29
|
||||
default ADC_RK30 if ARCH_RK30 || ARCH_RK2928 || ARCH_RK3188 || ARCH_RK3026 || ARCH_RK319X
|
||||
|
||||
config ADC_NULL
|
||||
bool "NULL"
|
||||
|
||||
config ADC_RK28
|
||||
bool "RK28 adc interface"
|
||||
depends on ARCH_RK2818 || ARCH_RK2808 || ARCH_RK2816
|
||||
help
|
||||
This supports the use of the ADC interface on rk28 processors.
|
||||
|
||||
config ADC_RK29
|
||||
bool "RK29 adc interface"
|
||||
depends on ARCH_RK29
|
||||
help
|
||||
This supports the use of the ADC interface on rk29 processors.
|
||||
|
||||
config ADC_RK30
|
||||
bool "RK30 adc interface"
|
||||
depends on ARCH_RK30 || ARCH_RK2928 || ARCH_RK3188 || ARCH_RK3026 || ARCH_RK319X
|
||||
help
|
||||
This supports the use of the ADC interface on rk30 processors.
|
||||
endchoice
|
||||
@@ -1,7 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the adc hardware drivers.
|
||||
#
|
||||
obj-$(CONFIG_ADC_RK28) += rk28_adc.o
|
||||
obj-$(CONFIG_ADC_RK29) += rk29_adc.o
|
||||
obj-$(CONFIG_ADC_RK30) += rk30_adc.o
|
||||
@@ -1,221 +0,0 @@
|
||||
/* 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/adc.h>
|
||||
|
||||
#include "../adc_priv.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->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(&pdev->dev, sizeof(struct rk28_adc_device), SARADC_CHN_MASK);
|
||||
if (!adc)
|
||||
return -ENOMEM;
|
||||
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_threaded_irq(dev->irq, NULL, rk28_adc_irq, IRQF_ONESHOT, 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_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");
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* 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 >> SARADC_CHN_SHIFT)
|
||||
#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 */
|
||||
@@ -1,261 +0,0 @@
|
||||
/* 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/adc.h>
|
||||
|
||||
#include "../adc_priv.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->chn;
|
||||
|
||||
writel(0, dev->regs + ADC_CTRL);
|
||||
writel(ADC_CTRL_POWER_UP|ADC_CTRL_CH(chn), dev->regs + ADC_CTRL);
|
||||
udelay(SAMPLE_RATE);
|
||||
|
||||
writel(readl(dev->regs + ADC_CTRL)|ADC_CTRL_IRQ_ENABLE|ADC_CTRL_START,
|
||||
dev->regs + ADC_CTRL);
|
||||
return;
|
||||
}
|
||||
static void rk29_adc_stop(struct adc_host *adc)
|
||||
{
|
||||
struct rk29_adc_device *dev = adc_priv(adc);
|
||||
|
||||
writel(0, 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
|
||||
struct adc_test_data {
|
||||
struct adc_client *client;
|
||||
struct timer_list timer;
|
||||
struct work_struct timer_work;
|
||||
};
|
||||
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 void adc_timer(unsigned long data)
|
||||
{
|
||||
//int sync_read = 0;
|
||||
struct adc_test_data *test=(struct adc_test_data *)data;
|
||||
|
||||
//sync_read = adc_sync_read(test->client);
|
||||
//dev_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);
|
||||
schedule_work(&test->timer_work);
|
||||
add_timer(&test->timer);
|
||||
}
|
||||
static void adc_timer_work(struct work_struct *work)
|
||||
{
|
||||
int sync_read = 0;
|
||||
struct adc_test_data *test = container_of(work, struct adc_test_data,
|
||||
timer_work);
|
||||
adc_async_read(test->client);
|
||||
sync_read = adc_sync_read(test->client);
|
||||
dev_info(test->client->adc->dev, "[chn%d] sync_read = %d\n", 0, sync_read);
|
||||
}
|
||||
|
||||
static int rk29_adc_test(void)
|
||||
{
|
||||
struct adc_test_data *test = NULL;
|
||||
|
||||
test = kzalloc(sizeof(struct adc_test_data), GFP_KERNEL);
|
||||
|
||||
test->client = adc_register(0, callback, NULL);
|
||||
INIT_WORK(&test->timer_work, adc_timer_work);
|
||||
setup_timer(&test->timer, adc_timer, (unsigned long)test);
|
||||
test->timer.expires = jiffies + 100;
|
||||
add_timer(&test->timer);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rk29_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct adc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct adc_host *adc = NULL;
|
||||
struct rk29_adc_device *dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
if(!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
adc = adc_alloc_host(&pdev->dev, sizeof(struct rk29_adc_device), SARADC_CHN_MASK);
|
||||
if (!adc)
|
||||
return -ENOMEM;
|
||||
adc->ops = &rk29_adc_ops;
|
||||
adc->pdata = pdata;
|
||||
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_threaded_irq(dev->irq, NULL, rk29_adc_irq, IRQF_ONESHOT, 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;
|
||||
}
|
||||
g_adc = adc;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
dev_info(&pdev->dev, "rk29 adc: driver initialized\n");
|
||||
return 0;
|
||||
|
||||
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");
|
||||
static int __init adc_test_init(void)
|
||||
{
|
||||
#ifdef ADC_TEST
|
||||
rk29_adc_test();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
module_init(adc_test_init);
|
||||
@@ -1,29 +0,0 @@
|
||||
/* 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) (0x07 - ((ch >> SARADC_CHN_SHIFT)<<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
|
||||
#define SAMPLE_RATE (20/ADC_CLK_RATE) //20 CLK
|
||||
|
||||
|
||||
#endif /* __ASM_RK29_ADC_H */
|
||||
@@ -1,325 +0,0 @@
|
||||
/* drivers/adc/chips/rk30_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/adc.h>
|
||||
|
||||
#include "../adc_priv.h"
|
||||
#include "rk30_adc.h"
|
||||
|
||||
//#define ADC_TEST
|
||||
#define SAMPLE_COUNT 10
|
||||
#define MIN_SAMPLE_VALUE 310
|
||||
struct rk30_adc_device {
|
||||
int irq;
|
||||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
struct clk *pclk;
|
||||
struct resource *ioarea;
|
||||
struct adc_host *adc;
|
||||
};
|
||||
static void rk30_adc_dump(struct adc_host *adc)
|
||||
{
|
||||
struct rk30_adc_device *dev = adc_priv(adc);
|
||||
|
||||
dev_info(adc->dev, "[0x00-0x0c]: 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
adc_readl(dev->regs + 0x00),
|
||||
adc_readl(dev->regs + 0x04),
|
||||
adc_readl(dev->regs + 0x08),
|
||||
adc_readl(dev->regs + 0x0c));
|
||||
}
|
||||
static void rk30_adc_start(struct adc_host *adc)
|
||||
{
|
||||
struct rk30_adc_device *dev = adc_priv(adc);
|
||||
int chn = adc->chn;
|
||||
|
||||
//adc_writel(0, dev->regs + ADC_CTRL);
|
||||
adc_writel(0x08, dev->regs + ADC_DELAY_PU_SOC);
|
||||
adc_writel(ADC_CTRL_POWER_UP|ADC_CTRL_CH(chn)|ADC_CTRL_IRQ_ENABLE, dev->regs + ADC_CTRL);
|
||||
|
||||
return;
|
||||
}
|
||||
static void rk30_adc_stop(struct adc_host *adc)
|
||||
{
|
||||
struct rk30_adc_device *dev = adc_priv(adc);
|
||||
|
||||
adc_writel(0, dev->regs + ADC_CTRL);
|
||||
}
|
||||
static int rk30_adc_read(struct adc_host *adc)
|
||||
{
|
||||
struct rk30_adc_device *dev = adc_priv(adc);
|
||||
|
||||
return adc_readl(dev->regs + ADC_DATA) & ADC_DATA_MASK;
|
||||
}
|
||||
static irqreturn_t rk30_adc_irq(int irq, void *data)
|
||||
{
|
||||
struct rk30_adc_device *dev = data;
|
||||
|
||||
adc_core_irq_handle(dev->adc);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
static const struct adc_ops rk30_adc_ops = {
|
||||
.start = rk30_adc_start,
|
||||
.stop = rk30_adc_stop,
|
||||
.read = rk30_adc_read,
|
||||
.dump = rk30_adc_dump,
|
||||
};
|
||||
#ifdef ADC_TEST
|
||||
#define CHN_NR 3
|
||||
struct workqueue_struct *adc_wq;
|
||||
struct adc_test_data {
|
||||
struct adc_client *client;
|
||||
struct timer_list timer;
|
||||
struct work_struct timer_work;
|
||||
};
|
||||
static void callback(struct adc_client *client, void *param, int result)
|
||||
{
|
||||
dev_dbg(client->adc->dev, "[chn%d] async_read = %d\n", client->chn, result);
|
||||
return;
|
||||
}
|
||||
static void adc_timer(unsigned long data)
|
||||
{
|
||||
struct adc_test_data *test=(struct adc_test_data *)data;
|
||||
|
||||
queue_work(adc_wq, &test->timer_work);
|
||||
mod_timer(&test->timer, jiffies+msecs_to_jiffies(20));
|
||||
}
|
||||
static void adc_timer_work(struct work_struct *work)
|
||||
{
|
||||
int sync_read = 0;
|
||||
struct adc_test_data *test = container_of(work, struct adc_test_data,
|
||||
timer_work);
|
||||
adc_async_read(test->client);
|
||||
sync_read = adc_sync_read(test->client);
|
||||
dev_dbg(test->client->adc->dev, "[chn%d] sync_read = %d\n", test->client->chn, sync_read);
|
||||
}
|
||||
|
||||
static int rk30_adc_test(void)
|
||||
{
|
||||
int i;
|
||||
struct adc_test_data *test[CHN_NR];
|
||||
|
||||
adc_wq = create_singlethread_workqueue("adc_test");
|
||||
for(i = 0; i < CHN_NR; i++){
|
||||
test[i] = kzalloc(sizeof(struct adc_test_data), GFP_KERNEL);
|
||||
test[i]->client = adc_register(i, callback, NULL);
|
||||
INIT_WORK(&test[i]->timer_work, adc_timer_work);
|
||||
setup_timer(&test[i]->timer, adc_timer, (unsigned long)test[i]);
|
||||
mod_timer(&test[i]->timer, jiffies+msecs_to_jiffies(20));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rk30_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct adc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct adc_host *adc = NULL;
|
||||
struct rk30_adc_device *dev;
|
||||
struct resource *res;
|
||||
int ret = 0, i, v;
|
||||
|
||||
if(!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
adc = adc_alloc_host(&pdev->dev, sizeof(struct rk30_adc_device), SARADC_CHN_MASK);
|
||||
if (!adc)
|
||||
return -ENOMEM;
|
||||
adc->ops = &rk30_adc_ops;
|
||||
adc->pdata = pdata;
|
||||
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_threaded_irq(dev->irq, NULL, rk30_adc_irq, IRQF_ONESHOT, pdev->name, dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to attach adc irq\n");
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
dev->pclk = clk_get(&pdev->dev, "pclk_saradc");
|
||||
if (IS_ERR(dev->pclk)) {
|
||||
dev_err(&pdev->dev, "failed to get adc pclk\n");
|
||||
ret = PTR_ERR(dev->pclk);
|
||||
goto err_irq;
|
||||
}
|
||||
clk_enable(dev->pclk);
|
||||
|
||||
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_pclk;
|
||||
}
|
||||
|
||||
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_clk2;
|
||||
}
|
||||
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;
|
||||
}
|
||||
g_adc = adc;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
if(adc->pdata->base_chn > 0){
|
||||
adc->base_client = adc_register(adc->pdata->base_chn, NULL, NULL);
|
||||
if(!adc->base_client){
|
||||
dev_err(&pdev->dev, "adc_register(base_chn: %d) failed\n", adc->pdata->base_chn);
|
||||
ret = -ENOMEM;
|
||||
goto err_adc_register;
|
||||
}
|
||||
for(i = 0; i < SAMPLE_COUNT; i++){
|
||||
v = adc_sync_read(adc->base_client);
|
||||
if(v < 0){
|
||||
dev_err(&pdev->dev, "adc_register(base_chn: %d) failed\n", adc->pdata->base_chn);
|
||||
ret = v;
|
||||
goto err_adc_sync_read;
|
||||
}else if(v < MIN_SAMPLE_VALUE){
|
||||
dev_info(&pdev->dev, "chn[%d]: adc value(%d) is invalide\n", adc->pdata->base_chn, v);
|
||||
adc_unregister(adc->base_client);
|
||||
adc->base_client = NULL;
|
||||
break;
|
||||
}
|
||||
adc_dbg(&pdev->dev, "read ref_adc: %d\n", v);
|
||||
mdelay(1);
|
||||
}
|
||||
}
|
||||
dev_info(&pdev->dev, "rk30 adc: driver initialized\n");
|
||||
return 0;
|
||||
err_adc_sync_read:
|
||||
adc_unregister(adc->base_client);
|
||||
adc->base_client = NULL;
|
||||
err_adc_register:
|
||||
iounmap(dev->regs);
|
||||
err_ioarea:
|
||||
release_resource(dev->ioarea);
|
||||
kfree(dev->ioarea);
|
||||
|
||||
err_clk:
|
||||
clk_disable(dev->clk);
|
||||
|
||||
err_pclk:
|
||||
clk_disable(dev->pclk);
|
||||
clk_put(dev->pclk);
|
||||
|
||||
err_clk2:
|
||||
clk_put(dev->clk);
|
||||
|
||||
err_irq:
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
err_alloc:
|
||||
adc_free_host(dev->adc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk30_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk30_adc_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
if(dev->adc->base_client){
|
||||
adc_unregister(dev->adc->base_client);
|
||||
dev->adc->base_client = NULL;
|
||||
}
|
||||
iounmap(dev->regs);
|
||||
release_resource(dev->ioarea);
|
||||
kfree(dev->ioarea);
|
||||
free_irq(dev->irq, dev);
|
||||
clk_disable(dev->clk);
|
||||
clk_put(dev->clk);
|
||||
clk_disable(dev->pclk);
|
||||
clk_put(dev->pclk);
|
||||
adc_free_host(dev->adc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rk30_adc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct rk30_adc_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
dev->adc->is_suspended = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk30_adc_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct rk30_adc_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
dev->adc->is_suspended = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define rk30_adc_suspend NULL
|
||||
#define rk30_adc_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver rk30_adc_driver = {
|
||||
.driver = {
|
||||
.name = "rk30-adc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rk30_adc_probe,
|
||||
.remove = __devexit_p(rk30_adc_remove),
|
||||
.suspend = rk30_adc_suspend,
|
||||
.resume = rk30_adc_resume,
|
||||
};
|
||||
|
||||
static int __init rk30_adc_init(void)
|
||||
{
|
||||
return platform_driver_register(&rk30_adc_driver);
|
||||
}
|
||||
subsys_initcall(rk30_adc_init);
|
||||
|
||||
static void __exit rk30_adc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rk30_adc_driver);
|
||||
}
|
||||
module_exit(rk30_adc_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for ADC");
|
||||
MODULE_AUTHOR("kfx, kfx@rock-chips.com");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int __init adc_test_init(void)
|
||||
{
|
||||
printk("def_ref_volt: %dmV, curr_ref_volt: %dmV\n",
|
||||
adc_get_def_ref_volt(), adc_get_curr_ref_volt());
|
||||
#ifdef ADC_TEST
|
||||
rk30_adc_test();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
module_init(adc_test_init);
|
||||
@@ -1,29 +0,0 @@
|
||||
/* 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_RK30_ADC_H
|
||||
#define __ASM_RK30_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_DELAY_PU_SOC 0x0c
|
||||
#define ADC_CTRL_CH(ch) (ch >> SARADC_CHN_SHIFT) //(0x07 - ((ch)<<0))
|
||||
#define ADC_CTRL_POWER_UP (1<<3)
|
||||
#define ADC_CTRL_IRQ_ENABLE (1<<5)
|
||||
#define ADC_CTRL_IRQ_STATUS (1<<6)
|
||||
|
||||
#define ADC_CLK_RATE 1 //1M
|
||||
#define SAMPLE_RATE (20/ADC_CLK_RATE) //20 CLK
|
||||
|
||||
|
||||
#endif /* __ASM_RK30_ADC_H */
|
||||
@@ -1,81 +0,0 @@
|
||||
/* 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
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
enum host_chn_shift{
|
||||
SARADC_CHN_SHIFT = 0,
|
||||
CUSTOM_CHN_SHIFT = 28
|
||||
};
|
||||
|
||||
enum host_chn_mask{
|
||||
SARADC_CHN_MASK = 0x0000000f, // saradc: 0 -- 15
|
||||
CUSTOM_CHN_MASK = 0xf0000000,
|
||||
};
|
||||
|
||||
struct adc_host;
|
||||
struct adc_client {
|
||||
unsigned int index;
|
||||
unsigned int chn;
|
||||
unsigned int is_finished;
|
||||
unsigned int flags;
|
||||
int result;
|
||||
struct adc_host *adc;
|
||||
struct list_head list;
|
||||
wait_queue_head_t wait;
|
||||
void (*callback)(struct adc_client *, void *, int);
|
||||
void *callback_param;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
struct adc_client *adc_register(int chn,
|
||||
void (*callback)(struct adc_client *, void *, int),
|
||||
void *callback_param);
|
||||
void adc_unregister(struct adc_client *client);
|
||||
/*
|
||||
* function: adc_sync_read
|
||||
* 1)return value:
|
||||
* if correct, return adc sample value;
|
||||
* if error, return negative;
|
||||
*/
|
||||
int adc_sync_read(struct adc_client *client);
|
||||
/*
|
||||
* function: adc_async_read
|
||||
* 1)return value: if error, return negative; else return 0;
|
||||
* 2)adc sample value: the third parameter of callback.
|
||||
* if timeout, sample value is -1; else sample value is non-negative
|
||||
*/
|
||||
int adc_async_read(struct adc_client *client);
|
||||
/*
|
||||
* function: return current reference voltage, unit: mV
|
||||
*/
|
||||
int adc_get_curr_ref_volt(void);
|
||||
/*
|
||||
* function: return default reference voltage, unit: mV
|
||||
*/
|
||||
int adc_get_def_ref_volt(void);
|
||||
#else
|
||||
static inline struct adc_client *adc_register(int chn,
|
||||
void (*callback)(struct adc_client *, void *, int),
|
||||
void *callback_param)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void adc_unregister(struct adc_client *client) {}
|
||||
static inline int adc_sync_read(struct adc_client *client) { return -1; }
|
||||
static inline int adc_async_read(struct adc_client *client) { return -1; }
|
||||
static inline int adc_get_curr_ref_volt(void) { return -1; }
|
||||
static inline int adc_get_def_ref_volt(void) { return -1; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user