On Thu, 04 Jun 2009 06:45:22 -0000
"pratibha_275" wrote: > Hi! I got an ADC Driver file from the at91 SAM Portal
for my
> AT91SAM9260-EK. When i put it into the EK(insmod ARM_ADC.ko ...my ADC
> Driver), it gets inserted without giving any error, but i found
> no /dev/at91adc in EK, as i was expecting in my device.
So this is some variant of Linux? I run Linux with BusyBox as compiled
by Buildroot, and the solution to this (if your hotplug isn't fully
configured) is to run
mdev -s
after your modprobe or insmod.
Dan
Reply by pratibha_275●June 4, 20092009-06-04
Hi! I got an ADC Driver file from the at91 SAM Portal for my AT91SAM9260-EK.
When i put it into the EK(insmod ARM_ADC.ko ...my ADC Driver), it gets inserted
without giving any error, but i found no /dev/at91adc in EK, as i was expecting
in my device. And therefore i am not being able to read anything from ADC.I am
pasting my Driver here. Please HELP!
// Set the period between reads (max allowed value 1000)
#define SAMPLE_INTERVAL_MS 5
// Assume client always reads data at 1 second intervals; so the client will
read:
#define READ_SAMPLES 1000/SAMPLE_INTERVAL_MS
// Allocate to be at least 5 x bigger so that ISR will never catch up with
reading.
#define MAX_ADCSAMPLES 5* READ_SAMPLES
int at91adc_devno;
struct cdev at91adc_cdev;
struct file_operations at91adc_fops;
/*****************************************************************************************
| Timer counter 0 ISR: Sample both ADC channels and copy the data to module ring
buffer. |
*****************************************************************************************/
static irqreturn_t at91tc0_isr (int irq, void *dev_id)
{
int status;
//struct timeval time;
static int timecount = 0;
// Read TC0 status register to reset RC compare status.
status = ioread32(at91tc0_base + AT91_TC_SR);
// Trigger the ADC (this will be done using TIOA automatically eventually).
iowrite32(AT91_ADC_START, (at91adc_base + AT91_ADC_CR));
// Wait for conversion to be complete.
while ((ioread32(at91adc_base + AT91_ADC_SR) & AT91_ADC_DRDY) == 0)
cpu_relax();
// Copy converted data to module ring buffer.
at91adc_pbuf0[at91adc_appidx] = ioread32(at91adc_base + AT91_ADC_CHR(0));
at91adc_pbuf1[at91adc_appidx] = ioread32(at91adc_base + AT91_ADC_CHR(1));
// Increment the ring buffer index and check for wrap around.
at91adc_appidx += 1;
if (at91adc_appidx >= MAX_ADCSAMPLES) at91adc_appidx = 0;
}
//printk(KERN_INFO "Timer ISR\n");
return IRQ_HANDLED;
}
/*****************************************************************************************
| Module initialization: Allocate device numbers, register device, setup ADC and
timer |
| counter registers for 100 msec periodic sampling. |
*****************************************************************************************/
int init_module(void)
{
int ret;
// Dynamically allocate major number and minor number
ret = alloc_chrdev_region(&at91adc_devno,0,2, "at91adc");// pointer to where the
device number t
//be stored,first minor number requested,number of devices,device name
if (ret < 0)
{
printk(KERN_INFO "at91adc: Device number allocation failed\n");
ret = -ENODEV;
goto exit_1;
}
// Initialize cdev structure.
cdev_init(&at91adc_cdev,&at91adc_fops); // pointer to the cdev structure,
pointer to the file
//operations structure.
at91adc_cdev.owner = THIS_MODULE;
at91adc_cdev.ops = &at91adc_fops;
// Register the device with kernel
ret = cdev_add(&at91adc_cdev,at91adc_devno,2); // pointer to the initialized
cdev structure,
//device number allocated,number of devices
if (ret != 0)
{
printk(KERN_INFO "at91adc: Device registration failed\n");
ret = -ECANCELED;
goto exit_2;
}
// Character device driver initialization complete. Do device specific
initialization now.
// Allocate ring buffer memory for storing ADC values for both channels.
at91adc_pbuf0 = (unsigned short *)kmalloc((MAX_ADCSAMPLES * sizeof(unsigned
short)),GFP_KERNEL);
// Number of bytes,Flags
at91adc_pbuf1 = (unsigned short *)kmalloc((MAX_ADCSAMPLES * sizeof(unsigned
short)),GFP_KERNEL);
// Number of bytes, Flags
if ((at91adc_pbuf0 == NULL) || (at91adc_pbuf1 == NULL))
{
printk(KERN_INFO "at91adc: Memory allocation failed\n");
ret = -ECANCELED;
goto exit_3;
}
// Initialize the ring buffer and append index.
at91adc_appidx = 0;
for (ret = 0; ret < MAX_ADCSAMPLES; ret++)
{
at91adc_pbuf0[ret] = 0;
at91adc_pbuf1[ret] = 0;
}
// Initialize ADC. The following two lines set the appropriate PMC bit
// for the ADC. Easier than mapping PMC registers and then setting the bit.
at91adc_clk = clk_get(NULL, "adc_clk"); // Device pointer - not required.Clock
name.
clk_enable(at91adc_clk);
// Map ADC registers to the current address space.
at91adc_base = ioremap_nocache(AT91SAM9260_BASE_ADC, 64);// Physical
address,Number of bytes to be mapped.
if (at91adc_base == NULL)
{
printk(KERN_INFO "at91adc: ADC memory mapping failed\n");
ret = -EACCES;
goto exit_4;
}
// MUX GPIO pins for ADC (peripheral A) operation
at91_set_A_periph(AT91_PIN_PC0, 0);
at91_set_A_periph(AT91_PIN_PC1, 0);
// Reset the ADC
iowrite32(AT91_ADC_SWRST, (at91adc_base + AT91_ADC_CR));
// Configure ADC mode register.
// From table 43-31 in page #775 and page#741 of AT91SAM9260 user manual:
// Maximum ADC clock frequency = 5MHz = MCK / ((PRESCAL+1) * 2)
// PRESCAL = ((MCK / 5MHz) / 2) -1 = ((100MHz / 5MHz)/2)-1) = 9
// Maximum startup time = 15uS = (STARTUP+1)*8/ADC_CLOCK
// STARTUP = ((15uS*ADC_CLOK)/8)-1 = ((15uS*5MHz)/8)-1 = 9
// Minimum hold time = 1.2uS = (SHTIM+1)/ADC_CLOCK
// SHTIM = (1.2uS*ADC_CLOCK)-1 = (1.2uS*5MHz)-1 = 5, Use 9 to ensure 2uS hold
time.
// Enable sleep mode and hardware trigger from TIOA output from TC0.
iowrite32((AT91_ADC_SHTIM_(9) | AT91_ADC_STARTUP_(9) | AT91_ADC_PRESCAL_(9) |
AT91_ADC_SLEEP | AT91_ADC_TRGEN), (at91adc_base + AT91_ADC_MR));
// Initialize Timer Counter module 0. The following two lines set the
appropriate
// PMC bit for TC0. Easier than mapping PMC registers and then setting the
bit.
at91tc0_clk = clk_get(NULL, "tc0_clk"); // Device pointer - not required., Clock
name.
clk_enable(at91tc0_clk);
// Map TC0 registers to the current address space.
at91tc0_base = ioremap_nocache(AT91SAM9260_BASE_TC0, 64);// Physical
address,Number of bytes to be mapped.
if (at91tc0_base == NULL)
{
printk(KERN_INFO "at91adc: TC0 memory mapping failed\n");
ret = -EACCES;
goto exit_5;
}
// Configure TC0 in waveform mode, TIMER_CLK1 and to generate interrupt on RC
compare.
// Load 50000 to RC so that with TIMER_CLK1 = MCK/2 = 50MHz, the interrupt will
be
// generated every 1/50MHz * 50000 = 20nS * 50000 = 1 milli second.
// NOTE: Even though AT91_TC_RC is a 32-bit register, only 16-bits are
programmble.
// Install interrupt for TC0.
ret = request_irq(AT91SAM9260_ID_TC0,at91tc0_isr, 0, "at91adc", NULL);//
Interrupt number
// Pointer to the interrupt sub-routine, Flags - fast, shared or contributing
to entropy pool
// Device name to show as owner in /proc/interrupts,Private data for shared
interrupts
if (ret != 0)
{
printk(KERN_INFO "at91adc: Timer interrupt request failed\n");
ret = -EBUSY;
goto exit_6;
}