drivers: remove unused adc driver

Change-Id: I71a79cf4372d2645537e3b8d19253487eb9039a2
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
This commit is contained in:
Tao Huang
2018-11-01 14:20:07 +08:00
parent 96ab43200d
commit e8f64bc63e
13 changed files with 0 additions and 1399 deletions

View File

@@ -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

View File

@@ -1,8 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the adc core.
#
obj-$(CONFIG_ADC) += core.o
obj-y += plat/

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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");

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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