Revision: 19 http://acme-dev.svn.sourceforge.net/acme-dev/?rev=19&view=rev Author: claudyus Date: 2010-02-16 11:39:30 +0000 (Tue, 16 Feb 2010) Log Message: ----------- kernel: adc draft module Modified Paths: -------------- kernel-stuff/adc-driver/at91-adc.c Added Paths: ----------- kernel-stuff/adc-driver/Makefile kernel-stuff/adc-driver/at91_adc.h kernel-stuff/adc-driver/at91_tc.h Property Changed: ---------------- kernel-stuff/adc-driver/ Property changes on: kernel-stuff/adc-driver ___________________________________________________________________ Added: svn:ignore + .at91-adc.o.d Added: kernel-stuff/adc-driver/Makefile =================================================================== --- kernel-stuff/adc-driver/Makefile (rev 0) +++ kernel-stuff/adc-driver/Makefile 2010-02-16 11:39:30 UTC (rev 19) @@ -0,0 +1,8 @@ +obj-m := at91-adc.o + +KERNELDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +all default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + Modified: kernel-stuff/adc-driver/at91-adc.c =================================================================== --- kernel-stuff/adc-driver/at91-adc.c 2010-02-15 22:37:16 UTC (rev 18) +++ kernel-stuff/adc-driver/at91-adc.c 2010-02-16 11:39:30 UTC (rev 19) @@ -1,4 +1,16 @@ -/* Driver for ADC on the AT91SAM9260-EK +/* + * Driver for ADC on the FoxBoardG20 + * + * Copyright (R) 2010 - Claudio Mignanti + * + * Based on http://www.at91.com/forum/viewtopic.php/p,9409/#p9409 + * + * 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. + * + * $Id$ + * --------------------------------------------------------------------------- */ #include <linux/module.h> @@ -11,106 +23,72 @@ #include <asm/uaccess.h> #include <asm/io.h> -#include <asm/arch/at91_tc.h> -#include <asm/arch/at91_adc.h> -#define MAX_SAMPLES 128000 -#define CASE1 1 -#define CASE2 2 -#define CASE3 3 +#include "at91_adc.h" +#include "at91_tc.h" -void __iomem *adc_base; -struct clk *adc_clk; -struct clk *tc1_clk; -void __iomem *tc1_base; +#define ADC_MAJOR 178 +#define ADC_NAME "at91-adc" -static struct work_struct adc_wq; -int dex, rate; -unsigned char *adc_val; -DECLARE_COMPLETION(acquisition_complete); +#define ADC_REQUEST 1 +#define ADC_READ 2 -//Adc Work censored Tasklet -static void adc_do_tasklet(struct work_struct *work) -{ - int clk_tic; +void __iomem *adc_base; +struct clk *adc_clk; - clk_enable(tc1_clk); //Power the timer - dex = 0; - while(!at91_get_gpio_value(AT91_PIN_PA30) && (dex < MAX_SAMPLES)) - { - __raw_writel(AT91_TC_CLKEN | AT91_ADC_SWTRG, tc1_base + AT91_TC_CCR); - clk_tic = __raw_readl(tc1_base + AT91_TC_CV); - while(clk_tic < rate)//6250 for 8k - clk_tic = __raw_readl(tc1_base + AT91_TC_CV); - adc_val[dex] = channel0_read(); - dex++; - } - clk_disable(tc1_clk); - complete(&acquisition_complete); -} -//Interrupt Handler for Button 3 -static irqreturn_t btn3_int(int irq, void *dev_id) -{ - if (at91_get_gpio_value(AT91_PIN_PA30) == 0) - { - at91_set_gpio_value(AT91_PIN_PA6,0); //Turn LED on - schedule_work(&adc_wq); - } - else - { - at91_set_gpio_value(AT91_PIN_PA6,1); //Turn LED off - } - - return IRQ_HANDLED; -} - /* Function to read last conversion of channel 0*/ -static inline unsigned char channel0_read(void) -{ +static int read_chan (int chan) +{ + int val; + /* TODO: support for chan */ __raw_writel(0x02, adc_base + AT91_ADC_CR); //Start the ADC - while(!at91_adc_drdy()) //Is conversion ready? + while(!__raw_readl(adc_base + AT91_ADC_EOC(chan))) //Is conversion ready? cpu_relax(); - return __raw_readl(adc_base + AT91_ADC_CDR0); //Read & Return the conversion + val= __raw_readl(adc_base + AT91_ADC_CHR(chan)); //Read & Return the conversion + + return val; } -/* Function to check if DRDY is set */ -static inline int at91_adc_drdy(void) -{ - int drdy; - drdy = __raw_readl(adc_base + AT91_ADC_SR); - if (AT91_ADC_EOC(1)) - return 1; - else - return 0; -} +/* PC0 -> AD0 + PC1 AD1 + PC2 AD2 + PC3 AD3 */ +static int request_chan (int chan) { -/* ADC Open */ -static int adc_open(struct inode *inode, struct file *filp) -{ - return 0; -} + int pin_chan; -/* ADC Release */ -static int adc_release(struct inode *inode, struct file *filp) -{ - return 0; -} + switch (chan) { + case 0: + pin_chan=AT91_PIN_PC0; + break; + case 1: + pin_chan=AT91_PIN_PC1; + break; + case 2: + pin_chan=AT91_PIN_PC2; + break; + case 3: + pin_chan=AT91_PIN_PC3; + break; + default: + return -EINVAL; + } -/* ADC Read */ -static ssize_t adc_read(struct file *filp, char __iomem *buf, - size_t count, loff_t *f_pos) -{ - if (count < sizeof(adc_val)) - return -EINVAL; + at91_set_A_periph(pin_chan, 0); //Mux PIN to GPIO - /* Wait for workqueue to signal data is ready */ - wait_for_completion(&acquisition_complete); - if (copy_to_user(buf, adc_val, dex * sizeof(unsigned char))) - return -EFAULT; - return dex; + adc_base = ioremap(AT91SAM9260_BASE_ADC, SZ_16K); //Map the mem region + __raw_writel(0x01, adc_base + AT91_ADC_CR); //Reset the ADC + __raw_writel(( AT91_ADC_SHTIM | AT91_ADC_STARTUP | AT91_ADC_PRESCAL | \ + AT91_ADC_SLEEP | AT91_ADC_LOWRES | AT91_ADC_TRGSEL | \ + AT91_ADC_TRGEN), adc_base + AT91_ADC_MR); //Mode setup + + //__raw_writel(CH_EN, adc_base + AT91_ADC_CHER); ??? //Enable Channels + //__raw_writel(CH_DIS, adc_base + AT91_ADC_CHDR); //Disable Channels + + return 0; } // ioctl - I/O control @@ -118,15 +96,12 @@ unsigned int cmd, unsigned long arg) { int retval = 0; switch ( cmd ) { - case CASE1:/* 10K sample rate*/ - rate = 5000; + case ADC_REQUEST: + return request_chan ((int)arg); break; - case CASE2:/* 16K sample rate*/ - rate = 3125; + case ADC_READ: + return read_chan ((int)arg); break; - case CASE3: - rate = 1563; - break; default: retval = -EINVAL; } @@ -135,73 +110,41 @@ struct file_operations adc_fops = { .owner = THIS_MODULE, - .read = adc_read, - .open = adc_open, .ioctl = adc_ioctl, - .release = adc_release, }; /* Module Cleanup Function */ static void adc_exit(void) { - clk_disable(adc_clk); //Turn off ADC clock - clk_put(adc_clk); + clk_disable(adc_clk); //Turn off ADC clock iounmap(adc_base); //Unmap the ADC mem region unregister_chrdev (ADC_MAJOR, ADC_NAME); //Free the major,minor numbers -// free_irq(AT91_PIN_PA30, NULL); //Free the interrupt - kfree(adc_val); } /* Module initialization function */ static int adc_init(void) { int result; - adc_val = (unsigned char *) kmalloc(MAX_SAMPLES, GFP_KERNEL); /* ADC Set Up */ - adc_clk = clk_get(NULL, "adc_clk"); //Start ADC Clock + adc_clk = clk_get(NULL, "adc_clk"); clk_enable(adc_clk); - at91_set_A_periph(AT91_PIN_PC0,0); //Mux ADC0 to GPIO - - adc_base = ioremap(AT91SAM9260_BASE_ADC, SZ_16K); //Map the mem region - __raw_writel(0x01, adc_base + AT91_ADC_CR); //Reset the ADC - __raw_writel(( AT91_ADC_SHTIM | AT91_ADC_STARTUP | AT91_ADC_PRESCAL | \ - AT91_ADC_SLEEP | AT91_ADC_LOWRES | AT91_ADC_TRGSEL | \ - AT91_ADC_TRGEN), adc_base + AT91_ADC_MR); //Mode setup - - __raw_writel(CH_EN, adc_base + AT91_ADC_CHER); //Enable Channels - __raw_writel(CH_DIS, adc_base + AT91_ADC_CHDR); //Disable Channels - - //Get dynamic major number and a minor number + /*Get dynamic major number and a minor number */ result = register_chrdev(ADC_MAJOR, ADC_NAME, &adc_fops); if(result < 0){ printk(KERN_WARNING "adc: can't get major %d\n", ADC_MAJOR); return result; } - /* Set up of other devices around ADC for user i/o */ - at91_set_gpio_input(AT91_PIN_PA30,1); //Set user button 3 as input - at91_set_gpio_output(AT91_PIN_PA6,1); //Set user LED as output - at91_set_deglitch(AT91_PIN_PA30,1); //Set glitch filter on button 3 - //Request IRQ's for the button - if (request_irq(AT91_PIN_PA30, btn3_int, 0, "btn3", NULL)) - return -EBUSY; - - //Initialize the work censored - INIT_WORK(&adc_wq, adc_do_tasklet); - - /* Set up Timer Counter 0 */ - tc1_clk = clk_get(NULL, "tc1_clk"); - tc1_base = ioremap(AT91SAM9260_BASE_TC1,64); //Map the mem region - __raw_writel(0x01, tc1_base + AT91_TC_CCR); - return 0; } + module_init(adc_init); module_exit(adc_exit); MODULE_AUTHOR("Paul Kavan"); -MODULE_DESCRIPTION("ADC Driver for the Demo0"); +MODULE_AUTHOR("Claudio Mignanti"); +MODULE_DESCRIPTION("ADC Driver for the FoxBoardG20"); MODULE_LICENSE("GPL"); Added: kernel-stuff/adc-driver/at91_adc.h =================================================================== --- kernel-stuff/adc-driver/at91_adc.h (rev 0) +++ kernel-stuff/adc-driver/at91_adc.h 2010-02-16 11:39:30 UTC (rev 19) @@ -0,0 +1,62 @@ +/* + * include/asm-arm/arch-at91/at91_adc.h + * + * Copyright (C) SAN People + * + * Analog-to-Digital Converter (ADC) registers. + * Based on AT91SAM9260 datasheet revision D. + * + * 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. + */ + +#ifndef AT91_ADC_H +#define AT91_ADC_H + +#define AT91_ADC_CR 0x00 /* Control Register */ +#define AT91_ADC_SWRST (1 << 0) /* Software Reset */ +#define AT91_ADC_START (1 << 1) /* Start Conversion */ + +#define AT91_ADC_MR 0x04 /* Mode Register */ +#define AT91_ADC_TRGEN (1 << 0) /* Trigger Enable */ +#define AT91_ADC_TRGSEL (7 << 1) /* Trigger Selection */ +#define AT91_ADC_TRGSEL_TC0 (0 << 1) +#define AT91_ADC_TRGSEL_TC1 (1 << 1) +#define AT91_ADC_TRGSEL_TC2 (2 << 1) +#define AT91_ADC_TRGSEL_EXTERNAL (6 << 1) +#define AT91_ADC_LOWRES (1 << 4) /* Low Resolution */ +#define AT91_ADC_SLEEP (1 << 5) /* Sleep Mode */ +#define AT91_ADC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ +#define AT91_ADC_PRESCAL_(x) ((x) << 8) +#define AT91_ADC_STARTUP (0x1f << 16) /* Startup Up Time */ +#define AT91_ADC_STARTUP_(x) ((x) << 16) +#define AT91_ADC_SHTIM (0xf << 24) /* Sample & Hold Time */ +#define AT91_ADC_SHTIM_(x) ((x) << 24) + +#define AT91_ADC_CHER 0x10 /* Channel Enable Register */ +#define AT91_ADC_CHDR 0x14 /* Channel Disable Register */ +#define AT91_ADC_CHSR 0x18 /* Channel Status Register */ +#define AT91_ADC_CH(n) (1 << (n)) /* Channel Number */ + +#define AT91_ADC_SR 0x1C /* Status Register */ +#define AT91_ADC_EOC(n) (1 << (n)) /* End of Conversion on Channel N */ +#define AT91_ADC_OVRE(n) (1 << ((n) + 8))/* Overrun Error on Channel N */ +#define AT91_ADC_DRDY (1 << 16) /* Data Ready */ +#define AT91_ADC_GOVRE (1 << 17) /* General Overrun Error */ +#define AT91_ADC_ENDRX (1 << 18) /* End of RX Buffer */ +#define AT91_ADC_RXFUFF (1 << 19) /* RX Buffer Full */ + +#define AT91_ADC_LCDR 0x20 /* Last Converted Data Register */ +#define AT91_ADC_LDATA (0x3ff) + +#define AT91_ADC_IER 0x24 /* Interrupt Enable Register */ +#define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */ +#define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */ + +#define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */ +#define AT91_ADC_DATA (0x3ff) + +#endif + Added: kernel-stuff/adc-driver/at91_tc.h =================================================================== --- kernel-stuff/adc-driver/at91_tc.h (rev 0) +++ kernel-stuff/adc-driver/at91_tc.h 2010-02-16 11:39:30 UTC (rev 19) @@ -0,0 +1,146 @@ +/* + * arch/arm/mach-at91/include/mach/at91_tc.h + * + * Copyright (C) SAN People + * + * Timer/Counter Unit (TC) registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91_TC_H +#define AT91_TC_H + +#define AT91_TC_BCR 0xc0 /* TC Block Control Register */ +#define AT91_TC_SYNC (1 << 0) /* Synchro Command */ + +#define AT91_TC_BMR 0xc4 /* TC Block Mode Register */ +#define AT91_TC_TC0XC0S (3 << 0) /* External Clock Signal 0 Selection */ +#define AT91_TC_TC0XC0S_TCLK0 (0 << 0) +#define AT91_TC_TC0XC0S_NONE (1 << 0) +#define AT91_TC_TC0XC0S_TIOA1 (2 << 0) +#define AT91_TC_TC0XC0S_TIOA2 (3 << 0) +#define AT91_TC_TC1XC1S (3 << 2) /* External Clock Signal 1 Selection */ +#define AT91_TC_TC1XC1S_TCLK1 (0 << 2) +#define AT91_TC_TC1XC1S_NONE (1 << 2) +#define AT91_TC_TC1XC1S_TIOA0 (2 << 2) +#define AT91_TC_TC1XC1S_TIOA2 (3 << 2) +#define AT91_TC_TC2XC2S (3 << 4) /* External Clock Signal 2 Selection */ +#define AT91_TC_TC2XC2S_TCLK2 (0 << 4) +#define AT91_TC_TC2XC2S_NONE (1 << 4) +#define AT91_TC_TC2XC2S_TIOA0 (2 << 4) +#define AT91_TC_TC2XC2S_TIOA1 (3 << 4) + + +#define AT91_TC_CCR 0x00 /* Channel Control Register */ +#define AT91_TC_CLKEN (1 << 0) /* Counter Clock Enable Command */ +#define AT91_TC_CLKDIS (1 << 1) /* Counter CLock Disable Command */ +#define AT91_TC_SWTRG (1 << 2) /* Software Trigger Command */ + +#define AT91_TC_CMR 0x04 /* Channel Mode Register */ +#define AT91_TC_TCCLKS (7 << 0) /* Capture/Waveform Mode: Clock Selection */ +#define AT91_TC_TIMER_CLOCK1 (0 << 0) +#define AT91_TC_TIMER_CLOCK2 (1 << 0) +#define AT91_TC_TIMER_CLOCK3 (2 << 0) +#define AT91_TC_TIMER_CLOCK4 (3 << 0) +#define AT91_TC_TIMER_CLOCK5 (4 << 0) +#define AT91_TC_XC0 (5 << 0) +#define AT91_TC_XC1 (6 << 0) +#define AT91_TC_XC2 (7 << 0) +#define AT91_TC_CLKI (1 << 3) /* Capture/Waveform Mode: Clock Invert */ +#define AT91_TC_BURST (3 << 4) /* Capture/Waveform Mode: Burst Signal Selection */ +#define AT91_TC_LDBSTOP (1 << 6) /* Capture Mode: Counter Clock Stopped with TB Loading */ +#define AT91_TC_LDBDIS (1 << 7) /* Capture Mode: Counter Clock Disable with RB Loading */ +#define AT91_TC_ETRGEDG (3 << 8) /* Capture Mode: External Trigger Edge Selection */ +#define AT91_TC_ABETRG (1 << 10) /* Capture Mode: TIOA or TIOB External Trigger Selection */ +#define AT91_TC_CPCTRG (1 << 14) /* Capture Mode: RC Compare Trigger Enable */ +#define AT91_TC_WAVE (1 << 15) /* Capture/Waveform mode */ +#define AT91_TC_LDRA (3 << 16) /* Capture Mode: RA Loading Selection */ +#define AT91_TC_LDRB (3 << 18) /* Capture Mode: RB Loading Selection */ + +#define AT91_TC_CPCSTOP (1 << 6) /* Waveform Mode: Counter Clock Stopped with RC Compare */ +#define AT91_TC_CPCDIS (1 << 7) /* Waveform Mode: Counter Clock Disable with RC Compare */ +#define AT91_TC_EEVTEDG (3 << 8) /* Waveform Mode: External Event Edge Selection */ +#define AT91_TC_EEVTEDG_NONE (0 << 8) +#define AT91_TC_EEVTEDG_RISING (1 << 8) +#define AT91_TC_EEVTEDG_FALLING (2 << 8) +#define AT91_TC_EEVTEDG_BOTH (3 << 8) +#define AT91_TC_EEVT (3 << 10) /* Waveform Mode: External Event Selection */ +#define AT91_TC_EEVT_TIOB (0 << 10) +#define AT91_TC_EEVT_XC0 (1 << 10) +#define AT91_TC_EEVT_XC1 (2 << 10) +#define AT91_TC_EEVT_XC2 (3 << 10) +#define AT91_TC_ENETRG (1 << 12) /* Waveform Mode: External Event Trigger Enable */ +#define AT91_TC_WAVESEL (3 << 13) /* Waveform Mode: Waveform Selection */ +#define AT91_TC_WAVESEL_UP (0 << 13) +#define AT91_TC_WAVESEL_UP_AUTO (2 << 13) +#define AT91_TC_WAVESEL_UPDOWN (1 << 13) +#define AT91_TC_WAVESEL_UPDOWN_AUTO (3 << 13) +#define AT91_TC_ACPA (3 << 16) /* Waveform Mode: RA Compare Effect on TIOA */ +#define AT91_TC_ACPA_NONE (0 << 16) +#define AT91_TC_ACPA_SET (1 << 16) +#define AT91_TC_ACPA_CLEAR (2 << 16) +#define AT91_TC_ACPA_TOGGLE (3 << 16) +#define AT91_TC_ACPC (3 << 18) /* Waveform Mode: RC Compre Effect on TIOA */ +#define AT91_TC_ACPC_NONE (0 << 18) +#define AT91_TC_ACPC_SET (1 << 18) +#define AT91_TC_ACPC_CLEAR (2 << 18) +#define AT91_TC_ACPC_TOGGLE (3 << 18) +#define AT91_TC_AEEVT (3 << 20) /* Waveform Mode: External Event Effect on TIOA */ +#define AT91_TC_AEEVT_NONE (0 << 20) +#define AT91_TC_AEEVT_SET (1 << 20) +#define AT91_TC_AEEVT_CLEAR (2 << 20) +#define AT91_TC_AEEVT_TOGGLE (3 << 20) +#define AT91_TC_ASWTRG (3 << 22) /* Waveform Mode: Software Trigger Effect on TIOA */ +#define AT91_TC_ASWTRG_NONE (0 << 22) +#define AT91_TC_ASWTRG_SET (1 << 22) +#define AT91_TC_ASWTRG_CLEAR (2 << 22) +#define AT91_TC_ASWTRG_TOGGLE (3 << 22) +#define AT91_TC_BCPB (3 << 24) /* Waveform Mode: RB Compare Effect on TIOB */ +#define AT91_TC_BCPB_NONE (0 << 24) +#define AT91_TC_BCPB_SET (1 << 24) +#define AT91_TC_BCPB_CLEAR (2 << 24) +#define AT91_TC_BCPB_TOGGLE (3 << 24) +#define AT91_TC_BCPC (3 << 26) /* Waveform Mode: RC Compare Effect on TIOB */ +#define AT91_TC_BCPC_NONE (0 << 26) +#define AT91_TC_BCPC_SET (1 << 26) +#define AT91_TC_BCPC_CLEAR (2 << 26) +#define AT91_TC_BCPC_TOGGLE (3 << 26) +#define AT91_TC_BEEVT (3 << 28) /* Waveform Mode: External Event Effect on TIOB */ +#define AT91_TC_BEEVT_NONE (0 << 28) +#define AT91_TC_BEEVT_SET (1 << 28) +#define AT91_TC_BEEVT_CLEAR (2 << 28) +#define AT91_TC_BEEVT_TOGGLE (3 << 28) +#define AT91_TC_BSWTRG (3 << 30) /* Waveform Mode: Software Trigger Effect on TIOB */ +#define AT91_TC_BSWTRG_NONE (0 << 30) +#define AT91_TC_BSWTRG_SET (1 << 30) +#define AT91_TC_BSWTRG_CLEAR (2 << 30) +#define AT91_TC_BSWTRG_TOGGLE (3 << 30) + +#define AT91_TC_CV 0x10 /* Counter Value */ +#define AT91_TC_RA 0x14 /* Register A */ +#define AT91_TC_RB 0x18 /* Register B */ +#define AT91_TC_RC 0x1c /* Register C */ + +#define AT91_TC_SR 0x20 /* Status Register */ +#define AT91_TC_COVFS (1 << 0) /* Counter Overflow Status */ +#define AT91_TC_LOVRS (1 << 1) /* Load Overrun Status */ +#define AT91_TC_CPAS (1 << 2) /* RA Compare Status */ +#define AT91_TC_CPBS (1 << 3) /* RB Compare Status */ +#define AT91_TC_CPCS (1 << 4) /* RC Compare Status */ +#define AT91_TC_LDRAS (1 << 5) /* RA Loading Status */ +#define AT91_TC_LDRBS (1 << 6) /* RB Loading Status */ +#define AT91_TC_ETRGS (1 << 7) /* External Trigger Status */ +#define AT91_TC_CLKSTA (1 << 16) /* Clock Enabling Status */ +#define AT91_TC_MTIOA (1 << 17) /* TIOA Mirror */ +#define AT91_TC_MTIOB (1 << 18) /* TIOB Mirror */ + +#define AT91_TC_IER 0x24 /* Interrupt Enable Register */ +#define AT91_TC_IDR 0x28 /* Interrupt Disable Register */ +#define AT91_TC_IMR 0x2c /* Interrupt Mask Register */ + +#endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.