**************************************************************
*AtoD support for the at9260
*mwelling
*09/25/2007
*EMAC.Inc
**************************************************************
diff -uprN linux-2.6.20-at92_e1.2/arch/arm/mach-at91rm9200/atod-som9260m.c linux-2.6.20.snap/arch/arm/mach-at91rm9200/atod-som9260m.c
--- linux-2.6.20-at92_e1.2/arch/arm/mach-at91rm9200/atod-som9260m.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20.snap/arch/arm/mach-at91rm9200/atod-som9260m.c	2007-09-20 12:52:41.000000000 -0400
@@ -0,0 +1,97 @@
+/*
+ * arch/arm/mach-at91rm9200/atod-som9260m.c
+ * EMAC.Inc SOM9260m low level AtoD interactions
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ */
+
+
+#include "atod-som9260m.h"
+
+/* Global Variables Used in the Driver. */
+int drdy;
+void __iomem *adc_base;
+struct clk *adc_clk;
+
+
+int som9260m_atod_init(void){
+	
+	adc_clk = clk_get(NULL, "adc_clk");
+	clk_enable(adc_clk);
+
+	at91_set_A_periph(AT91_PIN_PC0,0);
+	at91_set_A_periph(AT91_PIN_PC1,0);
+	at91_set_A_periph(AT91_PIN_PC2,0);
+	at91_set_A_periph(AT91_PIN_PC3,0);
+	
+
+	//Set up the ADC
+	adc_base = ioremap(AT91SAM9260_BASE_ADC,SZ_16K);
+	__raw_writel((SHTIM << 24 | STARTUP << 16 | PRESCAL << 8 | SLEEP_MODE << 5 | 
+	LOWRES << 4 | TRGSEL << 1 | TRGEN), adc_base + ADC_MR); //Mode setup
+	__raw_writel((0x1 << 0)^(0xF), adc_base + ADC_CHDR);    //Disable Channels 1-3
+	__raw_writel((0x1 << 0), adc_base + ADC_CHER);     		//Enable Channel 0	
+	return 0;
+}
+
+int som9260m_atod_switch(int channel){
+	
+	__raw_writel((0x1 << channel)^(0xF), adc_base + ADC_CHDR);	//Disable Channels 		
+	__raw_writel((0x1 << channel), adc_base + ADC_CHER);	//Enable Channel
+	
+	return 0;
+}
+
+int som9260m_atod_read_current(void){
+	int data;
+	  
+	drdy = __raw_readl(adc_base + ADC_SR);
+	if (drdy & 0x10000){
+		data = __raw_readl(adc_base + ADC_LCDR);
+		return data;
+	}
+	else 
+		return -1;
+	
+	
+	
+	return (data);
+}
+
+static gpio_data atod_data_read(struct gpio_s *gpio){
+	int data;	
+	
+	
+	__raw_writel(0x02, adc_base + ADC_CR); //starts the conversion
+	
+	do {data = som9260m_atod_read_current();}
+	while(data==-1);//get first available data
+
+	return data;	
+}
+
+static gpio_data atod_index_read(struct gpio_s *gpio){
+	return gpio->index;
+}
+	
+static int atod_index_write(struct gpio_s *gpio,gpio_data index){
+	if(index>4)return -1;
+	if(index<0)return -1;
+	gpio->index = index;
+	som9260m_atod_switch(index);	
+	return 0;
+}
+
+struct class_device *som9260m_atod_class_create(const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = gpio_empty_write;
+	gpio->data_read = atod_data_read;
+	gpio->index_write = atod_index_write;
+	gpio->index_read = atod_index_read;
+	atod_index_write(gpio,0);
+	printk("registering indexed atod device: %s\n",name);
+	return gpio_register_class_device(gpio);
+}
diff -uprN linux-2.6.20-at92_e1.2/arch/arm/mach-at91rm9200/atod-som9260m.h linux-2.6.20.snap/arch/arm/mach-at91rm9200/atod-som9260m.h
--- linux-2.6.20-at92_e1.2/arch/arm/mach-at91rm9200/atod-som9260m.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20.snap/arch/arm/mach-at91rm9200/atod-som9260m.h	2007-09-20 12:52:41.000000000 -0400
@@ -0,0 +1,45 @@
+#ifndef ATODSOM9260M_H_
+#define ATODSOM9260M_H_
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <linux/class/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91sam9260.h>
+#include <asm/arch/gpio.h>
+
+
+#define ADC_CR          0x00    //Control Register Offset
+#define ADC_MR          0x04    //Mode Register Offset
+#define ADC_CHER        0x10    //Channel Enable Register Offset
+#define ADC_CHDR        0x14    //Channel Disable Register Offset
+#define ADC_CHSR        0x18    //Channel Status Register Offset
+#define ADC_SR          0x1C    //Status Register Offset
+#define ADC_LCDR        0x20    //Last Converted Data Register Offset
+#define ADC_IER         0x24    //Interrupt Enable Register Offset
+#define ADC_IDR         0x28    //Interrupt Disable Register Offset
+#define ADC_IMR         0x2C    //Interrupt Mask Register Offset
+#define ADC_CDR0        0x30    //Channel Data Register 0 Offset
+#define ADC_CDR1        0x34    //Channel Data Register 1 Offset
+#define ADC_CDR2        0x38    //Channel Data Register 2 Offset
+#define ADC_CDR3        0x3C    //Channel Data Register 3 Offset
+
+/* Define some of the values we will want in the registers
+ * This can be changed to reflect the needs of the driver
+ */
+
+#define TRGEN           0x00    //Trigger Enable
+#define TRGSEL          0x00    //Trigger Select
+#define LOWRES          0x00    //Resolution
+#define SLEEP_MODE      0x00    //Sleep Mode
+#define PRESCAL         0x22   //Prescaler Rate Selection (22 --> ~100 samples/sec)
+#define STARTUP         0x02    //Start Up Time
+#define SHTIM           0x00    //Sample and Hold Time
+
+
+int som9260m_atod_init(void);
+int som9260m_atod_switch(int channel);
+int som9260m_atod_read_current(void);
+struct class_device *som9260m_atod_class_create(const char *name);
+
+#endif /*ATODSOM9260M_H_*/


