static int stop_pmu(void)
{
	u32 intenc_value;
	u32 flag_value;
	u32 pmnc_value;

	intenc_value = 0xffffffff;
	flag_value   = 0xffffffff;

	/* disable all counters */
	pmnc_value = PJ4_Read_PMNC();
	pmnc_value &= ~0x1;
	PJ4_Write_PMNC(pmnc_value);

	/* clear overflow flags */
	PJ4_Write_FLAG(flag_value);

	/* disable all interrupts */
	PJ4_Write_INTENC(intenc_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_PJ4_PMU_CCNT] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_CCNT);
	reg_value[COUNTER_PJ4_PMU_PMN0] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN0);
	reg_value[COUNTER_PJ4_PMU_PMN1] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN1);
	reg_value[COUNTER_PJ4_PMU_PMN2] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN2);
	reg_value[COUNTER_PJ4_PMU_PMN3] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN3);

	unregister_pmu_isr();

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

	/* enable all counters */
	pmnc_value = PJ4_Read_PMNC();
	pmnc_value |= 0x1;
	PJ4_Write_PMNC(pmnc_value);

	return 0;
}
static int pause_pmu(void)
{
	u32 pmnc_value;

	/* disable all counters */
	pmnc_value = PJ4_Read_PMNC();
	pmnc_value &= ~0x1;
	PJ4_Write_PMNC(pmnc_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)
{
	u32 pmnc_value;
	u32 flag_value;
	unsigned int i;
	unsigned int reg_id;
	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 = PJ4_Read_PMNC();
	pmnc_value &= ~0x1;
	PJ4_Write_PMNC(pmnc_value);

	/* clear the overflow flag */
	flag_value = PJ4_Read_FLAG();
	PJ4_Write_FLAG(0xffffffff);
	
	if (flag_value != 0)
		backtrace(regs, cpu, pid, tid, css_data);

	if ((flag_value & 0x80000000) && es[COUNTER_PJ4_PMU_CCNT].enabled)
	{
		reg_id = COUNTER_PJ4_PMU_CCNT;

		/* ccnt overflow */
		if (es[reg_id].calibration == false)
		{
			/* write css data in non-calibration mode */
			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++;
		}

		PJ4_WritePMUCounter(reg_id, es[reg_id].reset_value);
	}

	for (i=0; i<PJ4_PMN_NUM; i++)
	{
		if (flag_value & (0x1 << i))
		{
			switch (i)
			{
			case 0:	reg_id = COUNTER_PJ4_PMU_PMN0; break;
			case 1:	reg_id = COUNTER_PJ4_PMU_PMN1; break;
			case 2:	reg_id = COUNTER_PJ4_PMU_PMN2; break;
			case 3:	reg_id = COUNTER_PJ4_PMU_PMN3; break;
			default: break;
			}

			if (es[reg_id].calibration == false)
			{
				/* write css data in non-calibration mode */
				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++;
			}

			PJ4_WritePMUCounter(reg_id, es[reg_id].reset_value);
		}

	}

	if (!buffer_full)
	{
		/* enable the counters */
		pmnc_value |= 0x1;
		PJ4_Write_PMNC(pmnc_value);
	}

	return IRQ_HANDLED;
}
static int start_pmu(bool is_start_paused)
{
	int i;
	int ret;

	struct pmu_registers_pj4 pmu_regs;

	pmu_regs.pmnc   = 0x0;
	pmu_regs.ccnt   = 0x0;
	pmu_regs.cntens = 0x0;
	pmu_regs.cntenc = 0x0;
	pmu_regs.intens = 0x0;
	pmu_regs.intenc = 0x0;
	pmu_regs.flag   = 0x0;

	for (i=0; i<PJ4_PMN_NUM; i++)
	{
		pmu_regs.evtsel[i] = 0;
		pmu_regs.pmncnt[i] = 0;
	}

	ret = allocate_pmu();

	if (ret != 0)
	{
		return ret;
	}

	ret = register_pmu_isr(px_css_isr);

	if (ret != 0)
	{
		return ret;
	}

	/* disable PMU and clear CCNT & PMNx */
	pmu_regs.pmnc = PJ4_Read_PMNC();
	pmu_regs.pmnc &= ~0x1;
	//pmu_regs.pmnc |= 0x6;
	PJ4_Write_PMNC(pmu_regs.pmnc);

	for (i=0; i<g_ebs_settings.eventNumber; i++)
	{
		switch (g_ebs_settings.event[i].registerId)
		{
		case COUNTER_PJ4_PMU_CCNT:
			set_ccnt_events(&g_ebs_settings.event[i], &pmu_regs);
			break;

		case COUNTER_PJ4_PMU_PMN0:
			set_pmn_events(0, &g_ebs_settings.event[i], &pmu_regs);
			break;

		case COUNTER_PJ4_PMU_PMN1:
			set_pmn_events(1, &g_ebs_settings.event[i], &pmu_regs);
			break;

		case COUNTER_PJ4_PMU_PMN2:
			set_pmn_events(2, &g_ebs_settings.event[i], &pmu_regs);
			break;

		case COUNTER_PJ4_PMU_PMN3:
			set_pmn_events(3, &g_ebs_settings.event[i], &pmu_regs);
			break;

		default:
			break;
		}

	}

	/* disable all counters */
	PJ4_Write_CNTENC(0xffffffff);

	/* disable all interrupts */
	PJ4_Write_INTENC(0xffffffff);

	/* clear overflow flags */
	PJ4_Write_FLAG(0xffffffff);

	/* write the counter values */
	PJ4_WritePMUCounter(COUNTER_PJ4_PMU_CCNT, pmu_regs.ccnt);
	PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN0, pmu_regs.pmncnt[0]);
	PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN1, pmu_regs.pmncnt[1]);
	PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN2, pmu_regs.pmncnt[2]);
	PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN3, pmu_regs.pmncnt[3]);

	/* set events */
	for (i=0; i<PJ4_PMN_NUM; i++)
	{
		PJ4_Write_PMNXSEL(i);
		PJ4_Write_PMNCNT(pmu_regs.pmncnt[i]);
		PJ4_Write_EVTSEL(pmu_regs.evtsel[i]);
	}

	if (is_start_paused)
	{
		pmu_regs.pmnc &= ~0x1;
	}
	else
	{
		pmu_regs.pmnc |= 0x1;
	}


	/* enable the interrupts */
	PJ4_Write_INTENS(pmu_regs.intens);

	/* enable the counters */
	PJ4_Write_CNTENS(pmu_regs.cntens);

	/* Enable PMU */
	PJ4_Write_PMNC(pmu_regs.pmnc);

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

	PXD32_Hotspot_Sample sample_rec;

	/* disable the counters */
	pmnc_value = PJ4_Read_PMNC();
	pmnc_value &= ~0x1;
	PJ4_Write_PMNC(pmnc_value);

	/* clear the overflow flag */
	flag_value = PJ4_Read_FLAG();
	PJ4_Write_FLAG(0x8000000f);

	sample_rec.pc = pc;
	sample_rec.pid = pid;
	sample_rec.tid = tid;
	memcpy(sample_rec.timestamp, &timestamp, 3);

	if ((flag_value & 0x80000000) && es[COUNTER_PJ4_PMU_CCNT].enabled)
	{
		sample_rec.registerId = COUNTER_PJ4_PMU_CCNT;

		/* ccnt overflow */
		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++;
		}

		PJ4_WritePMUCounter(sample_rec.registerId, es[sample_rec.registerId].reset_value); 
	}

	for (i=0; i<4; i++)
	{
		if (flag_value & (0x1 << i))
		{
			switch (i)
			{
			case 0:	sample_rec.registerId = COUNTER_PJ4_PMU_PMN0; break;
			case 1:	sample_rec.registerId = COUNTER_PJ4_PMU_PMN1; break;
			case 2:	sample_rec.registerId = COUNTER_PJ4_PMU_PMN2; break;
			case 3:	sample_rec.registerId = COUNTER_PJ4_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++;
			}

			PJ4_WritePMUCounter(sample_rec.registerId, es[sample_rec.registerId].reset_value); 
		}

	}

	if (!buffer_full)
	{
		/* enable the counters */
		pmnc_value |= 0x1;
		PJ4_Write_PMNC(pmnc_value);
	}

	return IRQ_HANDLED;
}