Hi everyone,
I am trying to use HSADC pin to read adc input. By reading mx28 datasheet, I understand this HSADC is designed for driving the linear image scanner sensor, we just want to use it as a normal 12 bit ADC. So no triggering from PWM, and no need to channel on DMA. What we need just read the value periodically via software. During the past weekend, I was trying to verify this concept. But I couldn't get HSADC to read any values. What I got is always a timeout interrupt (bit 1 and bit 0) read from HW_HSADC_CTRL1.
Here is my code snippet. Maybe you guys can quickly find out what I missed. Any suggestion or comment is welcomed. Thank you.
int hsadc_init(void)
{
int i;
int ret = 0;
unsigned int read = 0;
// Set Power bit for all PLL0
writel((0x01 << 17), HW_CLKCTRL_PLL0CTRL0_SET);
// Clear clk fraction divider gate
writel((0x01 << 15), HW_CLKCTRL_FRAC1_CLR);
// set hsadc trigger as GPIO
writel((0x03 << 14), HW_PINCTRL_MUXSEL1_SET);
// set another hsadc trigger as GPIO
writel((0x03 << 10), HW_PINCTRL_MUXSEL8_SET);
// HSADC clk divider normal work, divided by 72
writel(0x70000000, HW_CLKCTRL_HSADC);
// Clk gate cleared
writel((0x01 << 31), HW_POWER_ANACLKCTRL_CLR);
writel((0x01 << 26), HW_POWER_ANACLKCTRL_CLR);
// INDIV set to 0x02, 1.5 MHz sampling rate
writel((0x01 << 1), HW_POWER_ANACLKCTRL_SET);
writel((0x01 << 0), HW_POWER_ANACLKCTRL_CLR);
// INCLK_SHIFT
writel((0x01 << 5), HW_POWER_ANACLKCTRL_SET);
writel((0x01 << 4), HW_POWER_ANACLKCTRL_CLR);
/*
* Set 0x1 to make the configuration INDIV<1:0> and INCLK_SHIFT available,
* but there would be <= 0.67us timing delay between HSADC start conversion
* and ‘start run’ command from software trigger or PWM trigger. If this delay
* is not desired, it is recommended to set INDIV<1:0> to 0x2 and using PWM
* trigger for HSADC
*/
writel((0x01 << 9), HW_POWER_ANACLKCTRL_SET);
ret = hsadc_reset();
if (ret)
return ret;
// Clear Power Down bit
writel((0x01 << 13), HW_HSADC_CTRL2_CLR);
for (i=0; i < 1000; i++)
{
udelay(1);
read = readl(HW_HSADC_CTRL2);
if (!(read & (0x01 << 13)))
break;
}
if (i >= 1000)
return -3;
// Set Pre-Charge bit
writel((0x01 << 0), HW_HSADC_CTRL2_SET);
for (i=0; i < 1000; i++)
{
udelay(1);
read = readl(HW_HSADC_CTRL2);
if ((read & (0x01 << 0)))
break;
}
if (i >= 1000)
return -4;
// Set on chip ground
writel((0x01 << 5), HW_HSADC_CTRL2_SET);
// use HSADC0 pin as analog input
writel((0x07 << 1), HW_HSADC_CTRL2_SET);
// One (0x01) sample per sequence
writel((0x001), HW_HSADC_SEQUENCE_SAMPLES_NUM);
// One (0x01)squence per conversion
writel((0x001), HW_HSADC_SEQUENCE_NUM);
// all interrupt enabled as default
// ADC triggerd by software
writel((0x03 << 28), HW_HSADC_CTRL0_CLR);
// 12 bit sample data
writel((0x01 << 17), HW_HSADC_CTRL0_CLR);
writel((0x01 << 18), HW_HSADC_CTRL0_SET);
// Big endian sample data
writel((0x01 << 16), HW_HSADC_CTRL0_SET);
// Clear FIFO data before start
for (i=0; i<1000; i++)
{
read = readl(HW_HSADC_CTRL1_SET);
if (read & 0x0020)
break;
}
if (i >= 1000)
return -5;
// Clear interrupt
writel((0x01 << 27), HW_HSADC_CTRL1_SET);
// Clear all interrupt flags
writel((0x01 << 26), HW_HSADC_CTRL1_SET);
// Set trigger delay cycles to
writel((0x03 << 1), HW_HSADC_CTRL0_SET);
// HSADC starts to run
writel((0x01 << 0), HW_HSADC_CTRL0_SET);
udelay(10);
// Trigger the ADC conversion
writel((0x01 << 27), HW_HSADC_CTRL0_SET);
// Wait for completion
for (i=0; i<100000; i++)
{
v1 = readl(HW_HSADC_CTRL1);
if (v1 & 0x01)
break;
udelay(1);
}
ret = v1;
hsadc_checkctrlreg();
hsadc_checkdatareg();
return ret;
}
void hsadc_checkdatareg(void)
{
unsigned int d0, d1, d2, d3, d4;
d0 = readl(HW_HSADC_FIFO_DATA);
d1 = readl(HW_HSADC_DBG_INFO0);
d2 = readl(HW_HSADC_DBG_INFO1);
d3 = readl(HW_HSADC_DBG_INFO2);
d4 = readl(HW_HSADC_VERSION);
printf("data=0x%08x, info0=0x%08x, info1=0x%08x, info2=0x%08x, ver=0x%08x\n",
d0, d1, d2, d3, d4);
}
void hsadc_checkctrlreg(void)
{
unsigned int v0, v1, v2;
v0 = readl(HW_HSADC_CTRL0);
v1 = readl(HW_HSADC_CTRL1);
v2 = readl(HW_HSADC_CTRL2);
printf("HW_HSADC_CTRL0 = 0x%08x, HW_HSADC_CTRL1 = 0x%08x, HW_HSADC_CTRL2 = 0x%08x\n",
v0, v1, v2);
}
The debug console output is like this:
HW_HSADC_CTRL0 = 0x00050046, HW_HSADC_CTRL1 = 0xf0000023, HW_HSADC_CTRL2 = 0x000000bf
data=0x00000000, info0=0x00000000, info1=0x00000000, info2=0x00000000, ver=0x00010000
is there any official code examples ?
I can't get the HSADC work.
this is my code:
initial:______________________________________________________________________________
writel(0x50000000, clk_base + HW_CLKCTRL_HSADC); /* M = 18;RST=High; */
*((u8*)(clk_base + HW_CLKCTRL_FRAC1 + 1)) = 30; /* HSADC=480*(M/N)=288MHz */
*((u8*)(clk_base + HW_CLKCTRL_FRAC1_CLR + 1)) = 0x80; /* clear HSADC_CLK_GATE */
writel(0xF0000000, hsadc_base + HW_HSADC_CTRL0_CLR); /* normal run;trigger is sw */
writel(0x0000000F, hsadc_base + HW_HSADC_CTRL2_SET); /* precharge before convert */
/* set pin to HSADC */
writel(0x00000003, hsadc_base + HW_HSADC_SEQUENCE_SAMPLES_NUM);/* 1 sample per sequence */
writel(0x00000003, hsadc_base + HW_HSADC_SEQUENCE_NUM); /* 1 sequence per trig */
writel(0xFC000000, hsadc_base + HW_HSADC_CTRL1_CLR); /* disable all interrupt */
writel(0x01C00001, hsadc_base + HW_HSADC_CTRL0_SET); /* 4 discard & 12bit mode */
/* get the HSADC running */
read the value:________________________________________________________________________
// while((readl(hsadc_base + HW_HSADC_CTRL1) & 0x00000020)){ /* if empty then */
writel(0x08000000, hsadc_base + HW_HSADC_CTRL0_SET); /* trig it! */
// }
iRes = readl(hsadc_base + HW_HSADC_FIFO_DATA);
it just not work...
any help will be apreciated...
Were you able to read sampled data from HSADC. I was able to configure the adc properly but i am unable to understand the data read from the HW_HSADC_FIFO_DATA register. Is it the sampled data or some setting register regarding DMA.
Hello Ravi,
its a long time ago and we stopped using the HSADC as the measurement quality was too bad for our purpose. What I can remember is that you only can read the sample correctly if all settings concerning Trigger Mode / Single Mode / Loop Modes are OK. Otherwise the HSADC does not work.
HI Michel
Regarding setting the modes correctly i will try to set it properly. But do you have some sample code from your past work then it will be really very helpful.
I am able to read data from the HW_HSADC_FIFO_DATA register but the overflow bit for fifo is also getting set when i am trying to capture a single samle in one sequence and one sequence only.
IF you can help me with the data reading part from the hsadc as not much is given in the documentation other than that for this purpose DMA has to be used.
Hello to all,
I will soon use the imx28 HSADC.
I see Mike and Iranna's works concerning the HSADC, and wonder if since that time, Freescale has created a Linux driver for the part.
Shall I write mine like Mike Z and Iranna did, or did Freescale release an official HSADC Linux driver ?
Thanks in advance for your answers and links.
Kind regards,
Gilles.
Hi
Ref Voltage can be configured by HW_HSADC_CTRL2_bit.SAH_GAIN_ADJ. I am writing HSADC driver, and the HSADC work correctly now. At first, I used 8 bits mode, but always get a wrong voltage from HSADC ; finally, I found ADC_SAMPLE_SHIFT_BITS_NUM must be 4 in 8 bits mode. In your code , you did nothing with ADC_SAMPLE_SHIFT_BITS_NUM, but you can get a right voltage , I don't know why. Now,I have one question, sample rate = 480M*(18/HW_CLKCTRL_FRAC1.HSADCFRAC) /HW_CLKCTRL_HSADC.FREQDIV/16, (where HSADCFRAC = 18-35). when HW_CLKCTRL_FRAC1.HSADCFRAC = 35 and HW_CLKCTRL_HSADC.FREQDIV = 3(Divide by 72), sample rate = 214K, is the lowest sample rate . Is this correct? How to get a lower sample rate than 214K?
Thanks
sheng
Hi
I modified code as you mentioned above, But still I am getting varying voltages, As follows
Voltage at HSADC pin - 0.83 0.54 1.02
FIfo data value (in HEX) - AD to B2 6E to 73 92 to 96
Voltage calculated(Vref = 1.3) - 0.877 0.55 0.75
Electrical specifications of HSADC, DC voltage can be used for HSADC is 0.5 to VDDA-0.5 (VDDA = 1.8V). So I am using 1.3V as Ref Voltage. Is this correct?
Thanks
Iranna
Iranna,
I see two problems in your code:
1. You didn't initial HSADC registers in your init() function.
// Clear Power Down bit
writel((0x01 << 13), HW_HSADC_CTRL2_CLR);
for (i=0; i < 1000; i++)
{
udelay(1);
read = readl(HW_HSADC_CTRL2);
if (!(read & (0x01 << 13)))
break;
}
if (i >= 1000)
return -3;
// ADC triggerd by software
writel((0x03 << 28), HW_HSADC_CTRL0_CLR);
// Discard first 2 samples
writel((0x01 << 20), HW_HSADC_CTRL0_CLR);
writel((0x01 << 19), HW_HSADC_CTRL0_SET);
if (bit == '0')
{
// 8 bit sample data
writel((0x01 << 18), HW_HSADC_CTRL0_CLR);
writel((0x01 << 17), HW_HSADC_CTRL0_CLR);
}
else if (bit == '1')
{
// 10 bit sample data
writel((0x01 << 18), HW_HSADC_CTRL0_CLR);
writel((0x01 << 17), HW_HSADC_CTRL0_SET);
}
else
{
// 12 bit sample data
writel((0x01 << 18), HW_HSADC_CTRL0_SET);
writel((0x01 << 17), HW_HSADC_CTRL0_CLR);
}
// Little endian sample data
writel((0x01 << 16), HW_HSADC_CTRL0_CLR);
// Delay 3 cycle after trigger
writel((0x03 << 1), HW_HSADC_CTRL0_SET);
// sampling at gain 4
writel((0x01 << 12), HW_HSADC_CTRL2_CLR);
writel((0x01 << 11), HW_HSADC_CTRL2_SET);
writel((0x01 << 10), HW_HSADC_CTRL2_SET);
// use HSADC0 pin as analog input
writel((0x01 << 3), HW_HSADC_CTRL2_SET);
writel((0x01 << 2), HW_HSADC_CTRL2_SET);
writel((0x01 << 1), HW_HSADC_CTRL2_SET);
// adjust headroom of current source
writel((0x01 << 9), HW_HSADC_CTRL2_CLR);
// adjust current
writel((0x01 << 8), HW_HSADC_CTRL2_CLR);
// Set Pre-Charge bit
writel((0x01 << 0), HW_HSADC_CTRL2_SET);
for (i=0; i < 1000; i++)
{
udelay(1);
read = readl(HW_HSADC_CTRL2);
if ((read & (0x01 << 0)))
break;
}
if (i >= 1000)
return -4;
// One (0x01) sample per sequence
writel((0x01), HW_HSADC_SEQUENCE_SAMPLES_NUM);
// One (0x01)squence per conversion
writel((0x01), HW_HSADC_SEQUENCE_NUM);
// Clear FIFO data before start
for (i=0; i<1000; i++)
{
read = readl(HW_HSADC_CTRL1_SET);
if (read & 0x0020)
break;
}
if (i >= 1000)
return -5;
// Clear interrupt
writel((0x01 << 27), HW_HSADC_CTRL1_SET);
// Clear all interrupt flags
writel((0x01 << 26), HW_HSADC_CTRL1_SET);
return 0;
}
2. It's better read FIFO data after you confirm you get ADC_DONE flag. If you get other flag (like timeout), you shall skip FIFO data, it just has garbage data there.
Hope these helps.
Michael
Hi
Were you able to read sampled data from HSADC. I was able to configure the adc properly but i am unable to understand the data read from the HW_HSADC_FIFO_DATA register. Is it the sampled data or some setting register regarding DMA. I have configured the HSADC as per the code given here and the registers show the values as set in the code later if i read those registers.
Is DMA the only way of reading data from the HSADC ?
Hello Mike, hello to all,
It has been a while you did it, but maybe you could help me.
I try to get hsadc working. After many analyses, I suspect the HSADC analog block not working.
Signs :
My clocks/power settings are the followings :
CLKCTRL_BASE_ADDR + HW_CLKCTRL_HSADC = 0x60000000
CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC1 = 0x00925292
REGS_POWER_BASE + HW_POWER_ANACLKCTRL = 0x84000626
And my registers settings just before soft-trigger are :
HW_HSADC_CTRL0 = 0x000c0049
HW_HSADC_CTRL1 = 0xc0000020
HW_HSADC_CTRL2 = 0x00001f8f
HW_HSADC_SEQUENCES_NUM = 0x00000001
HW_HSADC_SEQUENCE_SAMPLES_NUM = 0x0000000a
And just after soft-trigger :
HW_HSADC_CTRL0 = 0x000c0048
HW_HSADC_CTRL1 = 0xc0000002
HW_HSADC_CTRL2 = 0x00001f8f
HW_HSADC_SEQUENCES_NUM = 0x00000001
HW_HSADC_SEQUENCE_SAMPLES_NUM = 0x0000000a
I am sure I am missing something obvious to switch on the analog block, but it has been 3 days now, and I am banging my head on my keyboard...
If someone could help me to make my HSADC analog block run, I would be grateful.
Thanks in advance,
Gilles.
[edit : add registers after trigger ]
Hi mike
As you said HSADC is working in your board, Kindly Help me in this. what is the HSADC reference voltage and CTRL register values.
Thanks
Iranna
mike z said:
To make HSADC working, you need first implement this work around for a chip hardware problem. Here is the errata link:
http://cache.freescale.com/files/32bit/doc/errata/IMX28CE.pdf
You need check ENGR116296.
After implemented this, I got HSADC going and I can read data from FIFO register.
Hi,
I have tried writing HSADC driver, Using IOCTL call to read ADC converted value on HSADC0 channel,
that inside calls mxs_read_general() in which enabling interrupts(END_SEQ, ADC_DONE and TIMEOUT), setting RUN bit in Ctrl0 reg and triggring it.
and waiting for interrupt(ADC_DONE or END_SEQ or TIMEOUT). if TIMEOUT comes again caling mxs_read_general().
So now I am getting ADC_DONE interrupt and Reading FIFO_DATA reg for value in interrupt handler. but the values are different every time with same voltage.
Please help me in this any where I am going wrong.
static int mxs_hsadc_module_probe(struct platform_device *pdev)
{
int ret = 0;
struct device *temp_class;
struct resource *res;
void __iomem *base;
/* ioremap the base address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "No HSADC base address provided\n");
goto err_out0;
}
base = (void __iomem *)IO_ADDRESS(res->start);
if (base == NULL) {
dev_err(&pdev->dev, "Failed to rebase HSADC base address\n");
goto err_out0;
}
hsadc_base = (unsigned int)base;
/* create the chrdev */
mxs_hsadc_major = register_chrdev(0, "mxs-hsadc", &mxs_hsadc_fops);
if (mxs_hsadc_major < 0) {
dev_err(&pdev->dev, "Unable to get a major for mxs_hsadc\n");
return mxs_hsadc_major;
}
/*creating hsadc class */
mxs_hsadc_class = class_create(THIS_MODULE, "mxs-hsadc");
if (IS_ERR(mxs_hsadc_class)) {
dev_err(&pdev->dev, "Error creating mxs_hsadc class.\n");
ret = PTR_ERR(mxs_hsadc_class);
goto err_out1;
}
/*Creating device node */
temp_class = device_create(mxs_hsadc_class, NULL,
MKDEV(mxs_hsadc_major, 0), NULL, "mxs-hsadc");
if (IS_ERR(temp_class)) {
dev_err(&pdev->dev, "Error creating mxs_hsadc class device.\n");
ret = PTR_ERR(temp_class);
goto err_out2;
}
adc_data = kmalloc(sizeof(struct mxs_hsadc_data), GFP_KERNEL);
if (adc_data == NULL)
return -ENOMEM;
/* requesting hsadc irq */
adc_data->irq = platform_get_irq(pdev, 0);
ret = request_irq(adc_data->irq, mxs_hsadc_interrupt, 0, MOD_NAME, MOD_NAME);
if (ret) {
printk(KERN_DEBUG"HSADC : %s : irq registration failed %d\n",__FILE__,ret);
return ret;
}
if (ret != MXS_HSADC_SUCCESS) {
dev_err(&pdev->dev, "Error in mxs_hsadc_init.\n");
goto err_out4;
}
/*HSADC initialization */
ret = mxs_hsadc_init();
/* By default, devices should wakeup if they can */
/* So HSADC is set as "should wakeup" as it can */
device_init_wakeup(&pdev->dev, 1);
return ret;
err_out4:
device_destroy(mxs_hsadc_class, MKDEV(mxs_hsadc_major, 0));
err_out2:
class_destroy(mxs_hsadc_class);
err_out1:
unregister_chrdev(mxs_hsadc_major, "mxs-hsadc");
err_out0:
return ret;
}
int mxs_hsadc_init()
{
int i;
unsigned int reg;
// mxs_hsadc_clk_enable();
__raw_writel(BF_CLKCTRL_FRAC1_HSADCFRAC(0x3f), HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_FRAC1_CLR); /* Clear */
__raw_writel(BF_CLKCTRL_FRAC1_HSADCFRAC(30), HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_FRAC1_SET); /* Set to 288 MHz*/
/* Clear the clock gate*/
__raw_writel(BM_CLKCTRL_FRAC1_CLKGATEHSADC, HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_FRAC1_CLR);
/* Set the HSADC CLK ADC divider to ge the Operation clock of 16 MHz*/
__raw_writel(BM_CLKCTRL_HSADC_RESETB | BF_CLKCTRL_HSADC_FREQDIV( 1 /*CLKCTRL_HSADC_FREQDIV_18*/), HW_CLKCTRL_BASE_ADDRESS+HW_CLKCTRL_HSADC);
/* 1st workaround for HSADC */
__raw_writel(HSADC_CTRL0_RESET,hsadc_base + HSADC_CTRL0_CLR);
for (i = 0; i < 10000; i++) {
reg = __raw_readl(hsadc_base + HSADC_CTRL0);
if (!(reg & HSADC_CTRL0_RESET))
break;
udelay(3);
}
__raw_writel(HSADC_CTRL0_RESET & (~HSADC_CTRL0_CLKGATE_OFF), hsadc_base + HSADC_CTRL0_SET);
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_SET);
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_CLR);
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_SET);
/* 1st workaround for HSADC */
// __raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_CLR);
__raw_writel(HSADC_CTRL0_RESET,hsadc_base + HSADC_CTRL0_CLR);
for (i = 0; i < 10000; i++) {
reg = __raw_readl(hsadc_base + HSADC_CTRL0);
if (!(reg & HSADC_CTRL0_RESET))
break;
udelay(3);
}
__raw_writel(HSADC_CTRL0_CLKGATE_OFF,hsadc_base + HSADC_CTRL0_CLR);
/*Disable the interrupts*/
__raw_writel(HSADC_INTR_CTRL_TIMEOUT_ENB ,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CTRL_END_SEQ_ENB,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CTRL_ADC_DONE_ENB,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CTRL_FIFO_OVFW_ENB,hsadc_base + HSADC_CTRL1_CLR);
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_SET);
/* HSADC is set to SINGLE Mode*/
reg = 0x1;
__raw_writel(reg , hsadc_base +HSADC_SEQ_NUM);
/*Number of samples*/
reg = 0x1;
__raw_writel(reg , hsadc_base +HSADC_SEQ_SAM_NUM);
/*Power Register config */
reg =0x84000626;
__raw_writel(reg , REGS_POWER_BASE + HW_POWER_ANACLKCTRL);
/* Wake up from power down mode */
__raw_writel(HSADC_CTRL2_POWER_DOWN,hsadc_base + HSADC_CTRL2_CLR);
/*Set PreCharge Enable */
__raw_writel(HSADC_CTRL2_PRECHARGE,hsadc_base + HSADC_CTRL2_SET);
/*Set HSADC_RUN mode*/
__raw_writel(HSADC_CTRL0_RUN,hsadc_base + HSADC_CTRL0_SET);
return 0;
}
/* interrupt handler */
static irqreturn_t mxs_hsadc_interrupt(int irq, void *dev_id)
{
unsigned long reg=0;
hsadc_value = __raw_readl(hsadc_base + HSADC_FIFO_DATA);
printk(KERN_DEBUG"HSADC : value %x\n",hsadc_value);
reg = __raw_readl(hsadc_base + HSADC_CTRL1) & HSADC_INTR_STATUS_END_SEQ;
if(reg)
{
printk(KERN_DEBUG"%s : reg value HSADC_INTR_STATUS_END_SEQ %d\n",__FILE__,(int)reg);
goto ADC_DONE
}
reg = __raw_readl(hsadc_base + HSADC_CTRL1) & HSADC_INTR_STATUS_ADC_DONE;
if(reg)
{
printk(KERN_DEBUG"%s : reg value HSADC_INTR_STATUS_ADC_DONE %d\n",__FILE__,(int)reg);
goto ADC_DONE
}
reg = __raw_readl(hsadc_base + HSADC_CTRL1) & HSADC_INTR_STATUS_TIMEOUT;
if (reg)
{
/*Disable timeout interrupt*/
__raw_writel(HSADC_INTR_CTRL_TIMEOUT_ENB,hsadc_base + HSADC_CTRL1_CLR);
/*Clear interrupt status and pending interrupts*/
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_CLR);
printk(KERN_DEBUG"%s : reg value HSADC_INTR_STATUS_TIMEOUT %d\n",__FILE__,(int)reg);
timeout = 1;
hsadc_conversion=1;
return IRQ_HANDLED;
}
ADC_DONE:
/*Clear interrupt status and pending interrupts*/
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_CLR);
timeout = 0;
hsadc_conversion=1;
return IRQ_HANDLED;
}
enum MXS_HSADC_STATUS mxs_hsadc_read_general()
{
unsigned long reg = 0;
hsadc_conversion=0;
/*channel selection */
__raw_writel((7 << 1), hsadc_base + HSADC_CTRL2_SET );
/*Clear interrupt status and pending interrupts*/
__raw_writel(HSADC_INTR_CLR,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_STATUS_CLR,hsadc_base + HSADC_CTRL1_SET);
/*Enabling the interrupts*/
__raw_writel(HSADC_INTR_CTRL_END_SEQ_ENB,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_CTRL_ADC_DONE_ENB,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_CTRL_FIFO_OVFW_ENB,hsadc_base + HSADC_CTRL1_SET);
__raw_writel(HSADC_INTR_CTRL_TIMEOUT_ENB,hsadc_base + HSADC_CTRL1_SET);
/*Delay cycles*/
reg = 4 << 1;
__raw_writel(reg, hsadc_base + HSADC_CTRL0_SET);
/*Set HSADC_RUN bit*/
__raw_writel(HSADC_CTRL0_RUN,hsadc_base + HSADC_CTRL0_SET);
mdelay(100);
__raw_writel(HSADC_CTRL0_SW_TRIGGER, hsadc_base + HSADC_CTRL0_SET);
mdelay(10);
__raw_writel(HSADC_CTRL0_SW_TRIGGER, hsadc_base + HSADC_CTRL0_SET);
while(!hsadc_conversion)
{
/*Waiting for the interrupt to occur*/
mdelay(100);
}
/*Disable the RUN Bit*/
__raw_writel(HSADC_CTRL0_RUN,hsadc_base + HSADC_CTRL0_CLR);
if(timeout)
return MXS_HSADC_ERROR;
else
return MXS_HSADC_SUCCESS;
}
Thanks,
Iranna
Mike,
Maybe you could post your HSADC driver somewhere?
Thanks,
Fabio Estevam
mike z said:
To make HSADC working, you need first implement this work around for a chip hardware problem. Here is the errata link:
http://cache.freescale.com/files/32bit/doc/errata/IMX28CE.pdf
You need check ENGR116296.
After implemented this, I got HSADC going and I can read data from FIFO register.
Hi,
I am getting ADC_DONE interrupt properly, but not getting constant values, Different values (FIFO reg value) every time when I execute the binary. Is there any thing to be taken care from driver side or Its hardware fault.
we are giving 3.3V as reference and ADC input voltage is 1.68V, getting values around 1.5V to 2.3V. Please reply me.
Best regards
Iranna
Hello iranna,
were facing also the problem that we don't get constant values. For test purpose I switched the HSADC to LRADC2-pin (via HW_HSADC_CTRL2) where I have a simple voltage divider (10k/3,5k to 3.3V) with an 100nF capacitor to GND.
I get 12bit values beween about 0x7b0 and 0x880. Most values are near 0x810 but about every 10th value is strange smaller or greater. I write 0x385 in HW_HSADC_CTRL2.
When I bypass ADC sample and hold logics by writing 0x395 in HW_HSADC_CTRL2 I get nearly constant values (0x7ef..0x7f2). Therefore I think I have wrong values for sample and hold logic in HW_HSADC_CTRL2.
Can you help me?
To make HSADC working, you need first implement this work around for a chip hardware problem. Here is the errata link:
http://cache.freescale.com/files/32bit/doc/errata/IMX28CE.pdf
You need check ENGR116296.
After implemented this, I got HSADC going and I can read data from FIFO register.
Hi,
I am also facing the same problem while implementing HSADC on imx28 processor and linux-2.6.35.3 kernel. If you found solution please reply me.
best regds
iranna