aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/board-gaia-modems.c
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /arch/arm/mach-exynos/board-gaia-modems.c
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'arch/arm/mach-exynos/board-gaia-modems.c')
-rw-r--r--arch/arm/mach-exynos/board-gaia-modems.c1369
1 files changed, 1369 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/board-gaia-modems.c b/arch/arm/mach-exynos/board-gaia-modems.c
new file mode 100644
index 0000000..e453d6e
--- /dev/null
+++ b/arch/arm/mach-exynos/board-gaia-modems.c
@@ -0,0 +1,1369 @@
+/* linux/arch/arm/mach-xxxx/board-c1via-modems.c
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+/* inlcude platform specific file */
+#include <linux/platform_data/modem.h>
+#include <mach/sec_modem.h>
+#include <mach/gpio.h>
+#include <mach/gpio-exynos5.h>
+#include <plat/gpio-cfg.h>
+#include <mach/regs-mem.h>
+#include <plat/regs-srom.h>
+
+#ifdef CONFIG_USBHUB_USB3503
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/platform_data/usb3503.h>
+#include <mach/cpufreq.h>
+#include <plat/usb-phy.h>
+#endif
+#include <plat/devs.h>
+#include <plat/ehci.h>
+
+#define SROM_CS0_BASE 0x04000000
+#define SROM_WIDTH 0x01000000
+#define SROM_NUM_ADDR_BITS 14
+
+/* For "bus width and wait control (BW)" register */
+enum sromc_attr {
+ SROMC_DATA_16 = 0x1, /* 16-bit data bus */
+ SROMC_BYTE_ADDR = 0x2, /* Byte base address */
+ SROMC_WAIT_EN = 0x4, /* Wait enabled */
+ SROMC_BYTE_EN = 0x8, /* Byte access enabled */
+ SROMC_MASK = 0xF
+};
+
+/* DPRAM configuration */
+struct sromc_cfg {
+ enum sromc_attr attr;
+ unsigned size;
+ unsigned csn; /* CSn # */
+ unsigned addr; /* Start address (physical) */
+ unsigned end; /* End address (physical) */
+};
+
+/* DPRAM access timing configuration */
+struct sromc_access_cfg {
+ u32 tacs; /* Address set-up before CSn */
+ u32 tcos; /* Chip selection set-up before OEn */
+ u32 tacc; /* Access cycle */
+ u32 tcoh; /* Chip selection hold on OEn */
+ u32 tcah; /* Address holding time after CSn */
+ u32 tacp; /* Page mode access cycle at Page mode */
+ u32 pmc; /* Page Mode config */
+};
+
+/* For CMC221 IDPRAM (Internal DPRAM) */
+#define CMC_IDPRAM_SIZE 0x4000 /* 16 KB */
+
+/* FOR CMC221 SFR for IDPRAM */
+#define CMC_INT2CP_REG 0x10 /* Interrupt to CP */
+#define CMC_INT2AP_REG 0x50
+#define CMC_CLR_INT_REG 0x28 /* Clear Interrupt to AP */
+#define CMC_RESET_REG 0x3C
+#define CMC_PUT_REG 0x40 /* AP->CP reg for hostbooting */
+#define CMC_GET_REG 0x50 /* CP->AP reg for hostbooting */
+
+#define INT_MASK_REQ_ACK_F 0x0020
+#define INT_MASK_REQ_ACK_R 0x0010
+#define INT_MASK_RES_ACK_F 0x0008
+#define INT_MASK_RES_ACK_R 0x0004
+#define INT_MASK_SEND_F 0x0002
+#define INT_MASK_SEND_R 0x0001
+
+#define INT_MASK_REQ_ACK_RFS 0x0400 /* Request RES_ACK_RFS */
+#define INT_MASK_RES_ACK_RFS 0x0200 /* Response of REQ_ACK_RFS */
+#define INT_MASK_SEND_RFS 0x0100 /* Indicate sending RFS data */
+
+
+/* Function prototypes */
+static void config_dpram_port_gpio(void);
+static void init_sromc(void);
+static void setup_sromc(unsigned csn, struct sromc_cfg *cfg,
+ struct sromc_access_cfg *acc_cfg);
+static void setup_dpram_speed(unsigned csn, struct sromc_access_cfg *acc_cfg);
+static int __init init_modem(void);
+
+
+#ifdef CONFIG_USBHUB_USB3503
+static int host_port_enable(int port, int enable);
+#else
+/*
+static int host_port_enable(int port, int enable)
+{
+ return s5p_ehci_port_control(&s5p_device_ehci, port, enable);
+}
+*/
+#endif
+
+static struct sromc_cfg cmc_idpram_cfg = {
+ .attr = SROMC_DATA_16,
+ .size = CMC_IDPRAM_SIZE,
+};
+
+static struct sromc_access_cfg cmc_idpram_access_cfg[] = {
+ [DPRAM_SPEED_LOW] = {
+ .tacs = 0x0F << 28,
+ .tcos = 0x0F << 24,
+ .tacc = 0x1F << 16,
+ .tcoh = 0x0F << 12,
+ .tcah = 0x0F << 8,
+ .tacp = 0x00 << 4,
+ .pmc = 0x00 << 0,
+ },
+/* [DPRAM_SPEED_LOW] = {
+ .tacs = 0x01 << 28,
+ .tcos = 0x01 << 24,
+ .tacc = 0x1B << 16,
+ .tcoh = 0x01 << 12,
+ .tcah = 0x01 << 8,
+ .tacp = 0x00 << 4,
+ .pmc = 0x00 << 0,
+ },*/
+ [DPRAM_SPEED_HIGH] = {
+ .tacs = 0x01 << 28,
+ .tcos = 0x01 << 24,
+ .tacc = 0x0B << 16,
+ .tcoh = 0x01 << 12,
+ .tcah = 0x01 << 8,
+ .tacp = 0x00 << 4,
+ .pmc = 0x00 << 0,
+ },
+};
+
+/*
+ magic_code +
+ access_enable +
+ fmt_tx_head + fmt_tx_tail + fmt_tx_buff +
+ raw_tx_head + raw_tx_tail + raw_tx_buff +
+ rfs_tx_head + rfs_tx_tail + rfs_tx_buff +
+ fmt_rx_head + fmt_rx_tail + fmt_rx_buff +
+ raw_rx_head + raw_rx_tail + raw_rx_buff +
+ rfs_rx_head + rfs_rx_tail + rfs_rx_buff +
+ = 2 +
+ 2 +
+ 4 + 4 + 2040 +
+ 4 + 4 + 4088 +
+ 4 + 4 + 1016 +
+ 4 + 4 + 2040 +
+ 4 + 4 + 5112 +
+ 4 + 4 + 2036 +
+ = 16384
+*/
+#define DP_FMT_TX_BUFF_SZ 2040
+#define DP_RAW_TX_BUFF_SZ 4088
+#define DP_RFS_TX_BUFF_SZ 1016
+#define DP_FMT_RX_BUFF_SZ 2040
+#define DP_RAW_RX_BUFF_SZ 5112
+#define DP_RFS_RX_BUFF_SZ 2036
+
+#define MAX_CMC_IDPRAM_IPC_DEV (IPC_RFS + 1) /* FMT, RAW, RFS */
+
+struct dpram_ipc_cfg {
+ u16 magic;
+ u16 access;
+
+ u32 fmt_tx_head;
+ u32 fmt_tx_tail;
+ u8 fmt_tx_buff[DP_FMT_TX_BUFF_SZ];
+
+ u32 raw_tx_head;
+ u32 raw_tx_tail;
+ u8 raw_tx_buff[DP_RAW_TX_BUFF_SZ];
+
+ u32 rfs_tx_head;
+ u32 rfs_tx_tail;
+ u8 rfs_tx_buff[DP_RFS_TX_BUFF_SZ];
+
+ u32 fmt_rx_head;
+ u32 fmt_rx_tail;
+ u8 fmt_rx_buff[DP_FMT_RX_BUFF_SZ];
+
+ u32 raw_rx_head;
+ u32 raw_rx_tail;
+ u8 raw_rx_buff[DP_RAW_RX_BUFF_SZ];
+
+ u32 rfs_rx_head;
+ u32 rfs_rx_tail;
+ u8 rfs_rx_buff[DP_RFS_RX_BUFF_SZ];
+};
+
+struct cmc_dpram_circ {
+ u32 __iomem *head;
+ u32 __iomem *tail;
+ u8 __iomem *buff;
+ u32 size;
+};
+
+struct cmc_dpram_ipc_device {
+ char name[16];
+ int id;
+
+ struct cmc_dpram_circ txq;
+ struct cmc_dpram_circ rxq;
+
+ u16 mask_req_ack;
+ u16 mask_res_ack;
+ u16 mask_send;
+};
+
+struct cmc_dpram_ipc_map {
+ u16 __iomem *magic;
+ u16 __iomem *access;
+
+ struct cmc_dpram_ipc_device dev[MAX_CMC_IDPRAM_IPC_DEV];
+};
+
+struct cmc221_idpram_sfr {
+ u16 __iomem *int2cp;
+ u16 __iomem *int2ap;
+ u16 __iomem *clr_int2ap;
+ u16 __iomem *reset;
+ u16 __iomem *msg2cp;
+ u16 __iomem *msg2ap;
+};
+
+static struct cmc_dpram_ipc_map cmc_ipc_map;
+static u8 *cmc_sfr_base;
+static struct cmc221_idpram_sfr cmc_sfr;
+
+/* Function prototypes */
+static void cmc_idpram_reset(void);
+static void cmc_idpram_setup_speed(enum dpram_speed);
+static int cmc_idpram_wakeup(void);
+static void cmc_idpram_sleep(void);
+static void cmc_idpram_clr_intr(void);
+static u16 cmc_idpram_recv_intr(void);
+static void cmc_idpram_send_intr(u16 irq_mask);
+static u16 cmc_idpram_recv_msg(void);
+static void cmc_idpram_send_msg(u16 msg);
+
+static u16 cmc_idpram_get_magic(void);
+static void cmc_idpram_set_magic(u16 value);
+static u16 cmc_idpram_get_access(void);
+static void cmc_idpram_set_access(u16 value);
+
+static u32 cmc_idpram_get_tx_head(int dev_id);
+static u32 cmc_idpram_get_tx_tail(int dev_id);
+static void cmc_idpram_set_tx_head(int dev_id, u32 head);
+static void cmc_idpram_set_tx_tail(int dev_id, u32 tail);
+static u8 __iomem *cmc_idpram_get_tx_buff(int dev_id);
+static u32 cmc_idpram_get_tx_buff_size(int dev_id);
+
+static u32 cmc_idpram_get_rx_head(int dev_id);
+static u32 cmc_idpram_get_rx_tail(int dev_id);
+static void cmc_idpram_set_rx_head(int dev_id, u32 head);
+static void cmc_idpram_set_rx_tail(int dev_id, u32 tail);
+static u8 __iomem *cmc_idpram_get_rx_buff(int dev_id);
+static u32 cmc_idpram_get_rx_buff_size(int dev_id);
+
+static u16 cmc_idpram_get_mask_req_ack(int dev_id);
+static u16 cmc_idpram_get_mask_res_ack(int dev_id);
+static u16 cmc_idpram_get_mask_send(int dev_id);
+
+static struct modemlink_dpram_control cmc_idpram_ctrl = {
+ .reset = cmc_idpram_reset,
+
+ .setup_speed = cmc_idpram_setup_speed,
+
+ .wakeup = cmc_idpram_wakeup,
+ .sleep = cmc_idpram_sleep,
+
+ .clear_intr = cmc_idpram_clr_intr,
+ .recv_intr = cmc_idpram_recv_intr,
+ .send_intr = cmc_idpram_send_intr,
+ .recv_msg = cmc_idpram_recv_msg,
+ .send_msg = cmc_idpram_send_msg,
+
+ .get_magic = cmc_idpram_get_magic,
+ .set_magic = cmc_idpram_set_magic,
+ .get_access = cmc_idpram_get_access,
+ .set_access = cmc_idpram_set_access,
+
+ .get_tx_head = cmc_idpram_get_tx_head,
+ .get_tx_tail = cmc_idpram_get_tx_tail,
+ .set_tx_head = cmc_idpram_set_tx_head,
+ .set_tx_tail = cmc_idpram_set_tx_tail,
+ .get_tx_buff = cmc_idpram_get_tx_buff,
+ .get_tx_buff_size = cmc_idpram_get_tx_buff_size,
+
+ .get_rx_head = cmc_idpram_get_rx_head,
+ .get_rx_tail = cmc_idpram_get_rx_tail,
+ .set_rx_head = cmc_idpram_set_rx_head,
+ .set_rx_tail = cmc_idpram_set_rx_tail,
+ .get_rx_buff = cmc_idpram_get_rx_buff,
+ .get_rx_buff_size = cmc_idpram_get_rx_buff_size,
+
+ .get_mask_req_ack = cmc_idpram_get_mask_req_ack,
+ .get_mask_res_ack = cmc_idpram_get_mask_res_ack,
+ .get_mask_send = cmc_idpram_get_mask_send,
+
+ .dp_base = NULL,
+ .dp_size = 0,
+ .dp_type = CP_IDPRAM,
+ .aligned = 1,
+
+ .dpram_irq = CMC_IDPRAM_INT_IRQ_00,
+ .dpram_irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_RISING),
+ .dpram_irq_name = "CMC221_IDPRAM_IRQ",
+ .dpram_wlock_name = "CMC221_IDPRAM_WLOCK",
+
+ .max_ipc_dev = MAX_CMC_IDPRAM_IPC_DEV,
+};
+
+/*
+** UMTS target platform data
+*/
+static struct modem_io_t umts_io_devices[] = {
+ [0] = {
+ .name = "umts_boot0",
+ .id = 0x0,
+ .format = IPC_BOOT,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [1] = {
+ .name = "umts_ipc0",
+ .id = 0x0,
+ .format = IPC_FMT,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [2] = {
+ .name = "umts_rfs0",
+ .id = 0x0,
+ .format = IPC_RFS,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [3] = {
+ .name = "umts_multipdp",
+ .id = 0x1,
+ .format = IPC_MULTI_RAW,
+ .io_type = IODEV_DUMMY,
+ /* .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), */
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ .tx_link = LINKDEV_DPRAM,
+ },
+ [4] = {
+ .name = "rmnet0",
+ .id = 0x2A,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [5] = {
+ .name = "rmnet1",
+ .id = 0x2B,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [6] = {
+ .name = "rmnet2",
+ .id = 0x2C,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [7] = {
+ .name = "rmnet3",
+ .id = 0x2D,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [8] = {
+ .name = "umts_rmnet4",
+ .id = 0x27,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [9] = {
+ .name = "umts_rmnet5",
+ .id = 0x3A,
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [10] = {
+ .name = "umts_router", /* AT Iface & Dial-up */
+ .id = 0x3E, /* Channel 30 (0x3E & 0x1F) */
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [11] = {
+ .name = "umts_csd",
+ .id = 0x21,
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [12] = {
+ .name = "umts_ramdump0",
+ .id = 0x0,
+ .format = IPC_RAMDUMP,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [13] = {
+ .name = "umts_loopback0",
+ .id = 0x0,
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+ [14] = {
+ .name = "umts_dm0", /* DM Port */
+ .id = 0x3F, /* Channel 31 (0x3F & 0x1F) */
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_DPRAM),
+ },
+/*
+ [15] = {
+ .name = "lte_ipc0",
+ .id = 0x1,
+ .format = IPC_FMT,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_USB),
+ },
+*/
+};
+
+/*
+static int exynos_cpu_frequency_lock(void);
+static int exynos_cpu_frequency_unlock(void);
+*/
+
+static struct modemlink_pm_data umts_link_pm_data = {
+ .name = "umts_link_pm",
+
+ .gpio_link_enable = 0,
+ /*
+ .gpio_link_active = GPIO_ACTIVE_STATE,
+ .gpio_link_hostwake = GPIO_IPC_HOST_WAKEUP,
+ .gpio_link_slavewake = GPIO_IPC_SLAVE_WAKEUP,
+
+ .port_enable = host_port_enable,
+
+ .link_reconnect = umts_link_reconnect,
+ */
+ .freqlock = ATOMIC_INIT(0),
+ /*
+ .cpufreq_lock = exynos_cpu_frequency_lock,
+ .cpufreq_unlock = exynos_cpu_frequency_unlock,
+ */
+};
+
+static struct modem_data umts_modem_data = {
+ .name = "cmc221",
+
+ .gpio_cp_on = CP_CMC221_PMIC_PWRON,
+ .gpio_cp_reset = CP_CMC221_CPU_RST,
+ .gpio_phone_active = GPIO_LTE_ACTIVE,
+
+ .gpio_dpram_int = GPIO_CMC_IDPRAM_INT_00,
+ .gpio_dpram_status = GPIO_CMC_IDPRAM_STATUS,
+ .gpio_dpram_wakeup = GPIO_CMC_IDPRAM_WAKEUP,
+ /*
+ .gpio_slave_wakeup = GPIO_IPC_SLAVE_WAKEUP,
+ .gpio_host_active = GPIO_ACTIVE_STATE,
+ .gpio_host_wakeup = GPIO_IPC_HOST_WAKEUP,
+ */
+ .modem_net = UMTS_NETWORK,
+ .modem_type = SEC_CMC221,
+ /* .link_types = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), */
+ .link_types = LINKTYPE(LINKDEV_DPRAM),
+ .link_name = "cmc221_idpram",
+ .dpram_ctl = &cmc_idpram_ctrl,
+
+ .num_iodevs = ARRAY_SIZE(umts_io_devices),
+ .iodevs = umts_io_devices,
+
+ .link_pm_data = &umts_link_pm_data,
+
+ .ipc_version = SIPC_VER_41,
+};
+
+static struct resource umts_modem_res[] = {
+ [0] = {
+ .name = "cp_active_irq",
+ .start = LTE_ACTIVE_IRQ,
+ .end = LTE_ACTIVE_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device umts_modem = {
+ .name = "modem_if",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(umts_modem_res),
+ .resource = umts_modem_res,
+ .dev = {
+ .platform_data = &umts_modem_data,
+ },
+};
+
+#define HUB_STATE_OFF 0
+#if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB)
+void set_hsic_lpa_states(int states)
+{
+ int val = gpio_get_value(umts_modem_data.gpio_cp_reset);
+
+ mif_trace("\n");
+
+ if (val && states == STATE_HSIC_LPA_ENTER) {
+ pr_info("mif: usb3503: %s: hub off - lpa\n", __func__);
+ host_port_enable(2, 0);
+ *(umts_link_pm_data.p_hub_status) = HUB_STATE_OFF;
+ }
+}
+#endif
+
+int get_cp_active_state(void)
+{
+ return gpio_get_value(umts_modem_data.gpio_phone_active);
+}
+
+static void cmc_idpram_reset(void)
+{
+ iowrite16(1, cmc_sfr.reset);
+}
+
+static void cmc_idpram_setup_speed(enum dpram_speed speed)
+{
+ setup_dpram_speed(cmc_idpram_cfg.csn, &cmc_idpram_access_cfg[speed]);
+}
+
+static int cmc_idpram_wakeup(void)
+{
+ int cnt = 0;
+ u16 magic = 0;
+ u16 access = 0;
+
+ gpio_set_value(umts_modem_data.gpio_dpram_wakeup, 1);
+
+ cnt = 0;
+ while (!gpio_get_value(umts_modem_data.gpio_dpram_status)) {
+ if (cnt++ > 10) {
+ pr_err("[MDM/E] <%s> gpio_dpram_status == 0\n",
+ __func__);
+ break; /* return -EAGAIN; */
+ }
+
+ if (in_interrupt())
+ mdelay(1);
+ else
+ msleep_interruptible(1);
+ }
+
+ return 0;
+}
+
+static void cmc_idpram_sleep(void)
+{
+ gpio_set_value(umts_modem_data.gpio_dpram_wakeup, 0);
+}
+
+static void cmc_idpram_clr_intr(void)
+{
+ iowrite16(0xFFFF, cmc_sfr.clr_int2ap);
+ iowrite16(0, cmc_sfr.int2ap);
+}
+
+static u16 cmc_idpram_recv_intr(void)
+{
+ return ioread16(cmc_sfr.int2ap);
+}
+
+static void cmc_idpram_send_intr(u16 irq_mask)
+{
+ iowrite16(irq_mask, cmc_sfr.int2cp);
+}
+
+static u16 cmc_idpram_recv_msg(void)
+{
+ return ioread16(cmc_sfr.msg2ap);
+}
+
+static void cmc_idpram_send_msg(u16 msg)
+{
+ iowrite16(msg, cmc_sfr.msg2cp);
+}
+
+static u16 cmc_idpram_get_magic(void)
+{
+ return ioread16(cmc_ipc_map.magic);
+}
+
+static void cmc_idpram_set_magic(u16 value)
+{
+ iowrite16(value, cmc_ipc_map.magic);
+}
+
+static u16 cmc_idpram_get_access(void)
+{
+ return ioread16(cmc_ipc_map.access);
+}
+
+static void cmc_idpram_set_access(u16 value)
+{
+ iowrite16(value, cmc_ipc_map.access);
+}
+
+static u32 cmc_idpram_get_tx_head(int dev_id)
+{
+ return ioread32(cmc_ipc_map.dev[dev_id].txq.head);
+}
+
+static u32 cmc_idpram_get_tx_tail(int dev_id)
+{
+ return ioread32(cmc_ipc_map.dev[dev_id].txq.tail);
+}
+
+static void cmc_idpram_set_tx_head(int dev_id, u32 head)
+{
+ int cnt = 100;
+ u32 val = 0;
+
+ iowrite32(head, cmc_ipc_map.dev[dev_id].txq.head);
+
+ do {
+ /* Check head value written */
+ val = ioread32(cmc_ipc_map.dev[dev_id].txq.head);
+ if (val == head)
+ break;
+
+ pr_err("[MDM/E] <%s> txq.head(%d) != head(%d)\n",
+ __func__, val, head);
+
+ /* Write head value again */
+ iowrite32(head, cmc_ipc_map.dev[dev_id].txq.head);
+ } while (cnt--);
+}
+
+static void cmc_idpram_set_tx_tail(int dev_id, u32 tail)
+{
+ int cnt = 100;
+ u32 val = 0;
+
+ iowrite32(tail, cmc_ipc_map.dev[dev_id].txq.tail);
+
+ do {
+ /* Check tail value written */
+ val = ioread32(cmc_ipc_map.dev[dev_id].txq.tail);
+ if (val == tail)
+ break;
+
+ pr_err("[MDM/E] <%s> txq.tail(%d) != tail(%d)\n",
+ __func__, val, tail);
+
+ /* Write tail value again */
+ iowrite32(tail, cmc_ipc_map.dev[dev_id].txq.tail);
+ } while (cnt--);
+}
+
+static u8 __iomem *cmc_idpram_get_tx_buff(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].txq.buff;
+}
+
+static u32 cmc_idpram_get_tx_buff_size(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].txq.size;
+}
+
+static u32 cmc_idpram_get_rx_head(int dev_id)
+{
+ return ioread32(cmc_ipc_map.dev[dev_id].rxq.head);
+}
+
+static u32 cmc_idpram_get_rx_tail(int dev_id)
+{
+ return ioread32(cmc_ipc_map.dev[dev_id].rxq.tail);
+}
+
+static void cmc_idpram_set_rx_head(int dev_id, u32 head)
+{
+ int cnt = 100;
+ u32 val = 0;
+
+ iowrite32(head, cmc_ipc_map.dev[dev_id].rxq.head);
+
+ do {
+ /* Check head value written */
+ val = ioread32(cmc_ipc_map.dev[dev_id].rxq.head);
+ if (val == head)
+ break;
+
+ pr_err("[MDM/E] <%s> rxq.head(%d) != head(%d)\n",
+ __func__, val, head);
+
+ /* Write head value again */
+ iowrite32(head, cmc_ipc_map.dev[dev_id].rxq.head);
+ } while (cnt--);
+}
+
+static void cmc_idpram_set_rx_tail(int dev_id, u32 tail)
+{
+ int cnt = 100;
+ u32 val = 0;
+
+ iowrite32(tail, cmc_ipc_map.dev[dev_id].rxq.tail);
+
+ do {
+ /* Check tail value written */
+ val = ioread32(cmc_ipc_map.dev[dev_id].rxq.tail);
+ if (val == tail)
+ break;
+
+ pr_err("[MDM/E] <%s> rxq.tail(%d) != tail(%d)\n",
+ __func__, val, tail);
+
+ /* Write tail value again */
+ iowrite32(tail, cmc_ipc_map.dev[dev_id].rxq.tail);
+ } while (cnt--);
+}
+
+static u8 __iomem *cmc_idpram_get_rx_buff(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].rxq.buff;
+}
+
+static u32 cmc_idpram_get_rx_buff_size(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].rxq.size;
+}
+
+static u16 cmc_idpram_get_mask_req_ack(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].mask_req_ack;
+}
+
+static u16 cmc_idpram_get_mask_res_ack(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].mask_res_ack;
+}
+
+static u16 cmc_idpram_get_mask_send(int dev_id)
+{
+ return cmc_ipc_map.dev[dev_id].mask_send;
+}
+
+/* Set dynamic environment for a modem */
+static void setup_umts_modem_env(void)
+{
+ /* Config DPRAM control structure */
+ cmc_idpram_cfg.csn = 0;
+ cmc_idpram_cfg.addr = SROM_CS0_BASE + (SROM_WIDTH * cmc_idpram_cfg.csn);
+ cmc_idpram_cfg.end = cmc_idpram_cfg.addr + cmc_idpram_cfg.size - 1;
+
+ umts_modem_data.gpio_dpram_int = GPIO_CMC_IDPRAM_INT_00;
+}
+
+static void config_umts_modem_gpio(void)
+{
+ int err = 0;
+ unsigned gpio_cp_on = umts_modem_data.gpio_cp_on;
+ unsigned gpio_cp_rst = umts_modem_data.gpio_cp_reset;
+ unsigned gpio_pda_active = umts_modem_data.gpio_pda_active;
+ unsigned gpio_phone_active = umts_modem_data.gpio_phone_active;
+ unsigned gpio_active_state = umts_modem_data.gpio_host_active;
+ unsigned gpio_host_wakeup = umts_modem_data.gpio_host_wakeup;
+ unsigned gpio_slave_wakeup = umts_modem_data.gpio_slave_wakeup;
+ unsigned gpio_dpram_int = umts_modem_data.gpio_dpram_int;
+ unsigned gpio_dpram_status = umts_modem_data.gpio_dpram_status;
+ unsigned gpio_dpram_wakeup = umts_modem_data.gpio_dpram_wakeup;
+
+ pr_info("[MDM] <%s>\n", __func__);
+
+ if (gpio_cp_on) {
+ err = gpio_request(gpio_cp_on, "CMC_ON");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_ON");
+ } else {
+ gpio_direction_output(gpio_cp_on, 0);
+ s3c_gpio_setpull(gpio_cp_on, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_cp_rst) {
+ err = gpio_request(gpio_cp_rst, "CMC_RST");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_RST");
+ } else {
+ gpio_direction_output(gpio_cp_rst, 0);
+ s3c_gpio_setpull(gpio_cp_rst, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_pda_active) {
+ err = gpio_request(gpio_pda_active, "PDA_ACTIVE");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "PDA_ACTIVE");
+ } else {
+ gpio_direction_output(gpio_pda_active, 0);
+ s3c_gpio_setpull(gpio_pda_active, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_phone_active) {
+ err = gpio_request(gpio_phone_active, "CMC_ACTIVE");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_ACTIVE");
+ } else {
+ s3c_gpio_cfgpin(gpio_phone_active, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(gpio_phone_active, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_active_state) {
+ err = gpio_request(gpio_active_state, "CMC_ACTIVE_STATE");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_ACTIVE_STATE");
+ } else {
+ gpio_direction_output(gpio_active_state, 0);
+ s3c_gpio_setpull(gpio_active_state, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_slave_wakeup) {
+ err = gpio_request(gpio_slave_wakeup, "CMC_SLAVE_WAKEUP");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_SLAVE_WAKEUP");
+ } else {
+ gpio_direction_output(gpio_slave_wakeup, 0);
+ s3c_gpio_setpull(gpio_slave_wakeup, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_host_wakeup) {
+ err = gpio_request(gpio_host_wakeup, "CMC_HOST_WAKEUP");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_HOST_WAKEUP");
+ } else {
+ s3c_gpio_cfgpin(gpio_host_wakeup, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(gpio_host_wakeup, S3C_GPIO_PULL_DOWN);
+ }
+ }
+
+ if (gpio_dpram_int) {
+ err = gpio_request(gpio_dpram_int, "CMC_DPRAM_INT");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_DPRAM_INT");
+ } else {
+ /* Configure as a wake-up source */
+ s3c_gpio_cfgpin(gpio_dpram_int, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(gpio_dpram_int, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_dpram_status) {
+ err = gpio_request(gpio_dpram_status, "CMC_DPRAM_STATUS");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_DPRAM_STATUS");
+ } else {
+ /* Configure as a wake-up source */
+ s3c_gpio_cfgpin(gpio_dpram_status, S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(gpio_dpram_status, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ if (gpio_dpram_wakeup) {
+ err = gpio_request(gpio_dpram_wakeup, "CMC_DPRAM_WAKEUP");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "CMC_DPRAM_WAKEUP");
+ } else {
+ gpio_direction_output(gpio_dpram_wakeup, 1);
+ s3c_gpio_setpull(gpio_dpram_wakeup, S3C_GPIO_PULL_NONE);
+ }
+ }
+}
+
+static u8 *cmc_idpram_remap_mem_region(struct sromc_cfg *cfg)
+{
+ int dp_addr = 0;
+ int dp_size = 0;
+ u8 __iomem *dp_base = NULL;
+ struct dpram_ipc_cfg *ipc_map = NULL;
+ struct cmc_dpram_ipc_device *dev = NULL;
+
+ dp_addr = cfg->addr;
+ dp_size = cfg->size;
+
+ dp_base = (u8 *)ioremap_nocache(dp_addr, dp_size);
+ if (!dp_base) {
+ pr_err("[MDM] <%s> dpram base ioremap fail\n", __func__);
+ return NULL;
+ }
+ pr_info("[MDM] <%s> DPRAM VA=0x%08X\n", __func__, (int)dp_base);
+
+ cmc_sfr_base = (u8 *)ioremap_nocache((dp_addr + dp_size), dp_size);
+ if (cmc_sfr_base == NULL) {
+ pr_err("[MDM] <%s> Failed in ioremap_nocache()\n", __func__);
+ return NULL;
+ }
+
+ cmc_sfr.int2cp = (u16 __iomem *)(cmc_sfr_base + CMC_INT2CP_REG);
+ cmc_sfr.int2ap = (u16 __iomem *)(cmc_sfr_base + CMC_INT2AP_REG);
+ cmc_sfr.clr_int2ap = (u16 __iomem *)(cmc_sfr_base + CMC_CLR_INT_REG);
+ cmc_sfr.reset = (u16 __iomem *)(cmc_sfr_base + CMC_RESET_REG);
+ cmc_sfr.msg2cp = (u16 __iomem *)(cmc_sfr_base + CMC_PUT_REG);
+ cmc_sfr.msg2ap = (u16 __iomem *)(cmc_sfr_base + CMC_GET_REG);
+
+
+ cmc_idpram_ctrl.dp_base = (u8 __iomem *)dp_base;
+ cmc_idpram_ctrl.dp_size = dp_size;
+
+ /* Map for IPC */
+ ipc_map = (struct dpram_ipc_cfg *)dp_base;
+
+ /* Magic code and access enable fields */
+ cmc_ipc_map.magic = (u16 __iomem *)&ipc_map->magic;
+ cmc_ipc_map.access = (u16 __iomem *)&ipc_map->access;
+
+ /* FMT */
+ dev = &cmc_ipc_map.dev[IPC_FMT];
+
+ strcpy(dev->name, "FMT");
+ dev->id = IPC_FMT;
+
+ dev->txq.head = (u32 __iomem *)&ipc_map->fmt_tx_head;
+ dev->txq.tail = (u32 __iomem *)&ipc_map->fmt_tx_tail;
+ dev->txq.buff = (u8 __iomem *)&ipc_map->fmt_tx_buff[0];
+ dev->txq.size = DP_FMT_TX_BUFF_SZ;
+
+ dev->rxq.head = (u32 __iomem *)&ipc_map->fmt_rx_head;
+ dev->rxq.tail = (u32 __iomem *)&ipc_map->fmt_rx_tail;
+ dev->rxq.buff = (u8 __iomem *)&ipc_map->fmt_rx_buff[0];
+ dev->rxq.size = DP_FMT_RX_BUFF_SZ;
+
+ dev->mask_req_ack = INT_MASK_REQ_ACK_F;
+ dev->mask_res_ack = INT_MASK_RES_ACK_F;
+ dev->mask_send = INT_MASK_SEND_F;
+
+ /* RAW */
+ dev = &cmc_ipc_map.dev[IPC_RAW];
+
+ strcpy(dev->name, "RAW");
+ dev->id = IPC_RAW;
+
+ dev->txq.head = (u32 __iomem *)&ipc_map->raw_tx_head;
+ dev->txq.tail = (u32 __iomem *)&ipc_map->raw_tx_tail;
+ dev->txq.buff = (u8 __iomem *)&ipc_map->raw_tx_buff[0];
+ dev->txq.size = DP_RAW_TX_BUFF_SZ;
+
+ dev->rxq.head = (u32 __iomem *)&ipc_map->raw_rx_head;
+ dev->rxq.tail = (u32 __iomem *)&ipc_map->raw_rx_tail;
+ dev->rxq.buff = (u8 __iomem *)&ipc_map->raw_rx_buff[0];
+ dev->rxq.size = DP_RAW_RX_BUFF_SZ;
+
+ dev->mask_req_ack = INT_MASK_REQ_ACK_R;
+ dev->mask_res_ack = INT_MASK_RES_ACK_R;
+ dev->mask_send = INT_MASK_SEND_R;
+
+ /* RFS */
+ dev = &cmc_ipc_map.dev[IPC_RFS];
+
+ strcpy(dev->name, "RFS");
+ dev->id = IPC_RFS;
+
+ dev->txq.head = (u32 __iomem *)&ipc_map->rfs_tx_head;
+ dev->txq.tail = (u32 __iomem *)&ipc_map->rfs_tx_tail;
+ dev->txq.buff = (u8 __iomem *)&ipc_map->rfs_tx_buff[0];
+ dev->txq.size = DP_RFS_TX_BUFF_SZ;
+
+ dev->rxq.head = (u32 __iomem *)&ipc_map->rfs_rx_head;
+ dev->rxq.tail = (u32 __iomem *)&ipc_map->rfs_rx_tail;
+ dev->rxq.buff = (u8 __iomem *)&ipc_map->rfs_rx_buff[0];
+ dev->rxq.size = DP_RFS_RX_BUFF_SZ;
+
+ dev->mask_req_ack = INT_MASK_REQ_ACK_RFS;
+ dev->mask_res_ack = INT_MASK_RES_ACK_RFS;
+ dev->mask_send = INT_MASK_SEND_RFS;
+
+ return dp_base;
+}
+
+/**
+ * DPRAM GPIO settings
+ *
+ * SROM_NUM_ADDR_BITS value indicate the address line number or
+ * the mux/demux dpram type. if you want to set mux mode, define the
+ * SROM_NUM_ADDR_BITS to zero.
+ *
+ * for CMC22x
+ * CMC22x has 16KB + a SFR register address.
+ * It used 14 bits (13bits for 16KB word address and 1 bit for SFR
+ * register)
+ */
+static void config_dpram_port_gpio(void)
+{
+ int addr_bits = SROM_NUM_ADDR_BITS;
+
+ pr_info("[MDM] <%s> address line = %d bits\n", __func__, addr_bits);
+
+ /*
+ ** Config DPRAM address/data GPIO pins
+ */
+
+ /* Set GPIO for address bus (13 ~ 14 bits) */
+ switch (addr_bits) {
+ case 0:
+ break;
+
+ case 13 ... 14:
+ s3c_gpio_cfgrange_nopull(GPIO_SROM_ADDR_BUS_LOW,
+ EXYNOS4_GPIO_Y3_NR, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgrange_nopull(GPIO_SROM_ADDR_BUS_HIGH,
+ (addr_bits - EXYNOS4_GPIO_Y3_NR), S3C_GPIO_SFN(2));
+ break;
+
+ default:
+ pr_err("[MDM/E] <%s> Invalid addr_bits!!!\n", __func__);
+ return;
+ }
+
+ /* Set GPIO for data bus (16 bits) */
+ s3c_gpio_cfgrange_nopull(GPIO_SROM_DATA_BUS_LOW, 8, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgrange_nopull(GPIO_SROM_DATA_BUS_HIGH, 8, S3C_GPIO_SFN(2));
+
+ /* Setup SROMC CSn pins */
+ s3c_gpio_cfgpin(GPIO_DPRAM_CSN0, S3C_GPIO_SFN(2));
+
+ /* Config OEn, WEn */
+ s3c_gpio_cfgpin(GPIO_DPRAM_REN, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin(GPIO_DPRAM_WEN, S3C_GPIO_SFN(2));
+}
+
+static void init_sromc(void)
+{
+ struct clk *clk = NULL;
+
+ /* SROMC clk enable */
+ clk = clk_get(NULL, "sromc");
+ if (!clk) {
+ pr_err("[MDM/E] <%s> SROMC clock gate fail\n", __func__);
+ return;
+ }
+ clk_enable(clk);
+}
+
+static void setup_sromc
+(
+ unsigned csn,
+ struct sromc_cfg *cfg,
+ struct sromc_access_cfg *acc_cfg
+)
+{
+ unsigned bw = 0; /* Bus width and wait control */
+ unsigned bc = 0; /* Vank control */
+ void __iomem *bank_sfr = S5P_SROM_BC0 + (4 * csn);
+
+ pr_err("[MDM] <%s> SROMC settings for CS%d...\n", __func__, csn);
+
+ bw = __raw_readl(S5P_SROM_BW);
+ bc = __raw_readl(bank_sfr);
+ pr_err("[MDM] <%s> Old SROMC settings = BW(0x%08X), BC%d(0x%08X)\n",
+ __func__, bw, csn, bc);
+
+ /* Set the BW control field for the CSn */
+ bw &= ~(SROMC_MASK << (csn << 2));
+ bw |= (cfg->attr << (csn << 2));
+ writel(bw, S5P_SROM_BW);
+
+ /* Set SROMC memory access timing for the CSn */
+ bc = acc_cfg->tacs | acc_cfg->tcos | acc_cfg->tacc |
+ acc_cfg->tcoh | acc_cfg->tcah | acc_cfg->tacp | acc_cfg->pmc;
+
+ writel(bc, bank_sfr);
+
+ /* Verify SROMC settings */
+ bw = __raw_readl(S5P_SROM_BW);
+ bc = __raw_readl(bank_sfr);
+ pr_err("[MDM] <%s> New SROMC settings = BW(0x%08X), BC%d(0x%08X)\n",
+ __func__, bw, csn, bc);
+}
+
+static void setup_dpram_speed(unsigned csn, struct sromc_access_cfg *acc_cfg)
+{
+ void __iomem *bank_sfr = S5P_SROM_BC0 + (4 * csn);
+ unsigned bc = 0;
+
+ bc = __raw_readl(bank_sfr);
+ pr_info("[MDM] <%s> Old CS%d setting = 0x%08X\n", __func__, csn, bc);
+
+ /* SROMC memory access timing setting */
+ bc = acc_cfg->tacs | acc_cfg->tcos | acc_cfg->tacc |
+ acc_cfg->tcoh | acc_cfg->tcah | acc_cfg->tacp | acc_cfg->pmc;
+ writel(bc, bank_sfr);
+
+ bc = __raw_readl(bank_sfr);
+ pr_info("[MDM] <%s> New CS%d setting = 0x%08X\n", __func__, csn, bc);
+}
+
+static int __init init_modem(void)
+{
+ struct sromc_cfg *cfg = NULL;
+ struct sromc_access_cfg *acc_cfg = NULL;
+
+ pr_err("[MODEM_IF] <%s> System Revision = %d\n", __func__, system_rev);
+
+ setup_umts_modem_env();
+
+ config_dpram_port_gpio();
+
+ config_umts_modem_gpio();
+
+ init_sromc();
+
+ cfg = &cmc_idpram_cfg;
+ acc_cfg = &cmc_idpram_access_cfg[DPRAM_SPEED_LOW];
+
+ setup_sromc(cfg->csn, cfg, acc_cfg);
+
+ if (!cmc_idpram_remap_mem_region(&cmc_idpram_cfg))
+ return -1;
+
+ platform_device_register(&umts_modem);
+
+ pr_err("[MODEM_IF] %s: DONE!!\n", __func__);
+ return 0;
+}
+late_initcall(init_modem);
+/*device_initcall(init_modem);*/
+
+
+
+
+
+
+#ifdef CONFIG_USBHUB_USB3503
+static int (*usbhub_set_mode)(struct usb3503_hubctl *, int);
+static struct usb3503_hubctl *usbhub_ctl;
+
+#ifdef CONFIG_EXYNOS4_CPUFREQ
+static int exynos_cpu_frequency_lock(void)
+{
+ unsigned int level, freq = 700;
+
+ if (atomic_read(&umts_link_pm_data.freqlock) == 0) {
+ if (exynos_cpufreq_get_level(freq * 1000, &level)) {
+ pr_err("[MIF] exynos_cpufreq_get_level is fail\n");
+ return -EINVAL;
+ }
+
+ if (exynos_cpufreq_lock(DVFS_LOCK_ID_USB_IF, level)) {
+ pr_err("[MIF] exynos_cpufreq_lock is fail\n");
+ return -EINVAL;
+ }
+
+ atomic_set(&umts_link_pm_data.freqlock, 1);
+ pr_debug("[MIF] %s: <%d>%dMHz\n", __func__, level, freq);
+ }
+ return 0;
+}
+
+static int exynos_cpu_frequency_unlock(void)
+{
+ if (atomic_read(&umts_link_pm_data.freqlock) == 1) {
+ exynos_cpufreq_lock_free(DVFS_LOCK_ID_USB_IF);
+ atomic_set(&umts_link_pm_data.freqlock, 0);
+ pr_debug("[MIF] %s\n", __func__);
+ }
+ return 0;
+}
+#else /* for CONFIG_EXYNOS4_CPUFREQ */
+static int exynos_cpu_frequency_lock(void)
+{
+ return 0;
+}
+
+static int exynos_cpu_frequency_unlock(void)
+{
+ return 0;
+}
+#endif /* for CONFIG_EXYNOS4_CPUFREQ */
+
+void set_host_states(struct platform_device *pdev, int type)
+{
+}
+
+static int usb3503_hub_handler(void (*set_mode)(void), void *ctl)
+{
+ if (!set_mode || !ctl)
+ return -EINVAL;
+
+ usbhub_set_mode = (int (*)(struct usb3503_hubctl *, int))set_mode;
+ usbhub_ctl = (struct usb3503_hubctl *)ctl;
+
+ pr_info("[MDM] <%s> set_mode(%pF)\n", __func__, set_mode);
+
+ return 0;
+}
+
+static int usb3503_hw_config(void)
+{
+ int err;
+
+ err = gpio_request(GPIO_USB_HUB_RST, "HUB_RST");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "HUB_RST");
+ } else {
+ gpio_direction_output(GPIO_USB_HUB_RST, 0);
+ s3c_gpio_setpull(GPIO_USB_HUB_RST, S3C_GPIO_PULL_NONE);
+ }
+ s5p_gpio_set_drvstr(GPIO_USB_HUB_RST, S5P_GPIO_DRVSTR_LV1);
+ /* need to check drvstr 1 or 2 */
+
+ /* for USB3503 26Mhz Reference clock setting */
+ err = gpio_request(GPIO_USB_HUB_INT, "HUB_INT");
+ if (err) {
+ pr_err("fail to request gpio %s\n", "HUB_INT");
+ } else {
+ gpio_direction_output(GPIO_USB_HUB_INT, 1);
+ s3c_gpio_setpull(GPIO_USB_HUB_INT, S3C_GPIO_PULL_NONE);
+ }
+
+ return 0;
+}
+
+static int usb3503_reset_n(int val)
+{
+ gpio_set_value(GPIO_USB_HUB_RST, 0);
+
+ /* hub off from cpuidle(LPA), skip the msleep schedule*/
+ if (val) {
+ msleep(20);
+ pr_info("[MDM] <%s> val = %d\n", __func__,
+ gpio_get_value(GPIO_USB_HUB_RST));
+ gpio_set_value(GPIO_USB_HUB_RST, !!val);
+
+ pr_info("[MDM] <%s> val = %d\n", __func__,
+ gpio_get_value(GPIO_USB_HUB_RST));
+
+ udelay(5); /* need it ?*/
+ }
+ return 0;
+}
+
+static struct usb3503_platform_data usb3503_pdata = {
+ .initial_mode = USB3503_MODE_STANDBY,
+ .reset_n = usb3503_reset_n,
+ .register_hub_handler = usb3503_hub_handler,
+ .port_enable = host_port_enable,
+};
+
+static struct i2c_board_info i2c_devs20_emul[] __initdata = {
+ {
+ I2C_BOARD_INFO(USB3503_I2C_NAME, 0x08),
+ .platform_data = &usb3503_pdata,
+ },
+};
+
+/* I2C20_EMUL */
+static struct i2c_gpio_platform_data i2c20_platdata = {
+ .sda_pin = GPIO_USB_HUB_SDA,
+ .scl_pin = GPIO_USB_HUB_SCL,
+ /*FIXME: need to timming tunning... */
+ .udelay = 20,
+};
+
+static struct platform_device s3c_device_i2c20 = {
+ .name = "i2c-gpio",
+ .id = 20,
+ .dev.platform_data = &i2c20_platdata,
+};
+
+static int __init init_usbhub(void)
+{
+ usb3503_hw_config();
+ i2c_register_board_info(20, i2c_devs20_emul,
+ ARRAY_SIZE(i2c_devs20_emul));
+
+ platform_device_register(&s3c_device_i2c20);
+ return 0;
+}
+
+device_initcall(init_usbhub);
+
+static int host_port_enable(int port, int enable)
+{
+ int err;
+
+ pr_info("[MDM] <%s> port(%d) control(%d)\n", __func__, port, enable);
+
+ if (enable) {
+ err = usbhub_set_mode(usbhub_ctl, USB3503_MODE_HUB);
+ if (err < 0) {
+ pr_err("[MDM] <%s> hub on fail\n", __func__);
+ goto exit;
+ }
+ err = s5p_ehci_port_control(&s5p_device_ehci, port, 1);
+ if (err < 0) {
+ pr_err("[MDM] <%s> port(%d) enable fail\n", __func__,
+ port);
+ goto exit;
+ }
+ } else {
+ err = s5p_ehci_port_control(&s5p_device_ehci, port, 0);
+ if (err < 0) {
+ pr_err("[MDM] <%s> port(%d) enable fail\n", __func__,
+ port);
+ goto exit;
+ }
+ err = usbhub_set_mode(usbhub_ctl, USB3503_MODE_STANDBY);
+ if (err < 0) {
+ pr_err("[MDM] <%s> hub off fail\n", __func__);
+ goto exit;
+ }
+ }
+
+ err = gpio_direction_output(umts_modem_data.gpio_host_active, enable);
+ pr_info("[MDM] <%s> active state err(%d), en(%d), level(%d)\n",
+ __func__, err, enable,
+ gpio_get_value(umts_modem_data.gpio_host_active));
+
+exit:
+ return err;
+}
+#else /* for CONFIG_USBHUB_USB3503 */
+void set_host_states(struct platform_device *pdev, int type)
+{
+ /*
+ if (active_ctl.gpio_initialized) {
+ pr_err(" [MODEM_IF] Active States =%d, %s\n", type, pdev->name);
+ gpio_direction_output(umts_link_pm_data.gpio_link_active,
+ type);
+ } else
+ active_ctl.gpio_request_host_active = 1;
+ */
+ return;
+}
+#endif /* for CONFIG_USBHUB_USB3503 */
+