diff options
| author | Volodymyr Vorobiov <volodymyr.vorobiov@globallogic.com> | 2019-12-13 15:40:14 +0200 | 
|---|---|---|
| committer | Volodymyr Vorobiov <volodymyr.vorobiov@globallogic.com> | 2019-12-13 15:40:14 +0200 | 
| commit | 57651686d90c05a186604a27a532834fa7979c15 (patch) | |
| tree | a2c7d74ce707e715a5a4c818f586c072d7ad8f48 | |
| parent | e4577b095d086eeccc37516de42b331fd771a2fe (diff) | |
| download | mts-io-57651686d90c05a186604a27a532834fa7979c15.tar.gz mts-io-57651686d90c05a186604a27a532834fa7979c15.tar.bz2 mts-io-57651686d90c05a186604a27a532834fa7979c15.zip | |
Add ADC to mts-io
| -rw-r--r-- | io-module/adc.c | 126 | ||||
| -rw-r--r-- | io-module/mt100eocg.c | 74 | ||||
| -rw-r--r-- | io-module/mts-io.c | 15 | 
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); | 
