From 7220a7235e7b6722fb7dc6e8f599a20bac224760 Mon Sep 17 00:00:00 2001 From: Matthieu Crapet Date: Sun, 4 Jan 2009 01:32:39 +0100 Subject: [PATCH] TS-72xx MAX197 support MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Signed-off-by: Petr Štetiar --- arch/arm/mach-ep93xx/include/mach/ts72xx.h | 8 + arch/arm/mach-ep93xx/ts72xx.c | 27 ++++ drivers/misc/Kconfig | 21 +++ drivers/misc/Makefile | 1 + drivers/misc/ts72xx_max197.c | 235 ++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+), 0 deletions(-) create mode 100644 drivers/misc/ts72xx_max197.c diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h index bb67506..28372df 100644 --- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h +++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h @@ -87,6 +87,14 @@ #define TS72XX_WATCHDOG_FEED_PHYS_BASE 0x23c00000 #define TS72XX_WATCHDOG_FEED_SIZE 0x00001000 +#define TS72XX_JUMPERS_MAX197_VIRT_BASE 0xfebf2000 +#define TS72XX_JUMPERS_MAX197_PHYS_BASE 0x10800000 +#define TS72XX_JUMPERS_MAX197_SIZE 0x00001000 + +#define TS72XX_MAX197_SAMPLE_VIRT_BASE 0xfebf1000 +#define TS72XX_MAX197_SAMPLE_PHYS_BASE 0x10f00000 +#define TS72XX_MAX197_SAMPLE_SIZE 0x00001000 + #ifndef __ASSEMBLY__ #include diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index a9d3939..ea3deeb 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -205,6 +205,29 @@ static struct platform_device ts72xx_watchdog_device = { .resource = ts72xx_watchdog_resources, }; +static struct resource ts72xx_max197_resources[] = { + [0] = { /* sample/control register */ + .start = TS72XX_MAX197_SAMPLE_PHYS_BASE, + .end = TS72XX_MAX197_SAMPLE_PHYS_BASE + TS72XX_MAX197_SAMPLE_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { /* busy bit */ + .start = TS72XX_JUMPERS_MAX197_PHYS_BASE, + .end = TS72XX_JUMPERS_MAX197_PHYS_BASE + TS72XX_JUMPERS_MAX197_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ts72xx_max197_device = { + .name = "ts72xx-max197", + .id = -1, + .dev = { + .platform_data = NULL, + }, + .num_resources = ARRAY_SIZE(ts72xx_max197_resources), + .resource = ts72xx_max197_resources, +}; + static void __init ts72xx_init_machine(void) { ep93xx_init_devices(); @@ -220,6 +243,10 @@ static void __init ts72xx_init_machine(void) (void *)(EP93XX_ETHERNET_BASE + 0x50), 6); platform_device_register(&ts72xx_eth_device); platform_device_register(&ts72xx_watchdog_device); + + if (is_max197_installed()) { + platform_device_register(&ts72xx_max197_device); + } } MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a726f3b..4c696c6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -475,4 +475,25 @@ config SGI_GRU_DEBUG This option enables addition debugging code for the SGI GRU driver. If you are unsure, say N. +config TS72XX_MAX197 + tristate "TS-72xx MAX197 support" + depends on ARCH_EP93XX && MACH_TS72XX && SYSFS + help + Say Y here if to include support for the MAX197 A/D converter + optionally included on Technologic Systems SBCs. + Default acquisition range is [0..5V]. + + To compile this driver as a module, choose M here: the + module will be called ts72xx_max197. + +if TS72XX_MAX197 + +config TS72XX_MAX197_AVERAGE + bool "Average measurement" + help + Say Y here to enable making average measurement. Default is 1. + See /sys/module/ts72xx_max197/parameters/average file. + +endif # TS72XX_MAX197 + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c6c13f6..d97326f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_HP_ILO) += hpilo.o +obj-$(CONFIG_TS72XX_MAX197) += ts72xx_max197.o diff --git a/drivers/misc/ts72xx_max197.c b/drivers/misc/ts72xx_max197.c new file mode 100644 index 0000000..f989de6 --- /dev/null +++ b/drivers/misc/ts72xx_max197.c @@ -0,0 +1,235 @@ +/* + * TS-72XX max197 driver for Technologic Systems boards. + * + * Voltage conversion is taken from adc_logger from Jim Jackson. + * (c) Copyright 2008 Matthieu Crapet + * + * 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. + */ + +#include +#include +#include +#include + +#define DRV_VERSION "0.2" +#define PFX "ts72xx_max197: " + +#define MAX197_RANGE_5_5 1 // [- 5V + 5V] +#define MAX197_RANGE_10_10 3 // [-10V +10V] +#define MAX197_RANGE_0_5 0 // [ 0V + 5V] +#define MAX197_RANGE_0_10 2 // [ 0V +10V] + +#define MAX197_RESET_CHANNEL_CONF(x) (~(3 << (2*(x)))) +#define MAX197_SET_CHANNEL_CONF(x, range) ((range) << (2*(x))) +#define MAX197_GET_CHANNEL_CONF(x, conf) (((conf) >> (2*(x))) & 3) + +struct max197_config +{ + void __iomem *control_and_data_register; + void __iomem *busy_bit_register; + unsigned int channels; // two bits per channels +}; + +static struct max197_config conf; +#ifdef CONFIG_TS72XX_MAX197_AVERAGE +static ushort average = 1; +#endif + +static ssize_t max197_acquire(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int range, n; + signed short val; +#ifdef CONFIG_TS72XX_MAX197_AVERAGE + int i, total; +#endif + + n = attr->attr.name[2] - 0x31; + range = MAX197_GET_CHANNEL_CONF(n, conf.channels); + +#ifdef CONFIG_TS72XX_MAX197_AVERAGE + val = 0; total = 0; + for (i = 0; i < average; i++) { +#endif + + __raw_writeb(((range << 3) | n | 0x40) & 0xFF, + conf.control_and_data_register); + while (__raw_readb(conf.busy_bit_register) & 0x80); + val = __raw_readw(conf.control_and_data_register); + + //printk(PFX "%hd/%hd: 0x%04X\n", i+1, average, val); + +#ifdef CONFIG_TS72XX_MAX197_AVERAGE + total += val; + } + total /= average; + val = (signed short)total; +#endif + + /* We want three digit precision */ + switch (range) { + case MAX197_RANGE_0_5: + val = ((val * 50000/4096)+5)/10; + break; + case MAX197_RANGE_5_5: + case MAX197_RANGE_0_10: + val = ((val * 100000/4096)+5)/10; + break; + case MAX197_RANGE_10_10: + val = ((val * 200000/4096)+5)/10; + break; + } + + return sprintf(buf, "%d.%03d\n", val/1000, abs(val%1000)); +} + +static ssize_t max197_configure(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int n = attr->attr.name[2] - 0x31; + + long val = simple_strtol(buf, NULL, 10); + switch (val) { + case 10: + conf.channels &= MAX197_RESET_CHANNEL_CONF(n); + conf.channels |= MAX197_SET_CHANNEL_CONF(n, MAX197_RANGE_0_10); + break; + case 5: + conf.channels &= MAX197_RESET_CHANNEL_CONF(n); + conf.channels |= MAX197_SET_CHANNEL_CONF(n, MAX197_RANGE_0_5); + break; + case -10: + conf.channels &= MAX197_RESET_CHANNEL_CONF(n); + conf.channels |= MAX197_SET_CHANNEL_CONF(n, MAX197_RANGE_10_10); + break; + case -5: + conf.channels &= MAX197_RESET_CHANNEL_CONF(n); + conf.channels |= MAX197_SET_CHANNEL_CONF(n, MAX197_RANGE_5_5); + break; + + default: + return -EINVAL; + } + + return len; +} + +static DEVICE_ATTR(ch1, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch2, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch3, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch4, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch5, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch6, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch7, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); +static DEVICE_ATTR(ch8, S_IWUSR | S_IRUGO, max197_acquire, max197_configure); + +static struct attribute *max197_attributes[] = { + &dev_attr_ch1.attr, + &dev_attr_ch2.attr, + &dev_attr_ch3.attr, + &dev_attr_ch4.attr, + &dev_attr_ch5.attr, + &dev_attr_ch6.attr, + &dev_attr_ch7.attr, + &dev_attr_ch8.attr, + NULL +}; + +static struct attribute_group max197_group = { + .attrs = max197_attributes, + //.name = "channels", +}; + +static __devinit int ts72xx_max197_probe(struct platform_device *pdev) +{ + int err = 0; + struct resource *r_data, *r_busy; + + r_data = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r_busy = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + if (!r_data || !r_busy) { + dev_err(&pdev->dev, "missing resource(s)\n"); + return -EINVAL; + } + + conf.control_and_data_register = ioremap(r_data->start, r_data->end - r_data->start + 1); + if (!conf.control_and_data_register) { + err = -ENODEV; + goto exit; + } + + conf.busy_bit_register = ioremap(r_busy->start, r_busy->end - r_busy->start + 1); + if (!conf.busy_bit_register) { + err = -ENODEV; + goto exit_unmap1; + } + + conf.channels = + MAX197_SET_CHANNEL_CONF(0, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(1, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(2, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(3, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(4, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(5, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(6, MAX197_RANGE_0_5) | + MAX197_SET_CHANNEL_CONF(7, MAX197_RANGE_0_5); + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&pdev->dev.kobj, &max197_group))) + goto exit_unmap2; + + printk(PFX "TS-72xx max197 driver, v%s\n", DRV_VERSION); + return 0; + +exit_unmap2: + iounmap(conf.busy_bit_register); +exit_unmap1: + iounmap(conf.control_and_data_register); +exit: + return err; +} + +static int __devexit ts72xx_max197_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &max197_group); + iounmap(conf.busy_bit_register); + iounmap(conf.control_and_data_register); + return 0; +} + +static struct platform_driver ts72xx_max197_platform_driver = { + .probe = ts72xx_max197_probe, + .remove = __devexit_p(ts72xx_max197_remove), + .driver = { + .name = "ts72xx-max197", + .owner = THIS_MODULE, + }, +}; + +static int __init ts72xx_max197_init(void) +{ + return platform_driver_register(&ts72xx_max197_platform_driver); +} + +static void __exit ts72xx_max197_exit(void) +{ + platform_driver_unregister(&ts72xx_max197_platform_driver); +} + +#ifdef CONFIG_TS72XX_MAX197_AVERAGE +module_param(average, ushort, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(average, "Allow average measurement (default=1)"); +#endif + +MODULE_AUTHOR("Matthieu Crapet "); +MODULE_DESCRIPTION("TS-72xx max197 driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +module_init(ts72xx_max197_init); +module_exit(ts72xx_max197_exit); -- 1.6.0.4