Hi,
I attach a simple standalone driver for the for the dm365 ADC in the
hope that it might prove useful.
Shlomo
----
adc_driver.c
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/mc146818rtc.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include "adc.h"
#define ADC_VERSION "1.0"
void *dm365_adc_base;
int adc_single(unsigned int channel)
{
if (channel >= ADC_MAX_CHANNELS)
return -1;
//select channel
iowrite32(1 << channel,dm365_adc_base + DM365_ADC_CHSEL);
//start coversion
iowrite32(DM365_ADC_ADCTL_BIT_START,dm365_adc_base +
DM365_ADC_ADCTL);
// Wait for conversion to start
while (!(ioread32(dm365_adc_base + DM365_ADC_ADCTL) &
DM365_ADC_ADCTL_BIT_BUSY)){
cpu_relax();
}
// Wait for conversion to be complete.
while ((ioread32(dm365_adc_base + DM365_ADC_ADCTL) &
DM365_ADC_ADCTL_BIT_BUSY)){
cpu_relax();
}
return ioread32(dm365_adc_base + DM365_ADC_AD0DAT + 4 * channel);
}
static spinlock_t adc_lock = SPIN_LOCK_UNLOCKED;
static void adc_read_block(unsigned short *data, size_t length)
{
int i;
spin_lock_irq(&adc_lock);
for(i = 0; i < length; i++) {
data [i] = adc_single(i);
}
spin_unlock_irq(&adc_lock);
}
#ifndef CONFIG_PROC_FS
static int adc_add_proc_fs(void)
{
return 0;
}
#else
static int adc_proc_read(struct seq_file *seq, void *offset)
{
int i;
unsigned short data [ADC_MAX_CHANNELS];
adc_read_block(data,ADC_MAX_CHANNELS);
for(i = 0; i < ADC_MAX_CHANNELS; i++) {
seq_printf(seq, "0x%04X\n", data[i]);
}
return 0;
}
static int adc_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, adc_proc_read, NULL);
}
static const struct file_operations adc_proc_fops = {
.owner = THIS_MODULE,
.open = adc_proc_open,
.read = seq_read,
.release = single_release,
};
static int adc_add_proc_fs(void)
{
if (!proc_create("driver/adc", 0, NULL, &adc_proc_fops))
return -ENOMEM;
return 0;
}
#endif /* CONFIG_PROC_FS */
static ssize_t adc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned short data [ADC_MAX_CHANNELS];
if (count < sizeof(unsigned short))
return -ETOOSMALL;
adc_read_block(data,ADC_MAX_CHANNELS);
if (copy_to_user(buf, data, count))
return -EFAULT;
return count;
}
static int adc_open(struct inode *inode, struct file *file)
{
return 0;
}
static int adc_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations adc_fops = {
.owner = THIS_MODULE,
.read = adc_read,
.open = adc_open,
.release = adc_release,
};
static struct miscdevice adc_dev = {
NVRAM_MINOR,
"adc",
&adc_fops
};
static int adc_init_module(void)
{
int ret;
ret = misc_register(&adc_dev);
if (ret) {
printk(KERN_ERR "adc: can't misc_register on minor=%d\n",
NVRAM_MINOR);
return ret;
}
ret = adc_add_proc_fs();
if (ret) {
misc_deregister(&adc_dev);
printk(KERN_ERR "adc: can't create /proc/driver/adc\n");
return ret;
}
if (!devm_request_mem_region(adc_dev.this_device,
DM365_ADC_BASE,64,"adc"))
return -EBUSY;
dm365_adc_base =
devm_ioremap_nocache(adc_dev.this_device,DM365_ADC_BASE, 64);// Physical
address,Number of bytes to be mapped.
if (!dm365_adc_base)
return -ENOMEM;
printk(KERN_INFO "TI Davinci ADC v" ADC_VERSION "\n");
return 0;
}
static void adc_exit_module(void)
{
remove_proc_entry("driver/adc", NULL);
misc_deregister(&adc_dev);
printk( KERN_DEBUG "Module adc exit\n" );
}
module_init(adc_init_module);
module_exit(adc_exit_module);
MODULE_DESCRIPTION("TI Davinci Dm365 ADC");
MODULE_AUTHOR("Shlomo Kut,,, ([email protected])");
MODULE_LICENSE("GPL");
--
--
adc.h
/***************************************************************************
* Copyright (C) 2009 by Shlomo Kut,,, *
* shl...@shlomo-desktop *
*
*
* This program is free software; you can redistribute it and/or
modify *
* it under the terms of the GNU General Public License as published
by *
* the Free Software Foundation; either version 2 of the License, or
*
* (at your option) any later version.
*
*
*
* This program is distributed in the hope that it will be useful,
*
* but WITHOUT ANY WARRANTY; without even the implied warranty of
*
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*
* GNU General Public License for more details.
*
*
*
* You should have received a copy of the GNU General Public License
*
* along with this program; if not, write to the
*
* Free Software Foundation, Inc.,
*
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
***************************************************************************/
#ifndef _ADC_h
#define _ADC_H
#define ADC_MAX_CHANNELS 6
int adc_single(unsigned int channel);
#define DM365_ADC_BASE (0x01C23C00)
#define DM365_ADC_ADCTL 0x0
#define DM365_ADC_ADCTL_BIT_BUSY (1 << 7)
#define DM365_ADC_ADCTL_BIT_CMPFLG (1 << 6)
#define DM365_ADC_ADCTL_BIT_CMPIEN (1 << 5)
#define DM365_ADC_ADCTL_BIT_CMPMD (1 << 4)
#define DM365_ADC_ADCTL_BIT_SCNFLG (1 << 3)
#define DM365_ADC_ADCTL_BIT_SCNIEN (1 << 2)
#define DM365_ADC_ADCTL_BIT_SCNMD (1 << 1)
#define DM365_ADC_ADCTL_BIT_START (1 << 0)
#define DM365_ADC_CMPTGT 0x4
#define DM365_ADC_CMPLDAT 0x8
#define DM365_ADC_CMPHDAT 0xC
#define DM365_ADC_SETDIV 0x10
#define DM365_ADC_CHSEL 0x14
#define DM365_ADC_AD0DAT 0x18
#define DM365_ADC_AD1DAT 0x1C
#define DM365_ADC_AD2DAT 0x20
#define DM365_ADC_AD3DAT 0x24
#define DM365_ADC_AD4DAT 0x28
#define DM365_ADC_AD5DAT 0x2C
#define DM365_ADC_EMUCTRL 0x30
#endif //_ADC_H
----
test.c
//
//test program for adc driver
//
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "../driver/adc.h"
int main (int argc, char **argv)
{
int res,i,fd;
unsigned short data [ADC_MAX_CHANNELS];
printf("testing adc driver..\n");
fd = open("/dev/adc",O_RDONLY);
if (fd < 0) {
perror("open /dev/fdc");
return 1;
}
res = read(fd,data,sizeof(data));
if (res != sizeof(data)) {
perror("read failed");
close(fd);
return 1;
}
printf("raw data:");
for( i = 0; i < ADC_MAX_CHANNELS; i++){
printf("0x%08X ",data [i]);
}
printf("\n");
printf("converted data:");
for( i = 0; i < ADC_MAX_CHANNELS; i++){
double vref = 1.8;
double max_raw = 1 << 10;
double volts = (double) data [i] * vref / max_raw;
printf("%1.3fV ",volts);
}
printf("\n");
close(fd);
return 0;
}
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source