int msm_dex_comm(struct msm_dex_command * in, unsigned *out)
{
	unsigned base = (unsigned)(MSM_SHARED_BASE + 0xfc100);
	unsigned dex_timeout;
	unsigned status;
	unsigned num;
	unsigned base_cmd, base_status;

	mutex_acquire(&dex_mutex);

	init_dex_locked();

	DDEX("waiting for modem; command=0x%02x data=0x%x", in->cmd, in->data);

	// Store original cmd byte
	base_cmd = in->cmd & 0xff;

	// Write only lowest byte
	writeb(base_cmd, base + DEX_COMMAND);

	// If we have data to pass, add 0x100 bit and store the data
	if ( in->has_data )
	{
		writel(readl(base + DEX_COMMAND) | DEX_HAS_DATA, base + DEX_COMMAND);
		writel(in->data, base + DEX_DATA);
	} else {
		writel(readl(base + DEX_COMMAND) & ~DEX_HAS_DATA, base + DEX_COMMAND);
		writel(0, base + DEX_DATA);
	}

	// Increment last serial counter
	num = readl(base + DEX_SERIAL) + 1;
	writel(num, base + DEX_SERIAL);

	DDEX("command and data sent (cntr=0x%x) ...", num);

	// Notify ARM9 with int6
	notify_other_dex_comm();

	// Wait for response... XXX: check irq stat?
	dex_timeout = DEX_TIMEOUT;
	while ( --dex_timeout && readl(base + DEX_SERIAL_CHECK) != num )
		udelay(1);

	if ( ! dex_timeout )
	{
		EDEX("%s: DEX cmd timed out. status=0x%x, A2Mcntr=%x, M2Acntr=%x\n",
			__func__, readl(base + DEX_STATUS), num, readl(base + DEX_SERIAL_CHECK));
		goto end;
	}

	DDEX("command result status = 0x%08x", readl(base + DEX_STATUS));

	// Read status of command
	status = readl(base + DEX_STATUS);
	writeb(0, base + DEX_STATUS);
	base_status = status & 0xff;
	DDEX("status new = 0x%x; status base = 0x%x",
		readl(base + DEX_STATUS), base_status);


	if ( base_status == base_cmd )
	{
		if ( status & DEX_STATUS_FAIL )
		{
			EDEX("DEX cmd failed; status=%x, result=%x",
				readl(base + DEX_STATUS),
				readl(base + DEX_DATA_RESULT));

			writel(readl(base + DEX_STATUS) & ~DEX_STATUS_FAIL, base + DEX_STATUS);
		}
		else if ( status & DEX_HAS_DATA )
		{
			writel(readl(base + DEX_STATUS) & ~DEX_HAS_DATA, base + DEX_STATUS);
			if (out)
				*out = readl(base + DEX_DATA_RESULT);
			DDEX("DEX output data = 0x%x",
				readl(base + DEX_DATA_RESULT));
		}
	} else {
		dprintf(CRITICAL, "%s: DEX Code not match! a2m[0x%x], m2a[0x%x], a2m_num[0x%x], m2a_num[0x%x]\n",
			__func__, base_cmd, base_status, num, readl(base + DEX_SERIAL_CHECK));
	}

end:
	writel(0, base + DEX_DATA_RESULT);
	writel(0, base + DEX_STATUS);

	mutex_release(&dex_mutex);
	return 0;
}
int dex_comm(unsigned cmd, unsigned *data1, unsigned *data2)
{
	unsigned long flags;
	unsigned timeout;
	unsigned status;
	unsigned num, dex_has_data, dex_cmd=0, dex_data=0, dex_data2=0;
	unsigned base_cmd, base_status;
	
	dex_has_data = data1 ? 1 : data2 ? 1 : 0;
	dex_data = data1 ? *data1 : 0;
	dex_data2 = data2 ? *data2 : 0;
	dex_cmd = cmd;

	spin_lock_irqsave(&dex_comm_lock, flags);

	DDEX("waiting for modem; command=0x%02x data=0x%x data2=0x%x has_data=0x%x", dex_cmd, dex_data, dex_data2, dex_has_data);
	DDEX("Check DEX Status: %d base adress: 0x%x\n", readl(base + PC_READY), base);

	// Store original cmd byte
	base_cmd = dex_cmd & 0xff;

	// Write only lowest byte
	writeb(base_cmd, base + PC_COMMAND);

	// If we have data to pass, add 0x100 bit and store the data
	if ( dex_has_data )
	{
		writel(readl(base + PC_COMMAND) | DEX_HAS_DATA, base + PC_COMMAND);
		writel(dex_data, base + PC_DATA);
		writel(dex_data2, base + PC_DATA2);
	} else {
		writel(readl(base + PC_COMMAND) & ~DEX_HAS_DATA, base + PC_COMMAND);
		writel(0, base + PC_DATA);
		writel(0, base + PC_DATA2);
	}
	
	// Increment last serial counter
	num = readl(base + PC_SERIAL) + 1;
	writel(num, base + PC_SERIAL);

	DDEX("command and data sent (cntr=0x%x) ...", num);

	// Notify ARM9 with int6
	notify_other_dex_comm();

	// Wait for response...  XXX: check irq stat?
	timeout = TIMEOUT;
	while ( --timeout && readl(base + PC_SERIAL_CHECK) != num )
		udelay(1);

	if ( ! timeout )
	{
		printk(KERN_WARNING "%s: DEX cmd timed out. status=0x%x, A2Mcntr=%x, M2Acntr=%x\n", 
			__func__, readl(base + PC_STATUS), num, readl(base + PC_SERIAL_CHECK));
		goto end;
	}
	
	DDEX("command result status = 0x%08x", readl(base + PC_STATUS));

	// Read status of command
	status = readl(base + PC_STATUS);
	writeb(0, base + PC_STATUS);
	base_status = status & 0xff;
	DDEX("status new = 0x%x; status base = 0x%x", 
		readl(base + PC_STATUS), base_status);


	if ( base_status == base_cmd )
	{
		if ( status & DEX_STATUS_FAIL )
		{
			DDEX("DEX cmd failed; status=%x, result=%x",
				readl(base + PC_STATUS),
				readl(base + PC_DATA_RESULT));

			writel(readl(base + PC_STATUS) & ~DEX_STATUS_FAIL, base + PC_STATUS);
		}
		else if ( status & DEX_HAS_DATA )
		{
			writel(readl(base + PC_STATUS) & ~DEX_HAS_DATA, base + PC_STATUS);
			if (data1)
				*data1 = readl(base + PC_DATA_RESULT);
			if (data2)
				*data2 = readl(base + PC_DATA_RESULT2);
			DDEX("DEX output data = 0x%x  data2 = 0x%x ", 
				readl(base + PC_DATA_RESULT), readl(base + PC_DATA_RESULT2));
		}
	} else {
		printk(KERN_WARNING "%s: DEX Code not match! a2m[0x%x], m2a[0x%x], a2m_num[0x%x], m2a_num[0x%x]\n", 
			__func__, base_cmd, base_status, num, readl(base + PC_SERIAL_CHECK));
	}

end:
	writel(0, base + PC_DATA_RESULT);
	writel(0, base + PC_STATUS);

	spin_unlock_irqrestore(&dex_comm_lock, flags);
	return 0;
}