diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 05e5822d..1bbf3a11 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -2,6 +2,7 @@ obj-y += io.o irq.o timer.o dma.o memory.o obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-y += devices.o pwrtest.o obj-y += proc_comm.o +obj-y += dex_comm.o obj-y += vreg.o obj-y += pmic.o obj-y += remote_spinlock.o diff --git a/arch/arm/mach-msm/dex_comm.c b/arch/arm/mach-msm/dex_comm.c new file mode 100644 index 00000000..a48f3c7d --- /dev/null +++ b/arch/arm/mach-msm/dex_comm.c @@ -0,0 +1,295 @@ +/* arch/arm/mach-msm/dex_comm.c + * + * Author: maejrep + * Markinus + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Based on proc_comm.c by Brian Swetland + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dex_comm.h" + + +// from board-htcleo-power.c +void notify_vbus_change_intr(void); + + +#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) + +static unsigned base = 0; + +static inline void notify_other_dex_comm(void) +{ + uint8_t dex_irq; + if(machine_is_htcleo()) + dex_irq = 4; + else + dex_irq = 6; + writel(1, MSM_A2M_INT(dex_irq)); +} + +#define PC_DEBUG 1 + +#define PC_COMMAND 0x00 +#define PC_STATUS 0x04 +#define PC_SERIAL 0x08 +#define PC_SERIAL_CHECK 0x0C +#define PC_DATA 0x20 +#define PC_DATA_RESULT 0x24 +#define PC_NOTIFY 0x28 +#define PC_DATA2 0x30 +#define PC_DATA_RESULT2 0x34 +#define PC_READY 0x3c + +#if (PC_DEBUG > 0) + #define DDEX(fmt, arg...) printk(KERN_DEBUG "[DEX] %s: " fmt "\n", __FUNCTION__, ## arg) +#else + #define DDEX(fmt, arg...) do {} while (0) +#endif + + +static DEFINE_SPINLOCK(dex_comm_lock); + +/* The higher level SMD support will install this to + * provide a way to check for and handle modem restart? + */ +int (*msm_check_for_modem_crash)(void); + +#define TIMEOUT (10000000) /* 10s in microseconds */ + +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; +} +int dex_audio(int param) +{ + return dex_comm(DEX_AUDIO_CALL, ¶m, 0); +} + + +#if defined(CONFIG_ARCH_QSD8X50) +#define PLLn_BASE(n) (MSM_CLK_CTL_BASE + 0x300 + 32 * (n)) +#else +#define PLLn_BASE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n)) +#endif +#define TCX0 19200000 // Hz +#define PLL_FREQ(l, m, n) (TCX0 * (l) + TCX0 * (m) / (n)) + +#define DUMP_PLL(name, base) { \ + unsigned int mode, L, M, N, freq; \ + mode = readl(base); \ + L = readl(base + 0x4); \ + M = readl(base + 0x8); \ + N = readl(base + 0xc); \ + freq = PLL_FREQ(L, M, N); \ + printk(KERN_INFO "%s @ %p: MODE=%08x L=%08x M=%08x N=%08x freq=%u Hz (%u MHz)\n", \ + name, base, mode, L, M, N, freq, freq / 1000000); \ + } + +// Dump useful debug stuff +void dump_debug_stuff(void) +{ + unsigned int pcb_xc, ver_base; + char amss_ver[16]; + if (machine_is_htcleo()) { + ver_base = 0xef230; + // Dump PLL params (for debug purposes, no relation to dex_comm) + DUMP_PLL("PLL0", PLLn_BASE(0)); + DUMP_PLL("PLL1", PLLn_BASE(1)); + DUMP_PLL("PLL4", PLLn_BASE(4)); + DUMP_PLL("PLL5", PLLn_BASE(5)); + } + else { + ver_base = 0xfc030; + // Dump PLL params (for debug purposes, no relation to dex_comm) + DUMP_PLL("PLL0", PLLn_BASE(0)); + DUMP_PLL("PLL1", PLLn_BASE(1)); + DUMP_PLL("PLL2", PLLn_BASE(2)); + DUMP_PLL("PLL3", PLLn_BASE(3)); + + } + // Dump PCB XC + pcb_xc = readl(MSM_SHARED_RAM_BASE + ver_base + 0x18); + printk(KERN_INFO "PCB XC: %08x\n", pcb_xc); + + // Dump AMMS version + *(unsigned int *) (amss_ver + 0x0) = readl(MSM_SHARED_RAM_BASE + ver_base + 0x0); + *(unsigned int *) (amss_ver + 0x4) = readl(MSM_SHARED_RAM_BASE + ver_base + 0x4); + *(unsigned int *) (amss_ver + 0x8) = readl(MSM_SHARED_RAM_BASE + ver_base + 0x8); + *(unsigned int *) (amss_ver + 0xc) = readl(MSM_SHARED_RAM_BASE + ver_base + 0xc); + amss_ver[15] = 0; + printk(KERN_INFO "AMSS version: %s\n", amss_ver); +} + +/////////////////////////////////////////////////////////////////////// +// DEX callback +/////////////////////////////////////////////////////////////////////// + +static irqreturn_t dex_cb_interrupt(int irq, void *dev_id) +{ + uint32_t nt; + + nt = readl(base + PC_NOTIFY); + writeb(0, base + PC_NOTIFY); // clear state + +// printk("###DEX CB INTR[%08X]###\n", nt); + + if (nt & 2) // VBUS state changed + { + notify_vbus_change_intr(); + } + + return IRQ_HANDLED; +} + + +static struct irqaction dex_callback_irq = +{ + .name = "dex_cb", + .flags = IRQF_TRIGGER_RISING, //IRQF_DISABLED, + .handler = dex_cb_interrupt +}; + + +// Initialize DEX registers +int init_dex_comm() +{ + unsigned long flags; + + setup_irq(INT_A9_M2A_4, &dex_callback_irq); + + if(machine_is_htcleo()) + base = (unsigned)(MSM_SHARED_RAM_BASE + 0xefe00); + else + base = (unsigned)(MSM_SHARED_RAM_BASE + 0xfc100); + + spin_lock_irqsave(&dex_comm_lock, flags); + + writel(0, base + PC_DATA); + writel(0, base + PC_DATA_RESULT); + writel(0, base + PC_SERIAL); + writel(0, base + PC_SERIAL_CHECK); + writel(0, base + PC_STATUS); + + spin_unlock_irqrestore(&dex_comm_lock, flags); + printk(KERN_INFO "%s: WinCE DEX initialized.\n", __func__); + + dump_debug_stuff(); + + return 0; +} diff --git a/arch/arm/mach-msm/dex_comm.h b/arch/arm/mach-msm/dex_comm.h new file mode 100644 index 00000000..b8d0c4e6 --- /dev/null +++ b/arch/arm/mach-msm/dex_comm.h @@ -0,0 +1,134 @@ +/* arch/arm/mach-msm/proc_comm.h + * + * Copyright (c) 2007 QUALCOMM Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_MSM_DEX_COMM_CE_H_ +#define _ARCH_ARM_MACH_MSM_MSM_DEX_COMM_CE_H_ + +// DEX_* research taken from http://wiki.xda-developers.com/index.php?pagename=RaphaelDEX +// Research by cr2 + +#define DEX_HAS_DATA 0x100 +#define DEX_STATUS_FAIL 0x200 + +enum { + DEX_PMIC_WLAN_ON = 0x2, + DEX_PMIC_WLAN_OFF = 0x3, + DEX_PMIC_VIBRA_ON = 0x4, + DEX_PMIC_VIBRA_OFF = 0x5, + DEX_PMIC_IR_ON = 0x6, + DEX_PMIC_IR_OFF = 0x7, + DEX_PMIC_CAM_ON = 0x8, + DEX_PMIC_CAM_OFF = 0x9, + DEX_PMIC_VGACAM_ON = 0xa, + DEX_PMIC_VGACAM_OFF = 0xb, + DEX_PMIC_SD_ON = 0xc, + DEX_PMIC_SD_OFF = 0xd, + DEX_PMIC_LCD_ON = 0xe, + DEX_PMIC_LCD_OFF = 0xf, + DEX_PMIC_MDDI_ON = 0x10, + DEX_PMIC_MDDI_OFF = 0x11, + DEX_PMIC_BT_ON = 0x12, + DEX_PMIC_BT_OFF = 0x13, + DEX_POWER_OFF = 0x14, + DEX_PMIC_REG_ON = 0x15, + DEX_PMIC_REG_OFF = 0x16, + DEX_VIBRA_ON = 0x17, + DEX_VIBRA_OFF = 0x18, + DEX_SET_AUDIO_PATH = 0x19, + DEX_PMIC_REG_VOLTAGE = 0x1a, + DEX_SETUSB_DPLUS = 0x1b, + DEX_AUDIO_CALL = 0x1c, + + //??? + DEX_SET_L2_LOCK_BUS_CLK = 0x1d, + DEX_ARM9_LOW_SPEED = 0x1d, + DEX_REGISTER_VOCODER_PCM = 0x1e, + DEX_UNREGISTER_VOCODER_PCM = 0x1f, + DEX_SET_CLOCK_ON = 0x20, + DEX_SET_CLOCK_OFF = 0x21, + DEX_RESET_ARM9 = 0x22, + + DEX_PMIC_TVOUT_AUTO_ON = 0x25, + DEX_PMIC_TVOUT_AUTO_FF = 0x26, + + DEX_LCD_STATUS = 0x30, + DEX_CONFIG_MPP_PINS = 0x31, + DEX_SET_CHARGER_STATUS = 0x32, + DEX_TASK_REGISTER = 0x33, + DEX_TASK_UNREGISTER = 0x34, + + DEX_UPDATE_ACDB = 0x80, + DEX_READ_RTC = 0x81, + DEX_WRITE_RTC = 0x82, + DEX_SET_ALARM_RTC = 0x84, + + DEX_GET_BATTERY_DATA = 0x8a, + DEX_GET_BATTERY_ID = 0x8b, + + DEX_NOTIFY_ARM9_REBOOT = 0x8e, + + DEX_GET_TX_POWER = 0x90, + DEX_GET_NETWORK_BAND = 0x91, + DEX_GET_GSM_TX_BAND = 0x92, + + DEX_GET_SLEEP_CLOCK = 0xa2, + + DEX_FOTA_READ = 0xa4, + DEX_FOTA_WRITE = 0xa5, +}; + + +// ?? +#define GPIO_ENABLE 0 +#define GPIO_DISABLE 1 + +// .dir (1b) +#define GPIO_INPUT 0 +#define GPIO_OUTPUT 1 + +// .pull (2b) +#define GPIO_NO_PULL 0 +#define GPIO_PULL_DOWN 1 +#define GPIO_KEEPER 2 +#define GPIO_PULL_UP 3 + +// .drvstr (4b) +#define GPIO_2MA 0 +#define GPIO_4MA 1 +#define GPIO_6MA 2 +#define GPIO_8MA 3 +#define GPIO_10MA 4 +#define GPIO_12MA 5 +#define GPIO_14MA 6 +#define GPIO_16MA 7 + +#define DEX_GPIO_CFG(a, b, c, d, e, f) (struct msm_gpio_config){ \ + .gpio = (a), \ + .dir = (c), \ + .out_op = (f), \ + .pull = (d), \ + .func = (b), \ + .drvstr = (e) \ + } + + +int dex_comm(unsigned cmd, unsigned *data1, unsigned *data2); +int dex_audio(int param); + +int init_dex_comm(void); + +#endif + +