summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--io-module/adc.c126
-rw-r--r--io-module/mt100eocg.c74
-rw-r--r--io-module/mts-io.c15
3 files changed, 174 insertions, 41 deletions
diff --git a/io-module/adc.c b/io-module/adc.c
new file mode 100644
index 0000000..3d5f3d0
--- /dev/null
+++ b/io-module/adc.c
@@ -0,0 +1,126 @@
+#define AT91SAM9X5_BASE_ADC 0xf804c000
+#define AT91SAM9260_BASE_ADC 0xfffe0000
+
+#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);
+
+static int mts_io_board_adc_probe(struct platform_device *pdev)
+{
+ int err;
+ adc_clk = clk_get(&pdev->dev, "adc_clk");
+ if (adc_clk) {
+ err = clk_prepare_enable(adc_clk);
+ if (err) {
+ log_error("clock failed to prepare+enable: %d\n", err);
+ return err;
+ }
+ #ifdef CONFIG_SOC_AT91SAM9X5
+ adc_base = ioremap(AT91SAM9X5_BASE_ADC, SZ_16K);
+ #else
+ adc_base = ioremap(AT91SAM9260_BASE_ADC, SZ_16K);
+ #endif
+ if (!adc_base) {
+ log_error("ioremap failed.\n");
+ return -ENOMEM;
+ }
+ ADC_CONVERT_RESET(adc_base);
+ writel(ADC_MODE_DEFAULT, adc_base + ADC_MR_OFFSET);
+ writel(0x000F0F0F, adc_base + ADC_IDR_OFFSET);
+ writel(0x0F, adc_base + ADC_CHDR_OFFSET);
+ }
+ return 0;
+}
+
+static int mts_io_board_adc_remove(struct platform_device *pdev)
+{
+ if (adc_clk) {
+ int ret;
+ clk_disable_unprepare(adc_clk);
+ }
+ return 0;
+}
+
diff --git a/io-module/mt100eocg.c b/io-module/mt100eocg.c
index ad22d22..749b85a 100644
--- a/io-module/mt100eocg.c
+++ b/io-module/mt100eocg.c
@@ -1,6 +1,38 @@
#include "at91gpio.h"
/* Used for both MT100EOCG 0.0 */
static struct gpio_pin gpio_pins_mt100eocg_0_0[] = {
+ {
+ .name = "ADC0",
+ .pin = {
+ .label = "adc0",
+ .gpio = AT91_PIN_PC0,
+ .flags = GPIOF_IN,
+ },
+ },
+ {
+ .name = "ADC1",
+ .pin = {
+ .label = "adc1",
+ .gpio = AT91_PIN_PC1,
+ .flags = GPIOF_IN,
+ },
+ },
+ {
+ .name = "ADC2",
+ .pin = {
+ .label = "adc2",
+ .gpio = AT91_PIN_PC2,
+ .flags = GPIOF_IN,
+ },
+ },
+ {
+ .name = "ADC3",
+ .pin = {
+ .label = "adc3",
+ .gpio = AT91_PIN_PC3,
+ .flags = GPIOF_IN,
+ },
+ },
{
.name = "DTR1",
.pin = {
@@ -101,38 +133,6 @@ static struct gpio_pin gpio_pins_mt100eocg_0_0[] = {
},
/*
{
- .name = "ADC0",
- .pin = {
- .label = "adc0",
- .gpio = AT91_PIN_PC0,
- .flags = GPIOF_IN,
- },
- },
- {
- .name = "ADC1",
- .pin = {
- .label = "adc1",
- .gpio = AT91_PIN_PC1,
- .flags = GPIOF_IN,
- },
- },
- {
- .name = "ADC2",
- .pin = {
- .label = "adc2",
- .gpio = AT91_PIN_PC2,
- .flags = GPIOF_IN,
- },
- },
- {
- .name = "ADC3",
- .pin = {
- .label = "adc3",
- .gpio = AT91_PIN_PC3,
- .flags = GPIOF_IN,
- },
- },
- {
.name = "TXD1",
.pin = {
.gpio = AT91_PIN_PB17,
@@ -216,10 +216,10 @@ static struct attribute *mt100eocg_platform_attributes[] = {
&dev_attr_gpo2.attr,
&dev_attr_gpo3.attr,
&dev_attr_gpo4.attr,
-//
+//
// SPI
&dev_attr_led1.attr,
-//
+//
&dev_attr_led2.attr, // AT91_PIN_PA30
&dev_attr_led3.attr, // AT91_PIN_PC9
// SPI
@@ -227,7 +227,7 @@ static struct attribute *mt100eocg_platform_attributes[] = {
&dev_attr_led5.attr,
&dev_attr_led6.attr,
//
-// SPI
+// SPI
&dev_attr_gpi5.attr,
&dev_attr_gpi6.attr,
&dev_attr_gpi7.attr,
@@ -238,12 +238,12 @@ static struct attribute *mt100eocg_platform_attributes[] = {
// SPI
&dev_attr_board_temperature.attr,
//
-/* adc
+// adc
&dev_attr_adc0.attr,
&dev_attr_adc1.attr,
&dev_attr_adc2.attr,
&dev_attr_adc3.attr,
-*/
+
NULL,
};
diff --git a/io-module/mts-io.c b/io-module/mts-io.c
index 489f0d5..8c35f74 100644
--- a/io-module/mts-io.c
+++ b/io-module/mts-io.c
@@ -23,7 +23,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/input.h>
@@ -74,6 +74,11 @@ static const struct of_device_id mts_io_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mts_io_dt_ids);
+/* on-board EEPROM */
+static struct mts_id_eeprom_layout id_eeprom;
+
+#include "adc.c"
+
/*
* We must call platform_set_drvdata, or else the
* devres_head for the driver has junk in it, and
@@ -86,7 +91,11 @@ MODULE_DEVICE_TABLE(of, mts_io_dt_ids);
*/
static int mts_io_probe(struct platform_device *pdev)
{
- return 0;
+ int ret = 0;
+ if (!DEVICE_CAPA(id_eeprom.capa, CAPA_ADC)) {
+ ret = mts_io_board_adc_probe(pdev);
+ }
+ return ret;
}
static int mts_io_remove(struct platform_device *pdev)
@@ -107,8 +116,6 @@ static struct platform_driver mts_io_driver = {
};
-/* on-board EEPROM */
-static struct mts_id_eeprom_layout id_eeprom;
static uint8_t mts_hw_version;
struct platform_device *mts_io_platform_device;
EXPORT_SYMBOL(mts_io_platform_device);