Add dex communication interface
This commit is contained in:
parent
fecc9d9350
commit
a143168902
@ -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
|
||||
|
295
arch/arm/mach-msm/dex_comm.c
Normal file
295
arch/arm/mach-msm/dex_comm.c
Normal file
@ -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 <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <mach/msm_iomap.h>
|
||||
#include <mach/system.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#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;
|
||||
}
|
134
arch/arm/mach-msm/dex_comm.h
Normal file
134
arch/arm/mach-msm/dex_comm.h
Normal file
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user