static int stop_pmu(void)
{
	unsigned int inten_value;
	unsigned int pmnc_value;
	unsigned int flag_value;

	inten_value  = 0x0;
	flag_value = 0x1f;

	pmnc_value = ReadPMUReg(PXA2_PMU_PMNC);

	/* disable the counters */
	pmnc_value |= 0x10;
	pmnc_value &= ~0x1;

	WritePMUReg(PXA2_PMU_PMNC, pmnc_value);
	WritePMUReg(PXA2_PMU_INTEN, inten_value);
	WritePMUReg(PXA2_PMU_FLAG, flag_value);

	/* We need to save the PMU counter value for calibration result before calling free_pmu()
 	 * because free_pmu() may cause these registers be modified by IPM */
 	reg_value[COUNTER_PXA2_PMU_CCNT] = ReadPMUReg(PXA2_PMU_CCNT);
	reg_value[COUNTER_PXA2_PMU_PMN0] = ReadPMUReg(PXA2_PMU_PMN0);
	reg_value[COUNTER_PXA2_PMU_PMN1] = ReadPMUReg(PXA2_PMU_PMN1);
	reg_value[COUNTER_PXA2_PMU_PMN2] = ReadPMUReg(PXA2_PMU_PMN2);
	reg_value[COUNTER_PXA2_PMU_PMN3] = ReadPMUReg(PXA2_PMU_PMN3);

	unregister_pmu_isr();

	free_pmu();

	return 0;
}
static int resume_pmu(void)
{
	unsigned int pmnc_value;

	pmnc_value = ReadPMUReg(PXA2_PMU_PMNC);

	pmnc_value |= 0x1;
	pmnc_value &= ~0x10;

	WritePMUReg(PXA2_PMU_PMNC, pmnc_value);

	return 0;
}
static int pause_pmu(void)
{
	unsigned int flag_value = 0;
	unsigned int pmnc_value;

	pmnc_value = ReadPMUReg(PXA2_PMU_PMNC);

	/* disable the counters */
	pmnc_value |= 0x10;
	pmnc_value &= ~0x1;

	/* clear the overflow flags */
	flag_value = 0x1f;

	WritePMUReg(PXA2_PMU_PMNC, pmnc_value);
	WritePMUReg(PXA2_PMU_FLAG, flag_value);

	return 0;
}
static irqreturn_t px_pmu_isr(struct pt_regs * const regs,
                              unsigned int pid,
                              unsigned int tid,
                              unsigned int cpu,
                              unsigned long long ts)
{
	int i;
	int reg = 0;
	unsigned long flag_value;
	unsigned long pmnc_value;
	bool buffer_full = false;
	char ** bt_buffer = &per_cpu(g_bt_buffer, cpu);
	PXD32_CSS_Call_Stack_V2 *css_data = (PXD32_CSS_Call_Stack_V2 *)*bt_buffer;

	/* disable the counters */
	pmnc_value = ReadPMUReg(PXA2_PMU_PMNC);
	WritePMUReg(PXA2_PMU_PMNC, pmnc_value & ~PMNC_ENABLE_BIT);

	/* clear the overflow flag */
	flag_value = ReadPMUReg(PXA2_PMU_FLAG);
	WritePMUReg(PXA2_PMU_FLAG, FLAG_OVERFLOW_BITS);

	backtrace(regs, cpu, pid, tid, css_data);

	/* write sample record to sample buffer */
	if (flag_value & CCNT_OVERFLAG_BIT && es[COUNTER_PXA2_PMU_CCNT].enabled)
	{
		if (es[COUNTER_PXA2_PMU_CCNT].calibration == false)
		{
			/* write sample record in non-calibration mode */
			//buffer_full |= backtrace(regs, pid, tid, COUNTER_PXA2_PMU_CCNT, cpu, ts);
			if (!buffer_full)
			{
				fill_css_data_head(css_data, pid, tid, COUNTER_PXA2_PMU_CCNT, ts);

				buffer_full |= write_css_data(cpu, css_data);
			}
		}
		else
		{
			/* calculate the overflow count in calibration mode */
			es[COUNTER_PXA2_PMU_CCNT].overflow++;
		}

		/* reset the counter value */
		WritePMUReg(PXA2_PMU_CCNT, es[COUNTER_PXA2_PMU_CCNT].reset_value);
	}

	for (i=0; i<PXA2_PMN_NUM; i++)
	{
		if (flag_value & (PMN0_OVERFLAG_BIT << i))
		{
			unsigned int reg_id = 0;

			switch (i)
			{
			case 0: reg_id = COUNTER_PXA2_PMU_PMN0; reg = PXA2_PMU_PMN0; break;
			case 1: reg_id = COUNTER_PXA2_PMU_PMN1; reg = PXA2_PMU_PMN1; break;
			case 2: reg_id = COUNTER_PXA2_PMU_PMN2; reg = PXA2_PMU_PMN2; break;
			case 3: reg_id = COUNTER_PXA2_PMU_PMN3; reg = PXA2_PMU_PMN3; break;
			default: break;
			}

			if (es[reg_id].calibration == false)
			{
				/* write sample record in non-calibration mode */
				//buffer_full |= backtrace(regs, pid, tid, reg_id, cpu, ts);
				if (!buffer_full)
				{
					fill_css_data_head(css_data, pid, tid, reg_id, ts);

					buffer_full |= write_css_data(cpu, css_data);
				}
			}
			else
			{
				/* calculate the overflow count in calibration mode */
				es[reg_id].overflow++;
			}

			/* reset the counter value */
			WritePMUReg(reg, es[reg_id].reset_value);
		}
	}

	if (!buffer_full)
	{
		/* enable the counters if buffer is not full */
		WritePMUReg(PXA2_PMU_PMNC, pmnc_value | PMNC_ENABLE_BIT);
	}

	return IRQ_HANDLED;
}
static irqreturn_t px_pmu_isr(unsigned int pid,
                              unsigned int tid,
                              unsigned int pc,
                              unsigned int timestamp)
{
	int i;
	int reg = 0;
	unsigned long flag_value;
	unsigned long pmnc_value;
	PXD32_Hotspot_Sample sample_rec;
	bool buffer_full = false;

	/* disable the timer interrupt */
	//disable_irq(PX_IRQ_PXA2_TIMER);

	/* disable the counters */
	pmnc_value = ReadPMUReg(PXA2_PMU_PMNC);
	WritePMUReg(PXA2_PMU_PMNC, pmnc_value & ~PMNC_ENABLE_BIT);
	
	/* clear the overflow flag */
	flag_value = ReadPMUReg(PXA2_PMU_FLAG);
	WritePMUReg(PXA2_PMU_FLAG, FLAG_OVERFLOW_BITS);

	/* write sample record to sample buffer */
	sample_rec.pc	   = pc;
	sample_rec.pid	   = pid;
	sample_rec.tid	   = tid;
	memcpy(sample_rec.timestamp, &timestamp, 3);

	if (flag_value & CCNT_OVERFLAG_BIT && es[COUNTER_PXA2_PMU_CCNT].enabled)
	{
		sample_rec.registerId = COUNTER_PXA2_PMU_CCNT;
		if (es[COUNTER_PXA2_PMU_CCNT].calibration == false)
		{
			/* write sample record in non-calibration mode */
			buffer_full |= write_sample(&sample_rec);
		}
		else
		{
			/* calculate the overflow count in calibration mode */
			es[sample_rec.registerId].overflow++;
		}

		/* reset the counter value */
		WritePMUReg(PXA2_PMU_CCNT, es[COUNTER_PXA2_PMU_CCNT].reset_value);
	}
	
	for (i=0; i<4; i++)
	{
		if (flag_value & (PMN0_OVERFLAG_BIT << i))
		{
			switch (i)
			{
			case 0: sample_rec.registerId = COUNTER_PXA2_PMU_PMN0; reg = PXA2_PMU_PMN0; break;
			case 1: sample_rec.registerId = COUNTER_PXA2_PMU_PMN1; reg = PXA2_PMU_PMN1; break;
			case 2: sample_rec.registerId = COUNTER_PXA2_PMU_PMN2; reg = PXA2_PMU_PMN2; break;
			case 3: sample_rec.registerId = COUNTER_PXA2_PMU_PMN3; reg = PXA2_PMU_PMN3; break;
			default: break;
			}
			
			if (es[sample_rec.registerId].calibration == false)
			{
				/* write sample record in non-calibration mode */
				buffer_full |= write_sample(&sample_rec);
			}
			else
			{
				/* calculate the overflow count in calibration mode */
				es[sample_rec.registerId].overflow++;
			}

			/* reset the counter value */
			WritePMUReg(reg, es[sample_rec.registerId].reset_value);
		}
	}
	
	if (!buffer_full)
	{
		/* enable the counters if buffer is not full */
		WritePMUReg(PXA2_PMU_PMNC, pmnc_value | PMNC_ENABLE_BIT);
	}

	/* enable the timer interrupt */
	//enable_irq(PX_IRQ_PXA2_TIMER);
	return IRQ_HANDLED;
}