From 9cf9a09c665ecfb6425a08e424b01c8cacbdb660 Mon Sep 17 00:00:00 2001 From: Jesse Gilles Date: Fri, 16 May 2014 16:43:44 -0500 Subject: Major changes to split sources up * moved common peripheral i/o functions to separate source files * moved device-specific setup to separate source files * removed LED blink functionality (unused) * mtcdp, mt100eocg are not supported, but code is included for possible future use --- io-module/adc.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 io-module/adc.c (limited to 'io-module/adc.c') diff --git a/io-module/adc.c b/io-module/adc.c new file mode 100644 index 0000000..bcb3598 --- /dev/null +++ b/io-module/adc.c @@ -0,0 +1,87 @@ + +#define ADC_SHTIME_DEFAULT 0x05 +#define ADC_STARTUP_DEFAULT 0x04 +#define ADC_PRESCALE_DEFAULT 0x3F +#define ADC_MODE_DEFAULT \ + ((ADC_SHTIME_DEFAULT & 0x0F) << 24) | \ + ((ADC_STARTUP_DEFAULT & 0x1F) << 16) | \ + ((ADC_PRESCALE_DEFAULT & 0x3F) << 8) + +#define ADC_CR_OFFSET 0x00 +#define ADC_MR_OFFSET 0x04 +#define ADC_CHER_OFFSET 0x10 +#define ADC_CHDR_OFFSET 0x14 +#define ADC_CHSR_OFFSET 0x18 +#define ADC_SR_OFFSET 0x1C +#define ADC_LDCR_OFFSET 0x20 +#define ADC_IER_OFFSET 0x14 +#define ADC_IDR_OFFSET 0x28 +#define ADC_IMR_OFFSET 0x2C +#define ADC_CDR0_OFFSET 0x30 +#define ADC_CDR1_OFFSET 0x34 +#define ADC_CDR2_OFFSET 0x38 +#define ADC_CDR3_OFFSET 0x3C + +void __iomem *adc_base; +struct clk *adc_clk; + +#define ADC_CONVERT_RESET(base) writel(0x01, (base) + ADC_CR_OFFSET) +#define ADC_CONVERT_START(base) writel(0x02, (base) + ADC_CR_OFFSET) + +static ssize_t mts_attr_show_adc(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int offset; + u32 value; + u32 chan_mask; + + if (!DEVICE_CAPA(id_eeprom.capa, CAPA_ADC)) { + log_debug("ADC not available"); + return -ENODEV; + } + + if (!strcmp(attr->attr.name, "adc0")) { + offset = ADC_CDR0_OFFSET; + chan_mask = 0x01; + } else if (!strcmp(attr->attr.name, "adc1")) { + offset = ADC_CDR1_OFFSET; + chan_mask = 0x02; + } else if (!strcmp(attr->attr.name, "adc2")) { + offset = ADC_CDR2_OFFSET; + chan_mask = 0x04; + } else if (!strcmp(attr->attr.name, "adc3")) { + offset = ADC_CDR3_OFFSET; + chan_mask = 0x08; + } else { + log_notice("adc attr does not exist"); + return -ENOENT; + } + + mutex_lock(&mts_io_mutex); + + // disable all channels and enable the one we want + writel(0x0F, adc_base + ADC_CHDR_OFFSET); + writel(chan_mask, adc_base + ADC_CHER_OFFSET); + + ADC_CONVERT_START(adc_base); + + // wait for conversion to complete (EOC bit set) + value = 0; + while (value != chan_mask) { + value = readl(adc_base + ADC_SR_OFFSET) & chan_mask; + log_debug("ADC_SR EOC [%X]", value); + } + + // read result + value = readl(adc_base + offset); + + mutex_unlock(&mts_io_mutex); + + return sprintf(buf, "%lu\n", (unsigned long) value); +} + +static DEVICE_ATTR_RO_MTS(dev_attr_adc0, "adc0", mts_attr_show_adc); +static DEVICE_ATTR_RO_MTS(dev_attr_adc1, "adc1", mts_attr_show_adc); +static DEVICE_ATTR_RO_MTS(dev_attr_adc2, "adc2", mts_attr_show_adc); +static DEVICE_ATTR_RO_MTS(dev_attr_adc3, "adc3", mts_attr_show_adc); -- cgit v1.2.3