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; }