This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DM368 ADC driver

Hi Guy:

  Where are the DM368 adc driver to share. Thanks,

 

  • 3324.1018.ADC_driver.txt
    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,,, (shlomo at infodraw.com)");
     MODULE_LICENSE("GPL");
    
    --
    
    --
    adc.h
    
    /***************************************************************************
     *   Copyright (C) 2009 by Shlomo Kut,,,   *
     *   shlomo at 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;  
    }
    
    
    

  • Dear Ravikiran:

           I had use the above driver and insmod the ko. I got the error message the is "Unknown symbol in module (-1): No such file or d
    irectory". I adopt the dmesg and got error messsages. List below: 

    <4>adc: Unknown symbol proc_create
    <4>adc: Unknown symbol devm_request_mem_region
    <4>adc: Unknown symbol devm_ioremap_nocache

    I do not know what this, I am base on DM368 IPNC, Could help me , Thanks,

    Best Regards,

    Jemy

     

  • Try building it as inbuilt driver.  That should work :)

  • Dear Ravikiran:

    I can not find "devm_request_mem_region" and "devm_ioremap_nocache" in my kernel. I think may be my kernel is too old. Could you share your kernel to me, Thanks.
  • You can replace those calls with ioremap_nocache & request_mem_region respectively.