aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phone_svn/ipc_spi
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 /drivers/phone_svn/ipc_spi
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 'drivers/phone_svn/ipc_spi')
-rw-r--r--drivers/phone_svn/ipc_spi/Kconfig9
-rw-r--r--drivers/phone_svn/ipc_spi/Makefile2
-rw-r--r--drivers/phone_svn/ipc_spi/ipc_spis.c3923
-rw-r--r--drivers/phone_svn/ipc_spi/spi_app.c183
-rw-r--r--drivers/phone_svn/ipc_spi/spi_app.h15
-rw-r--r--drivers/phone_svn/ipc_spi/spi_data.c981
-rw-r--r--drivers/phone_svn/ipc_spi/spi_data.h129
-rw-r--r--drivers/phone_svn/ipc_spi/spi_dev.c345
-rw-r--r--drivers/phone_svn/ipc_spi/spi_dev.h49
-rw-r--r--drivers/phone_svn/ipc_spi/spi_main.c563
-rw-r--r--drivers/phone_svn/ipc_spi/spi_main.h80
-rw-r--r--drivers/phone_svn/ipc_spi/spi_os.c634
-rw-r--r--drivers/phone_svn/ipc_spi/spi_os.h82
-rw-r--r--drivers/phone_svn/ipc_spi/spi_test.c270
-rw-r--r--drivers/phone_svn/ipc_spi/spi_test.h14
15 files changed, 7279 insertions, 0 deletions
diff --git a/drivers/phone_svn/ipc_spi/Kconfig b/drivers/phone_svn/ipc_spi/Kconfig
new file mode 100644
index 0000000..fb1386c
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/Kconfig
@@ -0,0 +1,9 @@
+#
+# OneDRAM configuration
+#
+config DPRAM_BUILT_IN
+ tristate "onedram driver built-in"
+
+config SVNET_WHITELIST
+ bool "svnet uses whitelist via onedram"
+ default n
diff --git a/drivers/phone_svn/ipc_spi/Makefile b/drivers/phone_svn/ipc_spi/Makefile
new file mode 100644
index 0000000..28a66e6
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/Makefile
@@ -0,0 +1,2 @@
+ipc_spi-objs := ipc_spis.o spi_app.o spi_data.o spi_dev.o spi_main.o spi_os.o
+obj-$(CONFIG_PHONE_IPC_SPI) += ipc_spi.o
diff --git a/drivers/phone_svn/ipc_spi/ipc_spis.c b/drivers/phone_svn/ipc_spi/ipc_spis.c
new file mode 100644
index 0000000..331a238
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/ipc_spis.c
@@ -0,0 +1,3923 @@
+#define FEATURE_SAMSUNG_SPI
+
+/**
+ * Samsung Virtual Network driver using IpcSpi device
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#define DEBUG
+
+/*
+#define FORMAT_TX_DUMP
+#define RAW_TX_DUMP
+#define RFS_TX_DUMP
+#define FORMAT_RX_DUMP
+#define RAW_RX_DUMP
+#define RFS_RX_DUMP
+#define RAW_TX_RX_LENGTH_DUMP
+#define RFS_TX_RX_LENGTH_DUMP
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/phone_svn/ipc_spi.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include <linux/vmalloc.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/in.h>
+#include <mach/regs-pmu.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+
+#include <linux/workqueue.h>
+#ifdef FEATURE_SAMSUNG_SPI
+#include "spi_main.h"
+#endif
+
+#define DRVNAME "onedram"
+
+#define ONEDRAM_REG_OFFSET 0xFFF800
+#define ONEDRAM_REG_SIZE 0x800
+
+#define MB_VALID 0x0080
+#define MB_COMMAND 0x0040
+
+#define MB_CMD(x) (MB_VALID | MB_COMMAND | x)
+#define MB_DATA(x) (MB_VALID | x)
+
+#define MBD_SEND_FMT 0x0002
+#define MBD_SEND_RAW 0x0001
+#define MBD_SEND_RFS 0x0100
+#define MBD_REQ_ACK_FMT 0x0020
+#define MBD_REQ_ACK_RAW 0x0010
+#define MBD_REQ_ACK_RFS 0x0400
+#define MBD_RES_ACK_FMT 0x0008
+#define MBD_RES_ACK_RAW 0x0004
+#define MBD_RES_ACK_RFS 0x0200
+
+
+#define FMT_OUT 0x0FE000
+#define FMT_IN 0x10E000
+#define FMT_SZ 0x10000 /* 65536 bytes */
+
+#define RAW_OUT 0x11E000
+#define RAW_IN 0x21E000
+#define RAW_SZ 0x100000 /* 1 MB */
+
+#define RFS_OUT 0x31E000
+#define RFS_IN 0x41E000
+#define RFS_SZ 0x100000 /* 1 MB */
+
+static u32 ipc_spi_get_send_vbuff_command(void);
+static void ipc_spi_set_send_vbuff_command_clear(void);
+static inline void ipc_spi_get_pointer_of_vbuff_format_tx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_format_rx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_raw_tx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_raw_rx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_tx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_rx(u32 *head, u32 *tail);
+static inline void ipc_spi_update_tail_of_vbuff_format_tx(u32 u_tail);
+static inline void ipc_spi_update_head_of_vbuff_format_rx(u32 u_head);
+static inline void ipc_spi_update_tail_of_vbuff_raw_tx(u32 u_tail);
+static inline void ipc_spi_update_head_of_vbuff_raw_rx(u32 u_head);
+static inline void ipc_spi_update_tail_of_vbuff_rfs_tx(u32 u_tail);
+static inline void ipc_spi_update_head_of_vbuff_rfs_rx(u32 u_head);
+/*
+#define LOOPBACK_TEST
+*/
+#ifdef LOOPBACK_TEST
+int loop_back_test = 1;
+#define LOOP_SIZE 2048
+#else
+int loop_back_test;
+#endif
+
+enum {
+ MBC_NONE = 0,
+ MBC_INIT_START,
+ MBC_INIT_END,
+ MBC_REQ_ACTIVE,
+ MBC_RES_ACTIVE,
+ MBC_TIME_SYNC,
+ MBC_POWER_OFF,
+ MBC_RESET,
+ MBC_PHONE_START,
+ MBC_ERR_DISPLAY,
+ MBC_POWER_SAVE,
+ MBC_NV_REBUILD,
+ MBC_EMER_DOWN,
+ MBC_REQ_SEM,
+ MBC_RES_SEM,
+ MBC_MAX
+};
+#define MBC_MASK 0xFF
+
+#define MAX_BUF_SIZE 2044
+#define DEF_BUF_SIZE MAX_BUF_SIZE
+
+static struct spi_device *p_ipc_spi;
+
+#ifdef LOOPBACK_TEST
+struct spi_protocol_header {
+ unsigned long current_data_size:12;
+ unsigned long more:1;
+ unsigned long rx_error:1;
+ unsigned long packet_id:2;
+ unsigned long reserved:2;
+ unsigned long next_data_size:10;
+ unsigned long RI:1;
+ unsigned long DCD:1;
+ unsigned long RTSCTS:1;
+ unsigned long DSRDTR:1;
+};
+#else
+struct spi_protocol_header {
+ unsigned long current_data_size:31;
+ unsigned long more:1;
+};
+#endif
+
+struct onedram_reg_mapped {
+ u32 sem;
+ u32 reserved1[7];
+ u32 mailbox_AB; /* CP write, AP read */
+ u32 reserved2[7];
+ u32 mailbox_BA; /*AP write, CP read */
+ u32 reserved3[23];
+ u32 check_AB; /* can't read */
+ u32 reserved4[7];
+ u32 check_BA; /* 0: CP read, 1: CP don't read */
+};
+
+struct ipc_spi_handler {
+ struct list_head list;
+ void *data;
+ void (*handler)(u32, void *);
+};
+
+struct ipc_spi_handler_head {
+ struct list_head list;
+ u32 len;
+ spinlock_t lock;
+};
+static struct ipc_spi_handler_head h_list;
+
+static struct resource ipc_spi_resource = {
+ .name = DRVNAME,
+ .start = 0,
+ .end = -1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct ipc_spi {
+ struct class *class;
+ struct device *dev;
+ struct cdev cdev;
+ dev_t devid;
+
+ wait_queue_head_t waitq;
+ struct fasync_struct *async_queue;
+ u32 mailbox;
+
+ unsigned long base;
+ unsigned long size;
+ void __iomem *mmio;
+
+ int irq;
+
+ struct completion comp;
+ atomic_t ref_sem;
+ unsigned long flags;
+
+ const struct attribute_group *group;
+
+ struct onedram_reg_mapped *reg;
+};
+struct ipc_spi *ipc_spi;
+
+struct workqueue_struct *ipc_spi_wq;
+struct ipc_spi_send_modem_bin_workq_data {
+ struct ipc_spi *od;
+
+ struct work_struct send_modem_w;
+};
+struct ipc_spi_send_modem_bin_workq_data *ipc_spi_send_modem_work_data;
+
+static DEFINE_SPINLOCK(ipc_spi_lock);
+
+static unsigned long hw_tmp; /* for hardware */
+static inline int _read_sem(struct ipc_spi *od);
+static inline void _write_sem(struct ipc_spi *od, int v);
+static int ipc_spi_thread_restart(void);
+static inline void ipc_spi_get_pointer_of_vbuff_format_tx(u32 *head, u32 *tail);
+
+struct completion ril_init;
+static unsigned gpio_mrdy;
+static unsigned gpio_srdy;
+struct semaphore srdy_sem;
+struct semaphore transfer_event_sem;
+int send_modem_spi = 1;
+int is_cp_reset;
+int boot_done;
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+int transfer_thread_waiting;
+
+static void __iomem *p_virtual_buff;
+
+static unsigned long recv_cnt;
+static unsigned long send_cnt;
+static ssize_t show_debug(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ char *p = buf;
+ struct ipc_spi *od = dev_get_drvdata(d);
+
+ if (!od)
+ return 0;
+
+ p += sprintf(p, "Semaphore: %d (%d)\n", _read_sem(od), (char)hw_tmp);
+ p += sprintf(p, "Mailbox: %x\n", od->reg->mailbox_AB);
+ p += sprintf(p, "Reference count: %d\n", atomic_read(&od->ref_sem));
+ p += sprintf(p, "Mailbox send: %lu\n", send_cnt);
+ p += sprintf(p, "Mailbox recv: %lu\n", recv_cnt);
+
+ return p - buf;
+}
+
+
+#ifdef FEATURE_SAMSUNG_SPI
+void *ipc_spi_get_queue_buff(void)
+{
+ return (void *)p_virtual_buff;
+}
+#endif
+
+
+static DEVICE_ATTR(debug, S_IRUGO, show_debug, NULL);
+
+static struct attribute *ipc_spi_attributes[] = {
+ &dev_attr_debug.attr,
+ NULL
+};
+
+static const struct attribute_group ipc_spi_group = {
+ .attrs = ipc_spi_attributes,
+};
+
+static inline void _write_sem(struct ipc_spi *od, int v)
+{
+ od->reg->sem = 1;
+
+ hw_tmp = od->reg->sem; /* for hardware */
+}
+
+static inline int _read_sem(struct ipc_spi *od)
+{
+ od->reg->sem = 1;
+
+ return od->reg->sem;
+}
+
+static inline int _send_cmd(struct ipc_spi *od, u32 cmd)
+{
+ u32 tmp_cmd;
+
+ if (!od) {
+ printk(KERN_ERR "[%s]ipcspi: Dev is NULL, but try to access\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to send cmd, not initialized\n",
+ __LINE__);
+
+ return -EFAULT;
+ }
+
+ if (cmd & MB_VALID) {
+ if (cmd & MB_COMMAND) {
+ tmp_cmd = (cmd & MBC_MASK) & ~(MB_CMD(0));
+
+ switch (tmp_cmd) {
+ case MBC_INIT_END: /* 0x0002 */
+ dev_info(od->dev, "(%d) send ril init cmd : %x\n",
+ __LINE__, cmd);
+
+ send_cnt++;
+ od->reg->mailbox_BA = cmd;
+
+#ifdef FEATURE_SAMSUNG_SPI
+ spi_main_send_signal(SPI_MAIN_MSG_IPC_SEND);
+#else
+ if (transfer_thread_waiting) {
+ transfer_thread_waiting = 0;
+ up(&transfer_event_sem);
+ }
+#endif
+
+ complete_all(&ril_init);
+
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ dev_dbg(od->dev, "(%d) =>send data (0x%x)\n",
+ __LINE__, cmd);
+
+#ifdef FEATURE_SAMSUNG_SPI
+ spi_main_send_signal(SPI_MAIN_MSG_IPC_SEND);
+#else
+ if (transfer_thread_waiting) {
+ transfer_thread_waiting = 0;
+ up(&transfer_event_sem);
+ }
+#endif
+ }
+ } else {
+ if (cmd == 0x45674567) {
+ dev_dbg(od->dev, "(%d) modem image loaded.\n",
+ __LINE__);
+ dev_dbg(od->dev, "(%d) start to send modem binary to cp.\n",
+ __LINE__);
+
+ ipc_spi_send_modem_work_data->od = od;
+ if (!queue_work(ipc_spi_wq,
+ &ipc_spi_send_modem_work_data->send_modem_w))
+ dev_err(od->dev, "(%d) already exist w-q\n", __LINE__);
+
+ } else {
+ dev_err(od->dev, "(%d) send invalid cmd : 0x%x\n",
+ __LINE__, cmd);
+ }
+ }
+
+ return 0;
+}
+
+static inline int _recv_cmd(struct ipc_spi *od, u32 *cmd)
+{
+ if (!cmd)
+ return -EINVAL;
+
+ if (!od) {
+ printk(KERN_ERR "[%s]ipcspi: Dev is NULL, but try to access\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to read cmd, not initialized\n",
+ __LINE__);
+
+ return -EFAULT;
+ }
+
+ recv_cnt++;
+ *cmd = od->reg->mailbox_AB;
+ return 0;
+}
+
+static inline int _get_auth(struct ipc_spi *od, u32 cmd)
+{
+ unsigned long timeleft;
+ int retry = 0;
+
+ /* send cmd every 20m seconds */
+ while (1) {
+ _send_cmd(od, cmd);
+
+ timeleft = wait_for_completion_timeout(&od->comp, HZ/50);
+#if 0
+ if (timeleft)
+ break;
+#endif
+ if (_read_sem(od))
+ break;
+
+ retry++;
+ if (retry > 50) { /* time out after 1 seconds */
+ dev_err(od->dev, "(%d) get authority time out\n", __LINE__);
+
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int get_auth(struct ipc_spi *od, u32 cmd)
+{
+ int r;
+
+ if (!od) {
+ printk(KERN_ERR "[%s]ipcspi: Dev is NULL, but try to access\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to get authority\n", __LINE__);
+
+ return -EFAULT;
+ }
+
+ if (_read_sem(od))
+ return 0;
+
+ if (cmd)
+ r = _get_auth(od, cmd);
+ else
+ r = -EACCES;
+
+ return r;
+}
+
+static int put_auth(struct ipc_spi *od, int release)
+{
+ if (!od) {
+ printk(KERN_ERR "[%s]onedram: Dev is NULL, but try to access\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to put authority\n", __LINE__);
+
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int rel_sem(struct ipc_spi *od)
+{
+ if (!od) {
+ printk(KERN_ERR "[%s]onedram: Dev is NULL, but try to access\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to put authority\n", __LINE__);
+
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int onedram_read_mailbox(u32 *mb)
+{
+ return _recv_cmd(ipc_spi, mb);
+}
+EXPORT_SYMBOL(onedram_read_mailbox);
+
+int onedram_write_mailbox(u32 mb)
+{
+ return _send_cmd(ipc_spi, mb);
+}
+EXPORT_SYMBOL(onedram_write_mailbox);
+
+void onedram_init_mailbox(void)
+{
+ int r = 0;
+ /* flush mailbox before registering onedram irq */
+ r = ipc_spi->reg->mailbox_AB;
+
+ /* Set nINT_ONEDRAM_CP to low */
+ ipc_spi->reg->mailbox_BA = 0x0;
+}
+EXPORT_SYMBOL(onedram_init_mailbox);
+
+int onedram_get_auth(u32 cmd)
+{
+ return get_auth(ipc_spi, cmd);
+}
+EXPORT_SYMBOL(onedram_get_auth);
+
+int onedram_put_auth(int release)
+{
+ return put_auth(ipc_spi, release);
+}
+EXPORT_SYMBOL(onedram_put_auth);
+
+int onedram_rel_sem(void)
+{
+ return rel_sem(ipc_spi);
+}
+EXPORT_SYMBOL(onedram_rel_sem);
+
+int onedram_read_sem(void)
+{
+ return _read_sem(ipc_spi);
+}
+EXPORT_SYMBOL(onedram_read_sem);
+
+void onedram_get_vbase(void **vbase)
+{
+ *vbase = (void *)ipc_spi->mmio;
+}
+EXPORT_SYMBOL(onedram_get_vbase);
+
+
+static int ipc_spi_irq_log_flag;
+static irqreturn_t ipc_spi_irq_handler(int irq, void *data) /* SRDY Rising EDGE ISR */
+{
+ struct ipc_spi *od = (struct ipc_spi *)data;
+ int srdy_pin = 0;
+
+ srdy_pin = gpio_get_value(gpio_srdy);
+
+ if (!boot_done)
+ return IRQ_HANDLED;
+
+ /*
+ if (ipc_spi_irq_log_flag)
+ dev_dbg(od->dev, "(%d) isr SRDY : %d\n", __LINE__, srdy_pin);
+ */
+
+ if (!srdy_pin) {
+ printk(KERN_ERR "SRDY LOW.\n");
+ return IRQ_HANDLED;
+ }
+
+ up(&srdy_sem);
+
+ if (transfer_thread_waiting) {
+ transfer_thread_waiting = 0;
+
+ if (ipc_spi_irq_log_flag)
+ dev_dbg(od->dev, "(%d) signal transfer event.\n", __LINE__);
+
+ up(&transfer_event_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ipc_spi_vm_pagefault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct ipc_spi *od = vma->vm_private_data;
+
+ vmf->page = vmalloc_to_page(od->mmio + (vmf->pgoff << PAGE_SHIFT));
+ get_page(vmf->page);
+
+ return 0;
+}
+
+static struct vm_operations_struct ipc_spi_vm_ops = {
+ .fault = ipc_spi_vm_pagefault,
+};
+
+static int ipc_spi_open(struct inode *inode, struct file *filp)
+{
+ struct cdev *cdev = inode->i_cdev;
+ struct ipc_spi *od = container_of(cdev, struct ipc_spi, cdev);
+
+ filp->private_data = od;
+ return 0;
+}
+
+static int ipc_spi_release(struct inode *inode, struct file *filp)
+{
+ filp->private_data = NULL;
+ return 0;
+}
+
+static unsigned int ipc_spi_poll(struct file *filp, poll_table *wait)
+{
+ struct ipc_spi *od;
+ u32 data;
+
+ od = filp->private_data;
+
+ poll_wait(filp, &od->waitq, wait);
+
+ spin_lock_irq(&ipc_spi_lock);
+ data = od->mailbox;
+ spin_unlock_irq(&ipc_spi_lock);
+
+ if (data)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static ssize_t ipc_spi_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ u32 data;
+ ssize_t retval;
+ struct ipc_spi *od;
+
+ od = filp->private_data;
+
+ if (count < sizeof(u32))
+ return -EINVAL;
+
+ add_wait_queue(&od->waitq, &wait);
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irq(&ipc_spi_lock);
+ data = od->mailbox;
+ od->mailbox = 0;
+ spin_unlock_irq(&ipc_spi_lock);
+
+ if (data)
+ break;
+ else if (filp->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto out;
+ } else if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ goto out;
+ }
+ schedule();
+ }
+
+ retval = put_user(data, (u32 __user *)buf);
+ if (!retval)
+ retval = sizeof(u32);
+out:
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&od->waitq, &wait);
+
+ return retval;
+}
+
+static ssize_t ipc_spi_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ipc_spi *od;
+
+ od = filp->private_data;
+
+ if (count) {
+ u32 data;
+
+ if (get_user(data, (u32 __user *)buf))
+ return -EFAULT;
+
+ _send_cmd(od, data);
+ }
+
+ return count;
+}
+
+static int ipc_spi_fasync(int fd, struct file *filp, int on)
+{
+ struct ipc_spi *od;
+
+ od = filp->private_data;
+
+ return fasync_helper(fd, filp, on, &od->async_queue);
+}
+
+static int ipc_spi_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct ipc_spi *od;
+ unsigned long size;
+ unsigned long offset;
+
+ od = filp->private_data;
+ if (!od || !vma)
+ return -EFAULT;
+
+ size = vma->vm_end - vma->vm_start;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ dev_dbg(od->dev, "(%d) Req region: 0x%08lx 0x%08lx\n", __LINE__, offset, size);
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ipc_spi_vm_ops;
+ vma->vm_private_data = od;
+
+ dev_dbg(od->dev, "(%d) ipc_spi_mmap Done.\n", __LINE__);
+
+ return 0;
+}
+
+int ipc_spi_sema_init(void)
+{
+ printk(KERN_ERR "[SPI] Srdy sema init\n");
+ sema_init(&srdy_sem, 0);
+ return 0;
+}
+
+static long ipc_spi_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+
+ int r = 0;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ switch (cmd) {
+ case ONEDRAM_CP_CRASH:
+ panic("CP Crash");
+ break;
+ case ONEDRAM_REL_SEM:
+ r = ipc_spi_thread_restart();
+ break;
+ case ONEDRAM_SEMA_INIT:
+ r = ipc_spi_sema_init();
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+ return r;
+}
+
+static const struct file_operations ipc_spi_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = ipc_spi_read,
+ .write = ipc_spi_write,
+ .poll = ipc_spi_poll,
+ .fasync = ipc_spi_fasync,
+ .open = ipc_spi_open,
+ .release = ipc_spi_release,
+ .mmap = ipc_spi_mmap,
+ .unlocked_ioctl = ipc_spi_ioctl,
+};
+
+static int _register_chrdev(struct ipc_spi *od)
+{
+ int r;
+ dev_t devid;
+
+ od->class = class_create(THIS_MODULE, DRVNAME);
+ if (IS_ERR(od->class)) {
+ r = PTR_ERR(od->class);
+ od->class = NULL;
+ return r;
+ }
+
+ r = alloc_chrdev_region(&devid, 0, 1, DRVNAME);
+ if (r)
+ return r;
+
+ cdev_init(&od->cdev, &ipc_spi_fops);
+
+ r = cdev_add(&od->cdev, devid, 1);
+ if (r) {
+ unregister_chrdev_region(devid, 1);
+ return r;
+ }
+ od->devid = devid;
+
+ od->dev = device_create(od->class, NULL, od->devid, od, DRVNAME);
+ if (IS_ERR(od->dev)) {
+ r = PTR_ERR(od->dev);
+ od->dev = NULL;
+ return r;
+ }
+ dev_set_drvdata(od->dev, od);
+
+ return 0;
+}
+
+static inline int _request_mem(struct ipc_spi *od, struct platform_device *pdev)
+{
+ od->mmio = vmalloc(od->size);
+ if (!od->mmio) {
+ dev_err(&pdev->dev, "(%d) Failed to vmalloc size : %lu\n", __LINE__, od->size);
+
+ return -EBUSY;
+ } else {
+ dev_dbg(&pdev->dev, "(%d) vmalloc Done. mmio : 0x%08x\n", __LINE__, (u32)od->mmio);
+ }
+
+ memset((void *)od->mmio, 0, od->size);
+
+ od->reg = (struct onedram_reg_mapped *)(
+ (char *)od->mmio + ONEDRAM_REG_OFFSET);
+ dev_dbg(&pdev->dev, "(%d) Onedram semaphore: %d\n", __LINE__, _read_sem(od));
+
+ od->reg->sem = 1;
+ dev_dbg(&pdev->dev, "(%d) force set sem to 1 : %d\n", __LINE__, od->reg->sem);
+
+ od->reg->mailbox_AB = 0x000000C8;
+ od->reg->mailbox_BA = 0;
+ dev_dbg(&pdev->dev, "(%d) force set mailbox to 0 : AB=0x%x, BA=0x%x\n", __LINE__, od->reg->mailbox_AB, od->reg->mailbox_BA);
+
+ ipc_spi_resource.start = (resource_size_t)od->mmio;
+ ipc_spi_resource.end = (resource_size_t)od->mmio + od->size - 1;
+
+ p_virtual_buff = od->mmio;
+
+ return 0;
+}
+
+static void _release(struct ipc_spi *od)
+{
+ if (!od)
+ return;
+
+ if (od->irq)
+ free_irq(od->irq, od);
+
+ if (od->group)
+ sysfs_remove_group(&od->dev->kobj, od->group);
+
+ if (od->dev)
+ device_destroy(od->class, od->devid);
+
+ if (od->devid) {
+ cdev_del(&od->cdev);
+ unregister_chrdev_region(od->devid, 1);
+ }
+
+ if (od->mmio) {
+ od->reg = NULL;
+
+ vfree((void *)od->mmio);
+
+ ipc_spi_resource.start = 0;
+ ipc_spi_resource.end = -1;
+ }
+
+ if (od->class)
+ class_destroy(od->class);
+
+ kfree(od);
+}
+
+struct resource *onedram_request_region(resource_size_t start,
+ resource_size_t n, const char *name)
+{
+ struct resource *res;
+
+ start += ipc_spi_resource.start;
+ res = __request_region(&ipc_spi_resource, start, n, name, 0);
+ if (!res)
+ return NULL;
+
+ return res;
+}
+EXPORT_SYMBOL(onedram_request_region);
+
+void onedram_release_region(resource_size_t start, resource_size_t n)
+{
+ start += ipc_spi_resource.start;
+ __release_region(&ipc_spi_resource, start, n);
+}
+EXPORT_SYMBOL(onedram_release_region);
+
+int onedram_register_handler(void (*handler)(u32, void *), void *data)
+{
+ unsigned long flags;
+ struct ipc_spi_handler *hd;
+
+ if (!handler)
+ return -EINVAL;
+
+ hd = kzalloc(sizeof(struct ipc_spi_handler), GFP_KERNEL);
+ if (!hd)
+ return -ENOMEM;
+
+ hd->data = data;
+ hd->handler = handler;
+
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_add_tail(&hd->list, &h_list.list);
+ h_list.len++;
+ spin_unlock_irqrestore(&h_list.lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(onedram_register_handler);
+
+int onedram_unregister_handler(void (*handler)(u32, void *))
+{
+ unsigned long flags;
+ struct list_head *l, *tmp;
+
+ if (!handler)
+ return -EINVAL;
+
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_for_each_safe(l, tmp, &h_list.list) {
+ struct ipc_spi_handler *hd = list_entry(l, struct ipc_spi_handler, list);
+
+ if (hd->handler == handler) {
+ list_del(&hd->list);
+ h_list.len--;
+ kfree(hd);
+ }
+ }
+ spin_unlock_irqrestore(&h_list.lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(onedram_unregister_handler);
+
+static void _unregister_all_handlers(void)
+{
+ unsigned long flags;
+ struct list_head *l, *tmp;
+
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_for_each_safe(l, tmp, &h_list.list) {
+ struct ipc_spi_handler *hd = list_entry(l, struct ipc_spi_handler, list);
+
+ list_del(&hd->list);
+ h_list.len--;
+ kfree(hd);
+ }
+ spin_unlock_irqrestore(&h_list.lock, flags);
+}
+
+static void _init_data(struct ipc_spi *od)
+{
+ init_completion(&od->comp);
+ atomic_set(&od->ref_sem, 0);
+ INIT_LIST_HEAD(&h_list.list);
+ spin_lock_init(&h_list.lock);
+ h_list.len = 0;
+ init_waitqueue_head(&od->waitq);
+
+ init_completion(&ril_init);
+ sema_init(&srdy_sem, 0);
+ sema_init(&transfer_event_sem, 0);
+}
+
+static u32 ipc_spi_get_send_vbuff_command(void)
+{
+ u32 cmd = 0;
+
+ memcpy((void *)&cmd, (void *)(p_virtual_buff + ONEDRAM_REG_OFFSET + 64), sizeof(cmd));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get mailbox_BA cmd : 0x%x\n", __LINE__, cmd); */
+
+ return cmd;
+}
+
+static void ipc_spi_set_send_vbuff_command_clear(void)
+{
+ u32 cmd = 0;
+
+ memcpy((void *)(p_virtual_buff + ONEDRAM_REG_OFFSET + 64), (void *)&cmd, sizeof(cmd));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) clear mailbox_BA cmd : 0x%x\n", __LINE__, cmd); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_format_tx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 16), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 20), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT tx_head : %d, tx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_format_rx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 16 + 8), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 20 + 8), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT rx_head : %d, rx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_raw_tx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 32), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 36), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW tx_head : %d, tx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_raw_rx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 32 + 8), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 36 + 8), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW rx_head : %d, rx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_tx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 48), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 52), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS tx_head : %d, tx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_rx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 48 + 8), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 52 + 8), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS rx_head : %d, rx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_update_tail_of_vbuff_format_tx(u32 u_tail)
+{
+ memcpy((void *)(p_virtual_buff + 20), (void *)&u_tail, sizeof(u_tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update FMT tx_tail : %d\n", __LINE__, u_tail); */
+}
+
+static inline void ipc_spi_update_head_of_vbuff_format_rx(u32 u_head)
+{
+ memcpy((void *)(p_virtual_buff + 20 + 4), (void *)&u_head, sizeof(u_head));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update FMT rx_head : %d\n", __LINE__, u_head); */
+}
+
+static inline void ipc_spi_update_tail_of_vbuff_raw_tx(u32 u_tail)
+{
+ memcpy((void *)(p_virtual_buff + 36), (void *)&u_tail, sizeof(u_tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RAW tx_tail : %d\n", __LINE__, u_tail); */
+}
+
+static inline void ipc_spi_update_head_of_vbuff_raw_rx(u32 u_head)
+{
+ memcpy((void *)(p_virtual_buff + 36 + 4), (void *)&u_head, sizeof(u_head));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RAW rx_head : %d\n", __LINE__, u_head); */
+}
+
+static inline void ipc_spi_update_tail_of_vbuff_rfs_tx(u32 u_tail)
+{
+ memcpy((void *)(p_virtual_buff + 52), (void *)&u_tail, sizeof(u_tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RFS tx_tail : %d\n", __LINE__, u_tail); */
+}
+
+static inline void ipc_spi_update_head_of_vbuff_rfs_rx(u32 u_head)
+{
+ memcpy((void *)(p_virtual_buff + 52 + 4), (void *)&u_head, sizeof(u_head));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RFS rx_head : %d\n", __LINE__, u_head); */
+}
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+u32 ipc_spi_get_length_vbuff_format_tx(u32 *out_head, u32 *out_tail)
+{
+ u32 len = 0;
+
+ ipc_spi_get_pointer_of_vbuff_format_tx(out_head, out_tail);
+
+ if (*out_head >= *out_tail)
+ len = *out_head - *out_tail;
+ else
+ len = FMT_SZ - *out_tail + *out_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT tx_len : %d\n", __LINE__, len); */
+
+ return len;
+}
+
+static u32 ipc_spi_get_length_vbuff_raw_tx(u32 *out_head, u32 *out_tail)
+{
+ u32 len = 0;
+
+ ipc_spi_get_pointer_of_vbuff_raw_tx(out_head, out_tail);
+
+ if (*out_head >= *out_tail)
+ len = *out_head - *out_tail;
+ else
+ len = RAW_SZ - *out_tail + *out_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW tx_len : %d\n", __LINE__, len); */
+
+ return len;
+}
+
+static u32 ipc_spi_get_length_vbuff_rfs_tx(u32 *out_head, u32 *out_tail)
+{
+ u32 len = 0;
+
+ ipc_spi_get_pointer_of_vbuff_rfs_tx(out_head, out_tail);
+
+ if (*out_head >= *out_tail)
+ len = *out_head - *out_tail;
+ else
+ len = RFS_SZ - *out_tail + *out_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS tx_len : %d\n", __LINE__, len); */
+
+ return len;
+}
+
+static u32 ipc_spi_get_space_vbuff_format_rx(u32 *in_head, u32 *in_tail)
+{
+ u32 space = 0;
+
+ ipc_spi_get_pointer_of_vbuff_format_rx(in_head, in_tail);
+
+ /* check the memory space remained */
+ if (*in_tail <= *in_head)
+ space = FMT_SZ - *in_head + *in_tail;
+ else
+ space = *in_tail - *in_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT rx space : %d\n", __LINE__, space); */
+
+ return space;
+}
+
+static u32 ipc_spi_get_space_vbuff_raw_rx(u32 *in_head, u32 *in_tail)
+{
+ u32 space = 0;
+
+ ipc_spi_get_pointer_of_vbuff_raw_rx(in_head, in_tail);
+
+ /* check the memory space remained */
+ if (*in_tail <= *in_head)
+ space = RAW_SZ - *in_head + *in_tail;
+ else
+ space = *in_tail - *in_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW rx space : %d\n", __LINE__, space); */
+
+ return space;
+}
+
+static u32 ipc_spi_get_space_vbuff_rfs_rx(u32 *in_head, u32 *in_tail)
+{
+ u32 space = 0;
+
+ ipc_spi_get_pointer_of_vbuff_rfs_rx(in_head, in_tail);
+
+ /* check the memory space remained */
+ if (*in_tail <= *in_head)
+ space = RFS_SZ - *in_head + *in_tail;
+ else
+ space = *in_tail - *in_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS rx space : %d\n", __LINE__, space); */
+
+ return space;
+}
+
+static int ipc_spi_check_send_data(void)
+{
+ int retval = 0;
+ u32 out_head = 0;
+ u32 out_tail = 0;
+
+#ifdef LOOPBACK_TEST
+ if (loop_back_test)
+ retval = 1;
+#endif
+
+ if (ipc_spi_get_send_vbuff_command())
+ retval = 1;
+
+ ipc_spi_get_pointer_of_vbuff_format_tx(&out_head, &out_tail);
+ if (out_head != out_tail)
+ retval = 1;
+
+ ipc_spi_get_pointer_of_vbuff_raw_tx(&out_head, &out_tail);
+ if (out_head != out_tail)
+ retval = 1;
+
+ ipc_spi_get_pointer_of_vbuff_rfs_tx(&out_head, &out_tail);
+ if (out_head != out_tail)
+ retval = 1;
+
+ return retval;
+}
+
+static void ipc_spi_copy_from_vbuff_format_tx(void *p_des, u32 offset_vbuff, u32 copy_len)
+{
+ if ((offset_vbuff + copy_len) <= FMT_SZ) {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + FMT_OUT + offset_vbuff), copy_len);
+ } else {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + FMT_OUT + offset_vbuff), FMT_SZ - offset_vbuff);
+ memcpy((void *)(p_des + (FMT_SZ - offset_vbuff)), (void *)(p_virtual_buff + FMT_OUT), copy_len - (FMT_SZ - offset_vbuff));
+ }
+}
+
+static void ipc_spi_copy_from_vbuff_raw_tx(void *p_des, u32 offset_vbuff, u32 copy_len)
+{
+ if ((offset_vbuff + copy_len) <= RAW_SZ) {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RAW_OUT + offset_vbuff), copy_len);
+ } else {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RAW_OUT + offset_vbuff), RAW_SZ - offset_vbuff);
+ memcpy((void *)(p_des + (RAW_SZ - offset_vbuff)), (void *)(p_virtual_buff + RAW_OUT), copy_len - (RAW_SZ - offset_vbuff));
+ }
+}
+
+static void ipc_spi_copy_from_vbuff_rfs_tx(void *p_des, u32 offset_vbuff, u32 copy_len)
+{
+ if ((offset_vbuff + copy_len) <= RFS_SZ) {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RFS_OUT + offset_vbuff), copy_len);
+ } else {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RFS_OUT + offset_vbuff), RFS_SZ - offset_vbuff);
+ memcpy((void *)(p_des + (RFS_SZ - offset_vbuff)), (void *)(p_virtual_buff + RFS_OUT), copy_len - (RFS_SZ - offset_vbuff));
+ }
+}
+
+#ifdef LOOPBACK_TEST
+static void ipc_spi_prepare_tx_data(u8 *tx_b)
+{
+ u32 len = 0, tx_b_remail_len = DEF_BUF_SIZE, read_size = 0;
+ struct spi_protocol_header *tx_header = (struct spi_protocol_header *)tx_b;
+ u32 cmd = 0;
+ u8 cmd_8 = 0;
+ u16 mux = 0;
+ u16 p_tx_b = sizeof(struct spi_protocol_header);
+ u32 p_send_data_h = 0, p_send_data_t = 0;
+ u16 pkt_fmt_len = 0;
+ u32 pkt_len = 0;
+ u8 bof = 0, eof = 0;
+ int i;
+
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ cmd = ipc_spi_get_send_vbuff_command(); /* check mailbox command data */
+ if (cmd) {
+ cmd_8 = cmd & 0xFF;
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>exist CMD cmd_8 : %x\n", __LINE__, cmd_8);
+
+ mux = 0x0004;
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header)), (void *)&mux, sizeof(mux));
+
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux)), (void *)&cmd_8, sizeof(cmd_8));
+ ipc_spi_set_send_vbuff_command_clear();
+
+ tx_header->current_data_size = sizeof(mux) + sizeof(cmd_8);
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+
+ if (ipc_spi_check_send_data())
+ tx_header->more = 1;
+ else
+ tx_header->more = 0;
+
+ } else { /* check format, raw, rfs data */
+ len = ipc_spi_get_length_vbuff_format_tx(&p_send_data_h, &p_send_data_t); /* len : vbuff_format_tx length */
+ if (len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>prepare FMT data\n", __LINE__);
+
+ mux = 0x0001;
+ read_size = 0;
+
+ while (len > read_size) { /* till len is zero */
+ /* bof : 0x7F check */
+ ipc_spi_copy_from_vbuff_format_tx((void *)&bof, p_send_data_t, sizeof(bof));
+
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT bof error, remove invalid data. bof : %x\n", __LINE__, bof);
+
+ ipc_spi_update_tail_of_vbuff_format_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ }
+
+ /* packet length check */
+ ipc_spi_copy_from_vbuff_format_tx((void *)&pkt_fmt_len, p_send_data_t + sizeof(bof), sizeof(pkt_fmt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>FMT packet len : %d\n", __LINE__, pkt_fmt_len);
+
+ if ((pkt_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT wrong packet len, remove invalid data. packet len : %x\n", __LINE__, pkt_fmt_len);
+
+ ipc_spi_update_tail_of_vbuff_format_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ } else if ((pkt_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > tx_b_remail_len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>FMT tx more set\n", __LINE__);
+
+ tx_header->more = 1;
+
+ break;
+ }
+
+ /* make spi tx packet (1 packet : vbuff -> tx_b) */
+ memcpy((void *)(tx_b + p_tx_b), (void *)&mux, sizeof(mux));
+ p_tx_b += sizeof(mux);
+ tx_b_remail_len -= sizeof(mux);
+
+ ipc_spi_copy_from_vbuff_format_tx((void *)(tx_b + p_tx_b), p_send_data_t, pkt_fmt_len + sizeof(bof) + sizeof(eof));
+
+#ifdef FORMAT_TX_DUMP
+ printk(KERN_ERR "[IPC_SPI => FMT TX :");
+ for (i = 0; i < (pkt_fmt_len + sizeof(bof) + sizeof(eof)); i++)
+ printk(KERN_ERR " %02x", *((u8 *)(tx_b + p_tx_b + i)));
+
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_tx_b += pkt_fmt_len + sizeof(bof) + sizeof(eof);
+ p_send_data_t += pkt_fmt_len + sizeof(bof) + sizeof(eof);
+ tx_b_remail_len -= pkt_fmt_len + sizeof(bof) + sizeof(eof);
+
+ p_send_data_t %= FMT_SZ;
+ ipc_spi_update_tail_of_vbuff_format_tx(p_send_data_t); /* in-pointer update */
+
+ read_size += pkt_fmt_len + sizeof(bof) + sizeof(eof);
+ if (len < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) FMT tx read error len : %d, read_size : %d\n", __LINE__, len, read_size);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>FMT len : %d\n", __LINE__, len);
+ }
+
+ tx_header->current_data_size = DEF_BUF_SIZE - tx_b_remail_len;
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+ }
+
+ len = ipc_spi_get_length_vbuff_raw_tx(&p_send_data_h, &p_send_data_t);
+ if (len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>prepare RAW data\n", __LINE__);
+
+ mux = 0x0002;
+ read_size = 0;
+
+ while (len > read_size) { /* till len is zero */
+ /* bof : 0x7F check */
+ ipc_spi_copy_from_vbuff_raw_tx((void *)&bof, p_send_data_t, sizeof(bof));
+
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW bof error, remove invalid data. bof : %x\n", __LINE__, bof);
+
+ ipc_spi_update_tail_of_vbuff_raw_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ }
+
+ /* packet length check */
+ ipc_spi_copy_from_vbuff_raw_tx((void *)&pkt_len, p_send_data_t + sizeof(bof), sizeof(pkt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RAW packet len : %d\n", __LINE__, pkt_len);
+
+ if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW wrong packet len, remove invalid data. packet len : %x\n", __LINE__, pkt_len);
+
+ ipc_spi_update_tail_of_vbuff_raw_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ } else if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > tx_b_remail_len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RAW tx more set\n", __LINE__);
+
+ tx_header->more = 1;
+
+ break;
+ }
+
+ /* make spi tx packet (1 packet : vbuff -> tx_b) */
+ memcpy((void *)(tx_b + p_tx_b), (void *)&mux, sizeof(mux));
+ p_tx_b += sizeof(mux);
+ tx_b_remail_len -= sizeof(mux);
+
+ ipc_spi_copy_from_vbuff_raw_tx((void *)(tx_b + p_tx_b), p_send_data_t, pkt_len + sizeof(bof) + sizeof(eof));
+
+#ifdef RAW_TX_DUMP
+ printk(KERN_ERR "[IPC_SPI => RAW TX :");
+ for (i = 0 ; i < (pkt_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(tx_b + p_tx_b + i)));
+
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_tx_b += pkt_len + sizeof(bof) + sizeof(eof);
+ p_send_data_t += pkt_len + sizeof(bof) + sizeof(eof);
+ tx_b_remail_len -= pkt_len + sizeof(bof) + sizeof(eof);
+
+ p_send_data_t %= RAW_SZ;
+ ipc_spi_update_tail_of_vbuff_raw_tx(p_send_data_t); /* in-pointer update */
+
+ read_size += pkt_len + sizeof(bof) + sizeof(eof);
+ if (len < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) RAW tx read error len : %d, read_size : %d\n", __LINE__, len, read_size);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RAW len : %d\n", __LINE__, len);
+ }
+
+ tx_header->current_data_size = DEF_BUF_SIZE - tx_b_remail_len;
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+ }
+
+ len = ipc_spi_get_length_vbuff_rfs_tx(&p_send_data_h, &p_send_data_t);
+ if (len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>prepare RFS data\n", __LINE__);
+
+ mux = 0x0003;
+ read_size = 0;
+
+ while (len > read_size) { /* till len is zero */
+ /* bof : 0x7F check */
+ ipc_spi_copy_from_vbuff_rfs_tx((void *)&bof, p_send_data_t, sizeof(bof));
+
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS bof error, remove invalid data. bof : %x\n", __LINE__, bof);
+
+ ipc_spi_update_tail_of_vbuff_rfs_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ }
+
+ /* packet length check */
+ ipc_spi_copy_from_vbuff_rfs_tx((void *)&pkt_len, p_send_data_t + sizeof(bof), sizeof(pkt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RFS packet len : %d\n", __LINE__, pkt_len);
+
+ if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS wrong packet len, remove invalid data. packet len : %x\n", __LINE__, pkt_len);
+
+ ipc_spi_update_tail_of_vbuff_rfs_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ } else if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > tx_b_remail_len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RFS tx more set\n", __LINE__);
+
+ tx_header->more = 1;
+
+ break;
+ }
+
+ /* make spi tx packet (1 packet : vbuff -> tx_b) */
+ memcpy((void *)(tx_b + p_tx_b), (void *)&mux, sizeof(mux));
+ p_tx_b += sizeof(mux);
+ tx_b_remail_len -= sizeof(mux);
+
+ ipc_spi_copy_from_vbuff_rfs_tx((void *)(tx_b + p_tx_b), p_send_data_t, pkt_len + sizeof(bof) + sizeof(eof));
+
+#ifdef RFS_TX_DUMP
+ printk(KERN_ERR "[IPC_SPI => RFS TX :");
+ for (i = 0 ; i < (pkt_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(tx_b + p_tx_b + i)));
+
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_tx_b += pkt_len + sizeof(bof) + sizeof(eof);
+ p_send_data_t += pkt_len + sizeof(bof) + sizeof(eof);
+ tx_b_remail_len -= pkt_len + sizeof(bof) + sizeof(eof);
+
+ p_send_data_t %= RFS_SZ;
+ ipc_spi_update_tail_of_vbuff_rfs_tx(p_send_data_t); /* in-pointer update */
+
+ read_size += pkt_len + sizeof(bof) + sizeof(eof);
+ if (len < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) RFS tx read error len : %d, read_size : %d\n", __LINE__, len, read_size);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RFS len : %d\n", __LINE__, len);
+
+#ifdef RFS_TX_RX_LENGTH_DUMP
+ printk(KERN_ERR "[IPC_SPI => RFS TX : %d]\n", pkt_len);
+#endif
+ }
+
+ tx_header->current_data_size = DEF_BUF_SIZE - tx_b_remail_len;
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+ }
+ }
+
+#ifndef LOOPBACK_TEST
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] TX : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ tx_b[0], tx_b[1], tx_b[2], tx_b[3], tx_b[4], tx_b[5], tx_b[6], tx_b[7], tx_b[8], tx_b[9], tx_b[10], tx_b[11], tx_b[12], tx_b[13], tx_b[14], tx_b[15], tx_b[16], tx_b[17], tx_b[18], tx_b[19],
+ tx_b[20], tx_b[21], tx_b[22], tx_b[23], tx_b[24], tx_b[25], tx_b[26], tx_b[27], tx_b[28], tx_b[29], tx_b[30], tx_b[31], tx_b[32], tx_b[33], tx_b[34], tx_b[35], tx_b[36], tx_b[37], tx_b[38], tx_b[39]);
+#endif
+}
+
+static void ipc_spi_prepare_loopback_tx_data(u8 *tx_b, u8 *rx_b, u8 *test_data)
+{
+ struct spi_protocol_header *tx_header = (struct spi_protocol_header *)tx_b;
+ u16 mux = 0;
+ u8 bof = 0x7F, eof = 0x7E;
+ u16 pkt_len = LOOP_SIZE - 8;
+ u16 ipc_len = pkt_len - 3;
+ u32 ipc_header = 0x010B0A00;
+
+ int i;
+
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ mux = 0x0001;
+
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header)), (void *)&mux, sizeof(mux));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux)), (void *)&bof, sizeof(bof));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof)), (void *)&pkt_len, sizeof(pkt_len));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + 1), (void *)&ipc_len, sizeof(ipc_len));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + 4), (void *)&ipc_header, sizeof(ipc_header));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + 4 + 4), (void *)test_data, LOOP_SIZE-18);
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + pkt_len), (void *)&eof, sizeof(eof));
+
+ tx_header->current_data_size = sizeof(mux) + sizeof(bof) + pkt_len + sizeof(eof);
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+
+ printk(KERN_ERR "[SPI DUMP] LOOP TX :]");
+ for (i = 0 ; i < 30 ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(tx_b + i)));
+ printk(KERN_ERR "| ");
+ for (i = LOOP_SIZE - 30 ; i < LOOP_SIZE ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(tx_b + i)));
+ printk(KERN_ERR "]\n");
+
+}
+#endif
+
+#if 0
+static void ipc_spi_prepare_loopback_tx_data(u8 *tx_b, u8 *rx_b)
+{
+ struct spi_protocol_header *tx_header = (struct spi_protocol_header *)tx_b;
+ u16 mux = 0;
+ u8 bof = 0x7F, eof = 0x7E;
+ u32 pkt_len = 16;
+ u8 test_data[10] = "0123456789";
+ u8 ch_id = 31, control_id = 0;
+
+ int i;
+
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ mux = 0x0002;
+
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header)), (void *)&mux, sizeof(mux));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux)), (void *)&bof, sizeof(bof));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof)), (void *)&pkt_len, sizeof(pkt_len));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len)),
+ (void *)&ch_id, sizeof(ch_id));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + sizeof(ch_id)),
+ (void *)&control_id, sizeof(control_id));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len)
+ + sizeof(ch_id) + sizeof(control_id)), (void *)&test_data, sizeof(test_data));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + pkt_len), (void *)&eof, sizeof(eof));
+
+ tx_header->current_data_size = sizeof(mux) + sizeof(bof) + pkt_len + sizeof(eof);
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+
+ printk(KERN_ERR "[SPI DUMP] LOOP TX : ");
+ for (i = 0 ; i < 30 ; i++)
+ printk(KERN_ERR "%02x ", tx_b[i]);
+ printk(KERN_ERR "\n");
+}
+#endif
+
+static void ipc_spi_set_MRDY_pin(int val)
+{
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) set MRDY %d\n", __LINE__, val); */
+
+ gpio_set_value(gpio_mrdy, val);
+}
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+int ipc_spi_tx_rx_sync(u8 *tx_d, u8 *rx_d, unsigned len)
+{
+ struct spi_transfer t;
+ struct spi_message msg;
+
+ memset(&t, 0, sizeof t);
+
+ t.len = len;
+
+ t.tx_buf = tx_d;
+ t.rx_buf = rx_d;
+
+ t.cs_change = 0;
+
+ t.bits_per_word = 32;
+ t.speed_hz = 12000000;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&t, &msg);
+
+ return spi_sync(p_ipc_spi, &msg);
+}
+
+static void ipc_spi_swap_data_htn(u8 *data, int len)
+{
+ int i;
+
+ for (i = 0 ; i < len ; i += 4)
+ *(u32 *)(data + i) = htonl(*(u32 *)(data + i));
+}
+
+static void ipc_spi_swap_data_nth(u8 *data, int len)
+{
+ int i;
+
+ for (i = 0 ; i < len ; i += 4)
+ *(u32 *)(data + i) = ntohl(*(u32 *)(data + i));
+}
+
+static int ipc_spi_copy_to_vbuff_format_rx(void *data, u16 len)
+{
+ u32 head = 0, tail = 0, new_head = 0, space = 0;
+ int copy_retry_count = 0;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to FMT vbuff, len : %d\n", __LINE__, len);
+
+COPY_TO_VBUFF_FMT_RETRY:
+
+ space = ipc_spi_get_space_vbuff_format_rx(&head, &tail);
+ if (space < len) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT vbuff is full, space : %d, len : %d\n", __LINE__, space, len);
+
+ copy_retry_count++;
+ if (copy_retry_count > 20) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT vbuff is full. copy fail.\n", __LINE__);
+
+ return -ENOMEM;
+ }
+
+ msleep(20);
+ goto COPY_TO_VBUFF_FMT_RETRY;
+ }
+
+ if (head + len <= FMT_SZ) {
+ memcpy((void *)(p_virtual_buff + FMT_IN + head), data, len);
+ } else {
+ memcpy((void *)(p_virtual_buff + FMT_IN + head), data, FMT_SZ - head);
+ memcpy((void *)(p_virtual_buff + FMT_IN), (void *)(data + (FMT_SZ - head)), len - (FMT_SZ - head));
+ }
+
+ new_head = (head + len) % FMT_SZ;
+ ipc_spi_update_head_of_vbuff_format_rx(new_head);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to FMT vbuff done.\n", __LINE__);
+
+ return 0;
+}
+
+static int ipc_spi_copy_to_vbuff_raw_rx(void *data, u32 len)
+{
+ u32 head = 0, tail = 0, new_head = 0, space = 0;
+ int copy_retry_count = 0;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RAW vbuff, len : %d\n", __LINE__, len);
+
+COPY_TO_VBUFF_RAW_RETRY:
+
+ space = ipc_spi_get_space_vbuff_raw_rx(&head, &tail);
+ if (space < len) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW vbuff is full, space : %d, len : %d\n", __LINE__, space, len);
+
+ copy_retry_count++;
+ if (copy_retry_count > 20) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW vbuff is full. copy fail.\n", __LINE__);
+
+ return -ENOMEM;
+ }
+
+ msleep(20);
+ goto COPY_TO_VBUFF_RAW_RETRY;
+ }
+
+ if (head + len <= RAW_SZ) {
+ memcpy((void *)(p_virtual_buff + RAW_IN + head), data, len);
+ } else {
+ memcpy((void *)(p_virtual_buff + RAW_IN + head), data, RAW_SZ - head);
+ memcpy((void *)(p_virtual_buff + RAW_IN), (void *)(data + (RAW_SZ - head)), len - (RAW_SZ - head));
+ }
+
+ new_head = (head + len) % RAW_SZ;
+ ipc_spi_update_head_of_vbuff_raw_rx(new_head);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RAW vbuff done.\n", __LINE__);
+
+ return 0;
+}
+
+static int ipc_spi_copy_to_vbuff_rfs_rx(void *data, u32 len)
+{
+ u32 head = 0, tail = 0, new_head = 0, space = 0;
+ int copy_retry_count = 0;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RFS vbuff, len : %d\n", __LINE__, len);
+
+COPY_TO_VBUFF_RFS_RETRY:
+
+ space = ipc_spi_get_space_vbuff_rfs_rx(&head, &tail);
+ if (space < len) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS vbuff is full, space : %d, len : %d\n", __LINE__, space, len);
+
+ copy_retry_count++;
+ if (copy_retry_count > 20) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS vbuff is full. copy fail.\n", __LINE__);
+
+ return -ENOMEM;
+ }
+
+ msleep(20);
+ goto COPY_TO_VBUFF_RFS_RETRY;
+ }
+
+ if (head + len <= RFS_SZ) {
+ memcpy((void *)(p_virtual_buff + RFS_IN + head), data, len);
+ } else {
+ memcpy((void *)(p_virtual_buff + RFS_IN + head), data, RFS_SZ - head);
+ memcpy((void *)(p_virtual_buff + RFS_IN), (void *)(data + (RFS_SZ - head)), len - (RFS_SZ - head));
+ }
+
+ new_head = (head + len) % RFS_SZ;
+ ipc_spi_update_head_of_vbuff_rfs_rx(new_head);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RFS vbuff done.\n", __LINE__);
+
+ return 0;
+}
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+void ipc_spi_make_data_interrupt(u32 cmd, struct ipc_spi *od)
+{
+ struct list_head *l;
+ unsigned long flags;
+ u32 mailbox;
+
+ mailbox = cmd;
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) <=make data int : 0x%08x\n", __LINE__, mailbox); */
+
+ if (h_list.len) {
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_for_each(l, &h_list.list) {
+ struct ipc_spi_handler *h = list_entry(l, struct ipc_spi_handler, list);
+
+ if (h->handler)
+ h->handler(mailbox, h->data);
+ }
+ spin_unlock_irqrestore(&h_list.lock, flags);
+
+ spin_lock(&ipc_spi_lock);
+ od->mailbox = mailbox;
+ spin_unlock(&ipc_spi_lock);
+ } else {
+ od->mailbox = mailbox;
+ }
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) <=send data int cmd event\n", __LINE__); */
+
+ wake_up_interruptible(&od->waitq);
+ kill_fasync(&od->async_queue, SIGIO, POLL_IN);
+}
+
+static int rx_prev_data_saved;
+static u16 rx_prev_data_mux;
+static u32 rx_prev_data_size;
+static u32 rx_prev_data_remain;
+
+static void ipc_spi_rx_process(u8 *rx_b, u8 *rx_save_b, struct ipc_spi *od)
+{
+ int retval = 0;
+ struct spi_protocol_header *rx_header = (struct spi_protocol_header *)rx_b;
+ u32 total_size = 0, read_size = 0;
+ u16 packet_fmt_len = 0;
+ u32 packet_len = 0;
+ u8 bof = 0, eof = 0;
+ u16 mux = 0;
+ u16 p_read = 4;
+ u32 int_cmd = 0;
+ int i;
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, more : %d, CTS : %d, current size : %d, next size : %d\n", __LINE__, rx_header->more, rx_header->RTSCTS, rx_header->current_data_size, rx_header->next_data_size); */
+
+ total_size = rx_header->current_data_size;
+
+ while (total_size > read_size) {
+ int_cmd = 0;
+
+ if (!rx_prev_data_saved) {
+ /* check bof : 0x7F */
+ memcpy((void *)&bof, (void *)(rx_b + p_read + sizeof(mux)), sizeof(bof));
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, bof : %x\n", __LINE__, bof); */
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, bof error : %x\n", __LINE__, bof);
+/*
+ printk(KERN_ERR "[IPC_SPI <= RX :");
+ for (i = 0 ; i < DEF_BUF_SIZE + 4 ; i++) {
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + i)));
+ }
+ printk(KERN_ERR "]\n");
+*/
+ break;
+ }
+ }
+
+ if (!rx_prev_data_saved) {
+ /* read mux */
+ memcpy((void *)&mux, (void *)(rx_b + p_read), sizeof(mux));
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, mux : 0x%04x\n", __LINE__, mux); */
+ if (mux > 0x4 || mux < 0x0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, mux error : %x\n", __LINE__, mux);
+ break;
+ }
+ } else {
+ mux = rx_prev_data_mux;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, prev_mux : %d\n", __LINE__, mux);
+ }
+
+ switch (mux) {
+ case 0x0001:
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, got FMT : %x\n", __LINE__, mux); */
+
+ if (rx_prev_data_saved) {
+ if (rx_prev_data_remain > DEF_BUF_SIZE) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data, FMT saved : %d, remain : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_mux = 0x0001;
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), DEF_BUF_SIZE);
+ rx_prev_data_size += DEF_BUF_SIZE;
+ rx_prev_data_remain -= DEF_BUF_SIZE;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data save, FMT size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), rx_prev_data_remain);
+ p_read += rx_prev_data_remain;
+ read_size += rx_prev_data_remain;
+
+ if (*rx_save_b != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, FMT bof error : %x\n", __LINE__, *rx_save_b);
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ if (*(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1) != 0x7E) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, FMT eof error : %x\n", __LINE__, *(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1));
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_format_rx((void *)rx_save_b, rx_prev_data_size + rx_prev_data_remain);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx prev data, cp -> ap FMT memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) rx prev data, <= one packet FMT read Done. size : %d, total_size : %d, read_size : %d, p_read : %d\n", __LINE__,
+ rx_prev_data_size + rx_prev_data_remain, total_size, read_size, p_read);
+ }
+
+#ifdef FORMAT_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= FMT RX :");
+ for (i = 0 ; i < (rx_prev_data_size + rx_prev_data_remain) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_save_b + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ rx_prev_data_saved = 0;
+ } else {
+ /* read packet len */
+ memcpy((void *)&packet_fmt_len, (void *)(rx_b + p_read + sizeof(mux) + sizeof(bof)), sizeof(packet_fmt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, FMT pkt len : %d\n", __LINE__, packet_fmt_len);
+/* if (packet_fmt_len > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, FMT pkt len error : %d\n", __LINE__, packet_fmt_len);
+ return;
+ } */
+
+ if ((packet_fmt_len + sizeof(mux) + sizeof(bof) + sizeof(eof)) > (total_size - read_size)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, FMT packet_fmt_len : %d, remain : %d\n", __LINE__, packet_fmt_len, total_size - read_size);
+
+ rx_prev_data_mux = 0x0001;
+
+ memcpy((void *)rx_save_b, (void *)(rx_b + p_read + sizeof(mux)), total_size - read_size - sizeof(mux));
+ rx_prev_data_size = total_size - read_size - sizeof(mux);
+ rx_prev_data_remain = packet_fmt_len + sizeof(bof) + sizeof(eof) - rx_prev_data_size;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data save, FMT size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_format_rx((void *)(rx_b + p_read + sizeof(mux)), packet_fmt_len + sizeof(bof) + sizeof(eof));
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, cp -> ap FMT memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, one packet FMT read Done.\n", __LINE__); */
+ }
+
+#ifdef FORMAT_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= FMT RX :");
+ for (i = 0 ; i < (packet_fmt_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + p_read + sizeof(mux) + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_read += packet_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+ read_size += packet_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, FMT read size : %d\n", __LINE__, read_size); */
+ }
+
+ /* make data interrupt cmd */
+ int_cmd = MB_DATA(MBD_SEND_FMT);
+ ipc_spi_make_data_interrupt(int_cmd, od);
+ break;
+
+ case 0x0002:
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, got RAW : %x\n", __LINE__, mux); */
+
+ if (rx_prev_data_saved) {
+ if (rx_prev_data_remain > DEF_BUF_SIZE) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data, RAW saved : %d, remain : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_mux = 0x0002;
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), DEF_BUF_SIZE);
+ rx_prev_data_size += DEF_BUF_SIZE;
+ rx_prev_data_remain -= DEF_BUF_SIZE;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data save, RAW size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), rx_prev_data_remain);
+ p_read += rx_prev_data_remain;
+ read_size += rx_prev_data_remain;
+
+ if (*rx_save_b != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RAW bof error : %x\n", __LINE__, *rx_save_b);
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ if (*(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1) != 0x7E) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RAW eof error : %x\n", __LINE__, *(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1));
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_raw_rx((void *)rx_save_b, rx_prev_data_size + rx_prev_data_remain);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx prev data, cp -> ap RAW memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) rx prev data, <= one packet RAW read Done. size : %d, total_size : %d, read_size : %d, p_read : %d\n", __LINE__,
+ rx_prev_data_size + rx_prev_data_remain, total_size, read_size, p_read);
+ }
+
+#ifdef RAW_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RAW RX :");
+ for (i = 0 ; i < (rx_prev_data_size + rx_prev_data_remain) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_save_b + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ rx_prev_data_saved = 0;
+ } else {
+ /* read packet len */
+ memcpy((void *)&packet_len, (void *)(rx_b + p_read + sizeof(mux) + sizeof(bof)), sizeof(packet_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, RAW pkt len : %d\n", __LINE__, packet_len);
+/* if (packet_len > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, RAW pkt len error : %d\n", __LINE__, packet_len);
+ return;
+ } */
+
+ if ((packet_len + sizeof(mux) + sizeof(bof) + sizeof(eof)) > (total_size - read_size)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, RAW packet_len : %d, remain : %d\n", __LINE__, packet_len, total_size - read_size);
+
+ rx_prev_data_mux = 0x0002;
+
+ memcpy((void *)rx_save_b, (void *)(rx_b + p_read + sizeof(mux)), total_size - read_size - sizeof(mux));
+ rx_prev_data_size = total_size - read_size - sizeof(mux);
+ rx_prev_data_remain = packet_len + sizeof(bof) + sizeof(eof) - rx_prev_data_size;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data save, RAW size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_raw_rx((void *)(rx_b + p_read + sizeof(mux)), packet_len + sizeof(bof) + sizeof(eof));
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, cp -> ap RAW memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, one packet RAW read Done.\n", __LINE__); */
+ }
+
+#ifdef RAW_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RAW RX :");
+ for (i = 0 ; i < (packet_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + p_read + sizeof(mux) + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_read += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+ read_size += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, RAW read size : %d\n", __LINE__, read_size); */
+ }
+
+ /* make data interrupt cmd */
+ int_cmd = MB_DATA(MBD_SEND_RAW);
+ ipc_spi_make_data_interrupt(int_cmd, od);
+ break;
+
+ case 0x0003:
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, got RFS : %x\n", __LINE__, mux); */
+
+ if (rx_prev_data_saved) {
+ if (rx_prev_data_remain > DEF_BUF_SIZE) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data, RFS saved : %d, remain : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_mux = 0x0003;
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), DEF_BUF_SIZE);
+ rx_prev_data_size += DEF_BUF_SIZE;
+ rx_prev_data_remain -= DEF_BUF_SIZE;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data save, RFS size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), rx_prev_data_remain);
+ p_read += rx_prev_data_remain;
+ read_size += rx_prev_data_remain;
+
+ if (*rx_save_b != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RFS bof error : %x\n", __LINE__, *rx_save_b);
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ if (*(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1) != 0x7E) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RFS eof error : %x\n", __LINE__, *(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1));
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_rfs_rx((void *)rx_save_b, rx_prev_data_size + rx_prev_data_remain);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx prev data, cp -> ap RFS memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) rx prev data, <= one packet RFS read Done. size : %d, total_size : %d, read_size : %d, p_read : %d\n", __LINE__,
+ rx_prev_data_size + rx_prev_data_remain, total_size, read_size, p_read);
+ }
+
+#ifdef RFS_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX :");
+ for (i = 0 ; i < (rx_prev_data_size + rx_prev_data_remain) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_save_b + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+#ifdef RFS_TX_RX_LENGTH_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX : %d]\n", rx_prev_data_size + rx_prev_data_remain);
+#endif
+
+ rx_prev_data_saved = 0;
+ } else {
+ /* read packet len */
+ memcpy((void *)&packet_len, (void *)(rx_b + p_read + sizeof(mux) + sizeof(bof)), sizeof(packet_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, RFS pkt len : %d\n", __LINE__, packet_len);
+/* if (packet_len > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, RFS pkt len error : %d\n", __LINE__, packet_len);
+ return;
+ } */
+
+ if ((packet_len + sizeof(mux) + sizeof(bof) + sizeof(eof)) > (total_size - read_size)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, RFS packet_len : %d, remain : %d\n", __LINE__, packet_len, total_size - read_size);
+
+ rx_prev_data_mux = 0x0003;
+
+ memcpy((void *)rx_save_b, (void *)(rx_b + p_read + sizeof(mux)), total_size - read_size - sizeof(mux));
+ rx_prev_data_size = total_size - read_size - sizeof(mux);
+ rx_prev_data_remain = packet_len + sizeof(bof) + sizeof(eof) - rx_prev_data_size;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data save, RFS size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_rfs_rx((void *)(rx_b + p_read + sizeof(mux)), packet_len + sizeof(bof) + sizeof(eof));
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, cp -> ap RFS memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, one packet RFS read Done.\n", __LINE__); */
+ }
+
+#ifdef RFS_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX :");
+ for (i = 0 ; i < (packet_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + p_read + sizeof(mux) + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_read += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+ read_size += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, RFS read size : %d\n", __LINE__, read_size); */
+
+#ifdef RFS_TX_RX_LENGTH_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX : %d]\n", packet_len);
+#endif
+
+ }
+
+ /* make data interrupt cmd */
+ int_cmd = MB_DATA(MBD_SEND_RFS);
+ ipc_spi_make_data_interrupt(int_cmd, od);
+ break;
+
+ case 0x0004:
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, got command : %x\n", __LINE__, mux);
+ break;
+
+ default:
+ break;
+ }
+
+ if (total_size < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, read error.\n", __LINE__);
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, LOOP ==== total : %d, read : %d, p_read : %d\n", __LINE__, total_size, read_size, p_read); */
+ }
+}
+
+static int ipc_spi_thread(void *data)
+{
+ struct ipc_spi *od = (struct ipc_spi *)data;
+
+ int retval = 0;
+#ifdef LOOPBACK_TEST
+ u8 *tx_buf = NULL;
+ struct spi_protocol_header *tx_header = NULL;
+ u8 *rx_buf = NULL;
+ struct spi_protocol_header *rx_header = NULL;
+ int skip_SRDY_chk = 0;
+ int clear_tx_buf = 0;
+ u8 *rx_save_buf = NULL;
+ u8 *test_data = NULL;
+ int tx_loopback_data = 1;
+ u8 rx_loopback_data;
+ int i, rx_loopback_count = 0;
+#endif
+
+#if defined(CONFIG_MACH_Q1_BD)
+ u32 val = __raw_readl(S5P_INFORM2);
+
+ if (val == 1) {
+ printk(KERN_ERR "[LPM mode] ipc_spi_thread exit!\n");
+ goto exit;
+ }
+#else
+ if (lpcharge == 1) {
+ printk(KERN_ERR "[LPM mode] ipc_spi_thread exit!\n");
+ goto exit;
+ }
+#endif
+
+ daemonize("ipc_spi_thread");
+
+ printk(KERN_ERR "[%s] ipc_spi_thread start.\n", __func__);
+ boot_done = 1;
+
+ wait_for_completion(&ril_init);
+
+ printk(KERN_ERR "[%s] ril_init completed.\n", __func__);
+
+ if (!p_ipc_spi) {
+ printk(KERN_ERR "[%s] p_ipc_spi is NULL.\n", __func__);
+
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!p_virtual_buff) {
+ dev_err(&p_ipc_spi->dev, "[%s] p_virtual_buff is NULL.\n", __func__);
+
+ retval = -ENODEV;
+ goto exit;
+ }
+
+#ifdef LOOPBACK_TEST
+ tx_buf = kmalloc(DEF_BUF_SIZE + 4, GFP_ATOMIC);
+ if (!tx_buf) {
+ dev_err(&p_ipc_spi->dev, "[%s] tx_buf kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ tx_header = (struct spi_protocol_header *)tx_buf;
+
+ rx_buf = kmalloc(DEF_BUF_SIZE + 4, GFP_ATOMIC);
+ if (!rx_buf) {
+ dev_err(&p_ipc_spi->dev, "[%s] rx_buf kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ rx_header = (struct spi_protocol_header *)rx_buf;
+
+ rx_save_buf = kmalloc(DEF_BUF_SIZE * 3, GFP_ATOMIC);
+ if (!rx_save_buf) {
+ dev_err(&p_ipc_spi->dev, "[%s] rx_save_buf kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ memset((void *)rx_save_buf, 0, DEF_BUF_SIZE * 3);
+
+ test_data = kmalloc(DEF_BUF_SIZE + 4, GFP_ATOMIC);
+ if (!test_data) {
+ dev_err(&p_ipc_spi->dev, "[%s] test_data kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ memset((void *)test_data, 0, DEF_BUF_SIZE + 4);
+#endif
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) wait 2 sec... srdy : %d\n", __LINE__, gpio_get_value(gpio_srdy));
+ msleep(2000);
+
+ while (gpio_get_value(gpio_srdy))
+ ;
+ dev_dbg(&p_ipc_spi->dev, "(%d) cp booting... Done.\n", __LINE__);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) wait 1 sec...\n", __LINE__);
+ msleep(1000);
+
+ printk(KERN_ERR "[IPC_SPI] Start IPC Communication. MRDY : %d, SRDY : %d\n", gpio_get_value(gpio_mrdy), gpio_get_value(gpio_srdy));
+ sema_init(&srdy_sem, 0);
+
+ ipc_spi_irq_log_flag = 1;
+
+#ifndef LOOPBACK_TEST
+ spi_main(1, od);
+#else
+ while (1) {
+
+ if (!ipc_spi_check_send_data()) { /* no send data */
+ if (down_trylock(&srdy_sem)) { /* no srdy sem */
+ dev_dbg(&p_ipc_spi->dev, "(%d) no data and no sem, wait tx-srdy event.\n", __LINE__);
+
+ transfer_thread_waiting = 1;
+
+ skip_SRDY_chk = 0;
+
+ down(&transfer_event_sem); /* wait event(tx or srdy) */
+ dev_dbg(&p_ipc_spi->dev, "(%d) got tx-srdy event.\n", __LINE__);
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) srdy_sem already exist\n", __LINE__);
+
+ skip_SRDY_chk = 1;
+ clear_tx_buf = 1;
+ }
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) send data exist\n", __LINE__);
+ }
+
+ /* HERE : Got tx data event or Got SRDY isr event */
+ if (gpio_get_value(gpio_mrdy)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) MRDY HIGH!!!\n", __LINE__);
+
+ ipc_spi_set_MRDY_pin(0);
+ }
+ ipc_spi_set_MRDY_pin(1);
+
+ do {
+
+ if (clear_tx_buf) {
+ memset((void *)tx_buf, 0, DEF_BUF_SIZE + 4);
+
+ clear_tx_buf = 0;
+ } else {
+ ipc_spi_prepare_tx_data(tx_buf);
+ }
+#ifdef LOOPBACK_TEST
+ if (loop_back_test) {
+ if (tx_header->current_data_size == 0x3) {
+ /*C2 send*/
+ } else {
+ memset((void *)test_data, tx_loopback_data, LOOP_SIZE-18);
+ ipc_spi_prepare_loopback_tx_data(tx_buf, rx_buf , test_data);
+ if (tx_loopback_data == 0x0A) {
+ loop_back_test = 1;
+ tx_loopback_data = 1;
+ } else
+ tx_loopback_data++;
+ }
+ }
+ skip_SRDY_chk = 1; /* AP Only Loopback */
+#endif
+
+ if (!skip_SRDY_chk) {
+RETRY_WAIT_SEM:
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) wait SRDY : %d\n", __LINE__, gpio_get_value(gpio_srdy));
+
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! MRDY : %d, SRDY : %d\n", __LINE__, gpio_get_value(gpio_mrdy), gpio_get_value(gpio_srdy));
+
+ ipc_spi_set_MRDY_pin(0);
+ mdelay(10);
+ ipc_spi_set_MRDY_pin(1);
+
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT Reset!!! MRDY : %d, SRDY : %d\n", __LINE__, gpio_get_value(gpio_mrdy), gpio_get_value(gpio_srdy));
+
+ if (!gpio_get_value(gpio_srdy))
+ goto RETRY_WAIT_SEM;
+ }
+ dev_dbg(&p_ipc_spi->dev, "(%d) got SRDY : %d\n", __LINE__, gpio_get_value(gpio_srdy));
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) skip wait SRDY.\n", __LINE__);
+
+ skip_SRDY_chk = 0;
+ }
+
+ ipc_spi_swap_data_htn(tx_buf, DEF_BUF_SIZE + 4); /* host to network */
+
+ retval = ipc_spi_tx_rx_sync(tx_buf, rx_buf, DEF_BUF_SIZE + 4);
+ if (retval != 0)
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ else
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+
+ ipc_spi_swap_data_nth(rx_buf, DEF_BUF_SIZE + 4); /* network to host */
+ *(u32 *)tx_header = ntohl(*(u32 *)tx_header);
+
+#ifdef LOOPBACK_TEST
+ printk(KERN_ERR "[SPI DUMP] LOOP RX :]");
+ for (i = 0 ; i < 30 ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(rx_buf + i)));
+
+ printk(KERN_ERR "| ");
+ for (i = LOOP_SIZE - 30 ; i < LOOP_SIZE ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(rx_buf + i)));
+
+ printk(KERN_ERR "]\n");
+#else
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] RX : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3], rx_buf[4], rx_buf[5], rx_buf[6], rx_buf[7], rx_buf[8], rx_buf[9], rx_buf[10], rx_buf[11], rx_buf[12], rx_buf[13], rx_buf[14], rx_buf[15], rx_buf[16], rx_buf[17], rx_buf[18], rx_buf[19],
+ rx_buf[20], rx_buf[21], rx_buf[22], rx_buf[23], rx_buf[24], rx_buf[25], rx_buf[26], rx_buf[27], rx_buf[28], rx_buf[29], rx_buf[30], rx_buf[31], rx_buf[32], rx_buf[33], rx_buf[34], rx_buf[35], rx_buf[36], rx_buf[37], rx_buf[38], rx_buf[39]);
+#endif
+
+#ifdef LOOPBACK_TEST
+ /* Loopback test, IPC header[0A 0C 03] */
+ if (rx_buf[14] == 0x0A && rx_buf[15] == 0x0B && rx_buf[16] == 0x01) {
+ rx_loopback_data = rx_buf[17];
+
+ for (i = 0; i < LOOP_SIZE - 18; i++) {
+ if (rx_buf[17+i] != rx_loopback_data) {
+ printk(KERN_ERR "[Loopback] %dth %02x != %02x Invaild data!\n", i, rx_loopback_data, rx_buf[17+i]);
+ goto exit;
+ }
+ }
+ if (i == (LOOP_SIZE-18))
+ printk(KERN_ERR "[Loopback] %02x is OK!\n", rx_loopback_data);
+
+ rx_loopback_count++;
+ if ((rx_loopback_count % 10) == 0 && rx_loopback_data == 0x0A) {
+ tx_loopback_data = 1;
+ loop_back_test = 1;
+ printk(KERN_ERR "[Loopback] rx_loopback_count = %d\n", rx_loopback_count);
+ }
+ rx_header->RTSCTS = 0;
+ rx_header->more = 0;
+ }
+#else
+ if (*(u32 *)rx_header != 0x00000000 && *(u32 *)rx_header != 0xFFFFFFFF) { /* valid spi header */
+/* dev_dbg(&p_ipc_spi->dev, "(%d) got valid rx data.\n", __LINE__); */
+
+ /* RX process */
+ ipc_spi_rx_process(rx_buf, rx_save_buf, od);
+
+ if (rx_header->RTSCTS) { /* modem is not available. */
+ dev_err(&p_ipc_spi->dev, "(%d) rx CTS set.\n", __LINE__);
+
+ clear_tx_buf = 1;
+ }
+
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) got invalid rx data.\n", __LINE__); */
+
+ rx_header->RTSCTS = 0;
+ rx_header->more = 0;
+ }
+#endif
+ dev_dbg(&p_ipc_spi->dev, "(%d) check more, CTS : %d, rx more : %d, tx more : %d\n", __LINE__, rx_header->RTSCTS, rx_header->more, tx_header->more);
+ msleep(2000);
+ } while (rx_header->RTSCTS || rx_header->more || tx_header->more);
+
+ ipc_spi_set_MRDY_pin(0);
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) LOOP Done ============================\n", __LINE__); */
+ }
+#endif
+
+exit:
+ printk(KERN_ERR "(%d) thread stop.\n", __LINE__);
+
+ return retval;
+}
+
+/* Send SPRD main image through SPI */
+#if defined(CONFIG_CHN_CMCC_SPI_SPRD)
+#define CP_VER_2
+/* #define SPRD_TRANSLATE_PACKET */
+#define SPRD_BLOCK_SIZE 32768
+
+#ifdef CP_VER_2
+enum image_type {
+ MODEM_MAIN,
+ MODEM_DSP,
+ MODEM_NV,
+ MODEM_EFS,
+ MODEM_RUN,
+};
+#else
+enum image_type {
+ MODEM_KERNEL,
+ MODEM_USER,
+ MODEM_DSP,
+ MODEM_NV,
+ MODEM_RUN,
+};
+#endif
+
+struct image_buf {
+ unsigned int length;
+ unsigned int offset;
+ unsigned int address;
+ unsigned char *buf;
+};
+
+struct sprd_image_buf {
+ u8 *tx_b;
+ u8 *rx_b;
+ u8 *encoded_tx_b;
+ u8 *decoded_rx_b;
+
+ int tx_size;
+ int rx_size;
+ int encoded_tx_size;
+ int decoded_rx_size;
+};
+
+/* CRC */
+#define CRC_16_POLYNOMIAL 0x1021
+#define CRC_16_L_POLYNOMIAL 0x8408
+#define CRC_16_L_SEED 0xFFFF
+#define CRC_TAB_SIZE 256 /* 2^CRC_TAB_BITS */
+#define CRC_16_L_OK 0x0
+#define HDLC_FLAG 0x7E
+#define HDLC_ESCAPE 0x7D
+#define HDLC_ESCAPE_MASK 0x20
+#define CRC_CHECK_SIZE 0x02
+
+#define M_32_SWAP(a) { \
+ u32 _tmp; \
+ _tmp = a; \
+ ((u8 *)&a)[0] = ((u8 *)&_tmp)[3]; \
+ ((u8 *)&a)[1] = ((u8 *)&_tmp)[2]; \
+ ((u8 *)&a)[2] = ((u8 *)&_tmp)[1]; \
+ ((u8 *)&a)[3] = ((u8 *)&_tmp)[0]; \
+ }
+
+#define M_16_SWAP(a) { \
+ u16 _tmp; \
+ _tmp = (u16)a; \
+ ((u8 *)&a)[0] = ((u8 *)&_tmp)[1]; \
+ ((u8 *)&a)[1] = ((u8 *)&_tmp)[0]; \
+ }
+
+unsigned int sprd_crc_calc(char *buf_ptr, unsigned int len)
+{
+ unsigned int i;
+ unsigned short crc = 0;
+
+ while (len-- != 0) {
+ for (i = 0x80; i != 0 ; i = i>>1) {
+ if ((crc & 0x8000) != 0) {
+ crc = crc << 1 ;
+ crc = crc ^ 0x1021;
+ } else {
+ crc = crc << 1 ;
+ }
+
+ if ((*buf_ptr & i) != 0)
+ crc = crc ^ 0x1021;
+ }
+ buf_ptr++;
+ }
+
+ return crc;
+
+}
+
+unsigned short sprd_crc_calc_fdl(unsigned short *src, int len)
+{
+ unsigned int sum = 0;
+ unsigned short SourceValue, DestValue;
+ unsigned short lowSourceValue, hiSourceValue;
+
+ /* Get sum value of the source.*/
+ while (len > 1) {
+ SourceValue = *src++;
+ DestValue = 0;
+ lowSourceValue = (SourceValue & 0xFF00) >> 8;
+ hiSourceValue = (SourceValue & 0x00FF) << 8;
+ DestValue = lowSourceValue | hiSourceValue;
+
+ sum += DestValue;
+ len -= 2;
+ }
+
+ if (len == 1)
+ sum += *((unsigned char *) src);
+
+ sum = (sum >> 16) + (sum & 0x0FFFF);
+ sum += (sum >> 16);
+
+ return ~sum;
+}
+
+int encode_msg(struct sprd_image_buf *img, int bcrc)
+{
+ u16 crc; /* CRC value*/
+ u8 *src_ptr; /* source buffer pointer*/
+ int dest_len; /* output buffer length*/
+ u8 *dest_ptr; /* dest buffer pointer*/
+ u8 high_crc, low_crc;
+ register int curr;
+
+ /* CRC Check. */
+ src_ptr = img->tx_b;
+
+ /* CRC Check. */
+ if (bcrc)
+ crc = sprd_crc_calc(src_ptr, img->tx_size);
+ else
+ crc = sprd_crc_calc_fdl((unsigned short *)src_ptr, img->tx_size);
+
+ high_crc = (crc>>8) & 0xFF;
+ low_crc = crc & 0xFF;
+
+ /* Get the total size to be allocated.*/
+ dest_len = 0;
+
+ for (curr = 0; curr < img->tx_size; curr++) {
+ switch (*(src_ptr+curr)) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ dest_len += 2;
+ break;
+ default:
+ dest_len++;
+ break;
+ }
+ }
+
+ switch (low_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ dest_len += 2;
+ break;
+ default:
+ dest_len++;
+ }
+
+ switch (high_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ dest_len += 2;
+ break;
+ default:
+ dest_len++;
+ }
+
+ dest_ptr = kmalloc(dest_len + 2, GFP_ATOMIC);
+ /* Memory Allocate fail.*/
+ if (dest_ptr == NULL)
+ return 0;
+
+ *dest_ptr = HDLC_FLAG;
+ dest_len = 1;
+
+ /* do escape*/
+ for (curr = 0; curr < img->tx_size; curr++) {
+ switch (*(src_ptr+curr)) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ *(dest_ptr + dest_len++) = HDLC_ESCAPE;
+ *(dest_ptr + dest_len++) = *(src_ptr + curr) ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len++) = *(src_ptr + curr);
+ break;
+ }
+ }
+
+ switch (high_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ *(dest_ptr + dest_len++) = HDLC_ESCAPE;
+ *(dest_ptr + dest_len++) = high_crc ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len++) = high_crc;
+ }
+
+ switch (low_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ *(dest_ptr + dest_len++) = HDLC_ESCAPE;
+ *(dest_ptr + dest_len++) = low_crc ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len++) = low_crc;
+ }
+
+
+ *(dest_ptr + dest_len++) = HDLC_FLAG;
+
+ memcpy(img->encoded_tx_b, dest_ptr, dest_len);
+ img->encoded_tx_size = dest_len;
+/*
+ LOGD("[In encode_msg dest_ptr]");
+ for (i=0;i<dest_len;i++)
+ LOGD("0x%X", *(dest_ptr+i));
+
+ LOGD("[In encode_msg output_buf]");
+ for (i=0;i<img->encoded_tx_size;i++)
+ LOGD("0x%X", *(img->encoded_tx_b+i));
+*/
+ kfree(dest_ptr);
+ return 1;
+}
+
+int decode_msg(struct sprd_image_buf *img, int bcrc)
+{
+ u16 crc; /* CRC value*/
+ u8 *src_ptr; /* source buffer pointer*/
+ int dest_len; /* output buffer length*/
+ u8 *dest_ptr; /* dest buffer pointer*/
+ register int curr;
+
+ /* Check if exist End Flag.*/
+ src_ptr = img->rx_b;
+
+ dest_len = 0;
+
+ if (img->rx_size < 4)
+ return -1;
+
+ /* Get the total size to be allocated for decoded message.*/
+ for (curr = 1; curr < img->rx_size - 1; curr++) {
+ switch (*(src_ptr + curr)) {
+ case HDLC_ESCAPE:
+ curr++;
+ dest_len++;
+ break;
+ default:
+ dest_len++;
+ break;
+ }
+ }
+
+ /* Allocate meomory for decoded message*/
+ dest_ptr = NULL;
+ dest_ptr = kmalloc(dest_len, GFP_ATOMIC);
+ /* Memory Free fail.*/
+ if (dest_ptr == NULL)
+ return -2;
+
+ memset(dest_ptr, 0, dest_len);
+
+ curr = 0;
+ dest_len = 0;
+ /* Do de-escape.*/
+ for (curr = 1; curr < img->rx_size - 1; curr++) {
+ switch (*(src_ptr + curr)) {
+ case HDLC_ESCAPE:
+ curr++;
+ *(dest_ptr + dest_len) = *(src_ptr + curr) ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len) = *(src_ptr + curr);
+ break;
+ }
+
+ dest_len = dest_len + 1;
+ }
+
+ /* CRC Check. */
+ if (bcrc)
+ crc = sprd_crc_calc(dest_ptr, dest_len);
+ else
+ crc = sprd_crc_calc_fdl((unsigned short *)dest_ptr, dest_len);
+
+ if (crc != CRC_16_L_OK) {
+ dev_err(&p_ipc_spi->dev, "CRC error : 0x%X", crc);
+ kfree(dest_ptr);
+ return -3;
+ }
+
+ memcpy(img->decoded_rx_b, dest_ptr, dest_len - CRC_CHECK_SIZE);
+ img->decoded_rx_size = dest_len - CRC_CHECK_SIZE ;
+/*
+ LOGD("[In decode_msg dest_ptr]");
+ for (i=0;i<dest_len;i++)
+ LOGD("0x%X", *(dest_ptr+i));
+
+ LOGD("[In decode_msg output_buf]");
+ for (i=0;i<*img->decoded_rx_size;i++)
+ LOGD("0x%X", *(img->decoded_rx_b+i));
+*/
+ kfree(dest_ptr);
+ return 1;
+}
+
+static int ipc_spi_send_modem_bin_execute_cmd(struct ipc_spi *od, u8 *spi_ptr, u32 spi_size, u16 spi_type, u16 spi_crc, struct sprd_image_buf *sprd_img)
+{
+ int retval;
+ u16 send_packet_size;
+ u8 *send_packet_data;
+ u16 d1_crc;
+ u16 d2_crc = spi_crc;
+ u16 type = spi_type;
+#ifdef SPRD_TRANSLATE_PACKET
+ int i, cnt_7E = 0;
+ int bcrc = 0;
+#endif
+
+ /* D1 */
+ send_packet_size = spi_size; /* u32 -> u16 */
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img->tx_size = 6;
+ memcpy(sprd_img->tx_b, &send_packet_size, sizeof(send_packet_size));
+ *(sprd_img->tx_b+2) = 0x00; *(sprd_img->tx_b+3) = 0x00; /* reserved 4 bytes */
+ *(sprd_img->tx_b+4) = 0x00; *(sprd_img->tx_b+5) = 0x00;
+
+ d1_crc = sprd_crc_calc_fdl((unsigned short *)sprd_img->tx_b, sprd_img->tx_size);
+ M_16_SWAP(d1_crc);
+ memcpy((sprd_img->tx_b+6), &d1_crc, sizeof(d1_crc));
+ sprd_img->tx_size += 2;
+#else
+ sprd_img->tx_size = 6;
+ M_16_SWAP(d2_crc);
+ memcpy(sprd_img->tx_b, &send_packet_size, sizeof(send_packet_size));
+ memcpy((sprd_img->tx_b+2), &type, sizeof(type));
+ memcpy((sprd_img->tx_b+4), &d2_crc, sizeof(d2_crc));
+
+ d1_crc = sprd_crc_calc_fdl((unsigned short *)sprd_img->tx_b, sprd_img->tx_size);
+ M_16_SWAP(d1_crc);
+ memcpy((sprd_img->tx_b+6), &d1_crc, sizeof(d1_crc));
+ sprd_img->tx_size += 2;
+#endif
+/*
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] TX_D1(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->tx_size,
+ sprd_img->tx_b[0], sprd_img->tx_b[1], sprd_img->tx_b[2], sprd_img->tx_b[3], sprd_img->tx_b[4],
+ sprd_img->tx_b[5], sprd_img->tx_b[6], sprd_img->tx_b[7]);
+*/
+
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! SRDY : %d, SEM : %d\n", __LINE__, gpio_get_value(gpio_srdy), srdy_sem.count);
+ return -1;
+ }
+
+ retval = ipc_spi_tx_rx_sync(sprd_img->tx_b, sprd_img->rx_b, sprd_img->tx_size);
+ if (retval != 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ return -1;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+ }
+/*
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] TX_D2(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ send_packet_size, spi_ptr[0], spi_ptr[1], spi_ptr[2], spi_ptr[3], spi_ptr[4],
+ spi_ptr[5], spi_ptr[6], spi_ptr[7], spi_ptr[8], spi_ptr[9],
+ spi_ptr[10], spi_ptr[11], spi_ptr[12], spi_ptr[13], spi_ptr[14],
+ spi_ptr[15], spi_ptr[16], spi_ptr[17], spi_ptr[18], spi_ptr[19],
+ spi_ptr[send_packet_size - 10], spi_ptr[send_packet_size - 9], spi_ptr[send_packet_size - 8], spi_ptr[send_packet_size - 7], spi_ptr[send_packet_size - 6],
+ spi_ptr[send_packet_size - 5], spi_ptr[send_packet_size - 4], spi_ptr[send_packet_size - 3], spi_ptr[send_packet_size - 2], spi_ptr[send_packet_size - 1]);
+*/
+ if ((type == 0x0003) || (type == 0x0004)) {
+ printk(KERN_ERR "D2 Skip!!\n");
+ goto ACK;
+ }
+
+ /* D2 */
+ send_packet_data = spi_ptr;
+
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! SRDY : %d, SEM : %d\n", __LINE__, gpio_get_value(gpio_srdy), srdy_sem.count);
+ return -1;
+ }
+
+ retval = ipc_spi_tx_rx_sync(send_packet_data, sprd_img->rx_b, send_packet_size);
+ if (retval != 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ return -1;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+ }
+
+ACK:
+
+ if (is_cp_reset) {
+ while (!gpio_get_value(gpio_srdy))
+ ;
+ } else {
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! SRDY : %d, SEM : %d\n", __LINE__, gpio_get_value(gpio_srdy), srdy_sem.count);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] TX_D1(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->tx_size,
+ sprd_img->tx_b[0], sprd_img->tx_b[1], sprd_img->tx_b[2], sprd_img->tx_b[3], sprd_img->tx_b[4],
+ sprd_img->tx_b[5], sprd_img->tx_b[6], sprd_img->tx_b[7]);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] TX_D2(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ send_packet_size, spi_ptr[0], spi_ptr[1], spi_ptr[2], spi_ptr[3], spi_ptr[4],
+ spi_ptr[5], spi_ptr[6], spi_ptr[7]);
+
+ /* WA (CP Reset) jongmoon.suh */
+ if (gpio_get_value(gpio_srdy))
+ ;
+ else
+ return -1;
+
+ }
+ }
+
+ memset(sprd_img->tx_b, 0, SPRD_BLOCK_SIZE+10);
+ retval = ipc_spi_tx_rx_sync(sprd_img->tx_b, sprd_img->rx_b, 8);
+ if (retval != 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ return -1;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+ }
+#ifdef SPRD_TRANSLATE_PACKET
+ for (i = 0; i < 8; i++) {
+ if (*(sprd_img->rx_b+i) == 0x7E)
+ cnt_7E++;
+ if (cnt_7E == 2)
+ break;
+ }
+ sprd_img->rx_size = i + 1;
+/*
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] RX(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->rx_size,
+ sprd_img->rx_b[0], sprd_img->rx_b[1], sprd_img->rx_b[2], sprd_img->rx_b[3], sprd_img->rx_b[4], sprd_img->rx_b[5], sprd_img->rx_b[6], sprd_img->rx_b[7],
+ sprd_img->rx_b[8], sprd_img->rx_b[9], sprd_img->rx_b[10], sprd_img->rx_b[11], sprd_img->rx_b[12], sprd_img->rx_b[13], sprd_img->rx_b[14], sprd_img->rx_b[15]);
+*/
+ if (sprd_img->rx_size != 8) {
+ dev_err(&p_ipc_spi->dev, "ACK size error!, %d\n", sprd_img->rx_size);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] RX(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->rx_size,
+ sprd_img->rx_b[0], sprd_img->rx_b[1], sprd_img->rx_b[2], sprd_img->rx_b[3], sprd_img->rx_b[4], sprd_img->rx_b[5], sprd_img->rx_b[6], sprd_img->rx_b[7],
+ sprd_img->rx_b[8], sprd_img->rx_b[9], sprd_img->rx_b[10], sprd_img->rx_b[11], sprd_img->rx_b[12], sprd_img->rx_b[13], sprd_img->rx_b[14], sprd_img->rx_b[15]);
+
+ return -1;
+ }
+ retval = decode_msg(sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "decode_msg(ACK) error!\n");
+ return -1;
+ }
+#else
+ memcpy(sprd_img->decoded_rx_b, sprd_img->rx_b, 4);
+#endif
+ if ((*(sprd_img->decoded_rx_b+0) == 0x00) && (*(sprd_img->decoded_rx_b+1) == 0x80) &&
+ (*(sprd_img->decoded_rx_b+2) == 0x00) && (*(sprd_img->decoded_rx_b+3) == 0x00)) {
+ /* dev_dbg(&p_ipc_spi->dev, "[SPRD] CP sent ACK"); */
+ } else {
+ dev_err(&p_ipc_spi->dev, "Transfer ACK error!srdy_sem = %d\n", srdy_sem.count);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] RX : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ sprd_img->rx_b[0], sprd_img->rx_b[1], sprd_img->rx_b[2], sprd_img->rx_b[3], sprd_img->rx_b[4], sprd_img->rx_b[5], sprd_img->rx_b[6], sprd_img->rx_b[7],
+ sprd_img->rx_b[8], sprd_img->rx_b[9], sprd_img->rx_b[10], sprd_img->rx_b[11], sprd_img->rx_b[12], sprd_img->rx_b[13], sprd_img->rx_b[14], sprd_img->rx_b[15]);
+
+ return -1;
+ }
+
+ return retval;
+
+}
+
+static int ipc_spi_send_modem_bin_xmit_img(struct ipc_spi *od, enum image_type type, struct image_buf *img)
+{
+ int retval = 0;
+ struct sprd_image_buf sprd_img;
+ unsigned int data_size;
+ unsigned int send_size = 0;
+ unsigned int rest_size = 0;
+ unsigned int spi_size = 0;
+ unsigned int address;
+ unsigned int fdl1_size;
+ /* No Translate */
+ u16 crc = 0;
+ u16 spi_type = 0;
+
+ unsigned char *spi_ptr;
+ unsigned char *ptr;
+ int i, j;
+#ifdef SPRD_TRANSLATE_PACKET
+ int bcrc = 0;
+#endif
+ u16 sprd_packet_size = SPRD_BLOCK_SIZE;
+
+ sprd_img.tx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.tx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) tx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.tx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ sprd_img.rx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.rx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.rx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ sprd_img.encoded_tx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.encoded_tx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) encoded_tx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.encoded_tx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ sprd_img.decoded_rx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.decoded_rx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) encoded_rx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.decoded_rx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img type : %d.\n", __LINE__, type);
+ memcpy(&fdl1_size, (void *)(p_virtual_buff + 4), 4);
+
+ switch (type) {
+#ifdef CP_VER_2
+ case MODEM_MAIN:
+ memcpy(&img->address, (void *)(p_virtual_buff + 8), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 12), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + 0x30 + fdl1_size);
+ img->offset = img->length + fdl1_size + 0x30;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save MAIN to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_DSP:
+ memcpy(&img->address, (void *)(p_virtual_buff + 16), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 20), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save DSP to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_NV:
+ memcpy(&img->address, (void *)(p_virtual_buff + 24), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 28), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save NV to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_EFS:
+ memcpy(&img->address, (void *)(p_virtual_buff + 32), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 36), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save EFS to img.\n", __LINE__);
+
+ break;
+#else
+ case MODEM_KERNEL:
+ memcpy(&img->address, (void *)(p_virtual_buff + 8), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 12), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + 0x30 + fdl1_size);
+ img->offset = img->length + fdl1_size + 0x30;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save KERNEL to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_USER:
+ memcpy(&img->address, (void *)(p_virtual_buff + 16), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 20), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save USER to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_DSP:
+ memcpy(&img->address, (void *)(p_virtual_buff + 24), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 28), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save DSP to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_NV:
+ memcpy(&img->address, (void *)(p_virtual_buff + 32), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 36), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save NV to img.\n", __LINE__);
+
+ break;
+#endif
+ case MODEM_RUN:
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = 4;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x04;
+ *(sprd_img.tx_b+2) = 0x00; *(sprd_img.tx_b+3) = 0x00;
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(Transfer Start) error!");
+ return -1;
+ }
+#else
+ memset(sprd_img.encoded_tx_b, 0, SPRD_BLOCK_SIZE*2);
+ sprd_img.encoded_tx_size = 0;
+ spi_type = 0x0004;
+ crc = 0;
+#endif
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+ return retval;
+
+ default:
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img wrong : %d.", __LINE__, type);
+ return -1;
+ }
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) Start send img. size : %d\n", __LINE__, img->length);
+
+ ptr = img->buf;
+ data_size = sprd_packet_size;
+ rest_size = img->length;
+ address = img->address;
+
+ M_32_SWAP(img->address);
+ M_32_SWAP(img->length);
+
+ /* Send Transfer Start */
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = 12;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x01;
+ *(sprd_img.tx_b+2) = 0x00; *(sprd_img.tx_b+3) = 0x08;
+ memcpy((sprd_img.tx_b+4), &img->address, sizeof(img->address));
+ memcpy((sprd_img.tx_b+8), &img->length, sizeof(img->length));
+
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(Transfer Start) error!");
+ return -1;
+ }
+#else
+ sprd_img.tx_size = 8;
+ memcpy((sprd_img.tx_b+0), &img->address, sizeof(img->address));
+ memcpy((sprd_img.tx_b+4), &img->length, sizeof(img->length));
+
+ spi_type = 0x0001;
+ crc = sprd_crc_calc_fdl((unsigned short *)sprd_img.tx_b, sprd_img.tx_size);
+ memcpy(sprd_img.encoded_tx_b, sprd_img.tx_b, sprd_img.tx_size);
+ sprd_img.encoded_tx_size = sprd_img.tx_size;
+#endif
+
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) [Transfer Start, Type = %d, Packet = %d]\n", __LINE__, type, sprd_packet_size);
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+ M_32_SWAP(img->length);
+
+ /* Send Data */
+ for (i = 0; send_size < img->length; i++) {
+ if (rest_size < sprd_packet_size)
+ data_size = rest_size;
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = sprd_packet_size + 4;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x02; /* type */
+ M_16_SWAP(sprd_packet_size);
+ memcpy((sprd_img.tx_b + 2), &sprd_packet_size, sizeof(sprd_packet_size));
+ M_16_SWAP(sprd_packet_size);
+
+ for (j = 0; j < data_size; j++)
+ *(sprd_img.tx_b+4+j) = *(ptr + j);
+
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(TransferData_%d) error!", i);
+ return -1;
+ }
+#else
+ sprd_img.encoded_tx_size = sprd_packet_size;
+ for (j = 0; j < data_size; j++)
+ *(sprd_img.encoded_tx_b+j) = *(ptr + j);
+
+ spi_type = 0x0002;
+ crc = sprd_crc_calc_fdl((unsigned short *)sprd_img.encoded_tx_b, sprd_img.encoded_tx_size);
+#endif
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d, %d", __LINE__, retval, i);
+ return -1;
+ }
+
+ send_size += data_size;
+ rest_size -= data_size;
+ ptr += data_size;
+
+ if (!(i % 100))
+ dev_dbg(&p_ipc_spi->dev, "(%d) [%d] 0x%x size done, rest size: 0x%x\n", __LINE__, i, send_size, rest_size);
+ }
+
+ /* Send Transfer End */
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = 4;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x03;
+ *(sprd_img.tx_b+2) = 0x00; *(sprd_img.tx_b+3) = 0x00;
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(TransferEnd) error!");
+ return -1;
+ }
+#else
+ memset(sprd_img.encoded_tx_b, 0, SPRD_BLOCK_SIZE * 2);
+ sprd_img.encoded_tx_size = 0;
+
+ spi_type = 0x0003;
+ crc = 0;
+#endif
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) [Transfer END]\n", __LINE__);
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+
+ kfree(sprd_img.tx_b);
+ kfree(sprd_img.rx_b);
+ kfree(sprd_img.encoded_tx_b);
+ kfree(sprd_img.decoded_rx_b);
+
+ return retval;
+
+}
+
+static void ipc_spi_send_modem_bin(struct work_struct *send_modem_w)
+{
+ int retval = 0;
+ u32 int_cmd = 0xABCDABCD;
+ u32 int_cmd_fail = 0xDCBADCBA;
+ struct image_buf img;
+ unsigned long tick1, tick2;
+
+ struct ipc_spi_send_modem_bin_workq_data *smw
+ = container_of(send_modem_w, struct ipc_spi_send_modem_bin_workq_data, send_modem_w);
+ struct ipc_spi *od = smw->od;
+
+ tick1 = jiffies_to_msecs(jiffies);
+
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] p_virtual_buff : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ *(u8 *)(p_virtual_buff), *(u8 *)(p_virtual_buff + 1), *(u8 *)(p_virtual_buff + 2), *(u8 *)(p_virtual_buff + 3), *(u8 *)(p_virtual_buff + 4),
+ *(u8 *)(p_virtual_buff + 5), *(u8 *)(p_virtual_buff + 6), *(u8 *)(p_virtual_buff + 7), *(u8 *)(p_virtual_buff + 8), *(u8 *)(p_virtual_buff + 9),
+ *(u8 *)(p_virtual_buff + 10), *(u8 *)(p_virtual_buff + 11), *(u8 *)(p_virtual_buff + 12), *(u8 *)(p_virtual_buff + 13), *(u8 *)(p_virtual_buff + 14),
+ *(u8 *)(p_virtual_buff + 15), *(u8 *)(p_virtual_buff + 16), *(u8 *)(p_virtual_buff + 17), *(u8 *)(p_virtual_buff + 18), *(u8 *)(p_virtual_buff + 19));
+#ifdef CP_VER_2
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_MAIN, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#else
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_KERNEL, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_USER, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#endif
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_DSP, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#ifdef CP_VER_2
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_EFS, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#endif
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_RUN, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+
+ send_modem_spi = 0;
+ is_cp_reset = 0;
+ tick2 = jiffies_to_msecs(jiffies);
+ dev_dbg(&p_ipc_spi->dev, "Downloading takes %lu msec\n", (tick2-tick1));
+
+ /* make data interrupt cmd */
+ ipc_spi_make_data_interrupt(int_cmd, od);
+
+ return;
+
+err:
+ /* make data interrupt cmd */
+ ipc_spi_make_data_interrupt(int_cmd_fail, od);
+
+}
+
+#else /*EUR */
+struct ipc_spi_send_modem_bin_header {
+ u16 sot;
+ u16 type;
+ u16 length;
+};
+
+struct ipc_spi_send_modem_bin_footer {
+ u16 crc;
+ u16 eot;
+};
+
+
+static u16 ipc_spi_send_modem_bin_make_crc(u8 *buf)
+{
+ u16 crc = 0;
+ int i;
+ struct ipc_spi_send_modem_bin_header *header = (struct ipc_spi_send_modem_bin_header *)(buf + 4);
+
+ crc += header->type;
+ crc += header->length;
+
+ buf += 4;
+ buf += sizeof(struct ipc_spi_send_modem_bin_header);
+ for (i = 0 ; i < header->length ; i++)
+ crc += *buf++;
+
+ return crc;
+}
+
+#define EBL_PACKET_SIZE 4096
+static int ipc_spi_send_modem_bin_execute_cmd(struct ipc_spi *od, u16 type, u32 len, void *data)
+{
+ int retval = 0;
+ u8 *tx_b = NULL;
+ u8 *rx_b = NULL;
+ struct spi_protocol_header *tx_spi_header = NULL;
+ struct spi_protocol_header *rx_spi_header = NULL;
+ struct ipc_spi_send_modem_bin_header *tx_header = NULL;
+ struct ipc_spi_send_modem_bin_footer *tx_footer = NULL;
+ struct ipc_spi_send_modem_bin_header *rx_header = NULL;
+ struct ipc_spi_send_modem_bin_footer *rx_footer = NULL;
+
+ tx_b = kmalloc(EBL_PACKET_SIZE, GFP_ATOMIC);
+ if (!tx_b) {
+ dev_err(od->dev, "(%d) tx_b kmalloc fail.", __LINE__);
+ return -ENOMEM;
+ }
+ tx_spi_header = (struct spi_protocol_header *)tx_b;
+ tx_header = (struct ipc_spi_send_modem_bin_header *)(tx_b + 4);
+ memset(tx_b, 0, EBL_PACKET_SIZE);
+
+ rx_b = kmalloc(EBL_PACKET_SIZE, GFP_ATOMIC);
+ if (!rx_b) {
+ dev_err(od->dev, "(%d) rx_b kmalloc fail.", __LINE__);
+ return -ENOMEM;
+ }
+ rx_spi_header = (struct spi_protocol_header *)rx_b;
+ rx_header = (struct ipc_spi_send_modem_bin_header *)(rx_b + 4);
+ memset(rx_b, 0, EBL_PACKET_SIZE);
+
+ ipc_spi_set_MRDY_pin(1);
+
+ tx_spi_header->next_data_size = (EBL_PACKET_SIZE - 4) >> 2;
+ tx_spi_header->current_data_size = sizeof(struct ipc_spi_send_modem_bin_header) + len + sizeof(struct ipc_spi_send_modem_bin_footer);
+
+ tx_header->sot = 0x0002;
+ tx_header->type = type;
+ tx_header->length = len;
+
+ memcpy((void *)(tx_b + sizeof(struct ipc_spi_send_modem_bin_header) + 4), data, len);
+
+ tx_footer = (struct ipc_spi_send_modem_bin_footer *)(tx_b + 4 + sizeof(struct ipc_spi_send_modem_bin_header) + len);
+
+ tx_footer->crc = ipc_spi_send_modem_bin_make_crc(tx_b);
+
+ tx_footer->eot = 0x0003;
+/*
+ dev_dbg(od->dev, "[SPI DUMP] tx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ tx_b[0], tx_b[1], tx_b[2], tx_b[3], tx_b[4],
+ tx_b[5], tx_b[6], tx_b[7], tx_b[8], tx_b[9],
+ tx_b[10], tx_b[11], tx_b[12], tx_b[13], tx_b[14],
+ tx_b[15], tx_b[16], tx_b[17], tx_b[18], tx_b[19],
+ tx_b[EBL_PACKET_SIZE - 10], tx_b[EBL_PACKET_SIZE - 9], tx_b[EBL_PACKET_SIZE - 8], tx_b[EBL_PACKET_SIZE - 7], tx_b[EBL_PACKET_SIZE - 6],
+ tx_b[EBL_PACKET_SIZE - 5], tx_b[EBL_PACKET_SIZE - 4], tx_b[EBL_PACKET_SIZE - 3], tx_b[EBL_PACKET_SIZE - 2], tx_b[EBL_PACKET_SIZE - 1]);
+*/
+ ipc_spi_swap_data_htn(tx_b, EBL_PACKET_SIZE);
+
+ down(&srdy_sem);
+
+ retval = ipc_spi_tx_rx_sync(tx_b, rx_b, EBL_PACKET_SIZE);
+ if (retval != 0)
+ dev_err(od->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ else
+ ;/*dev_dbg(od->dev, "(%d) transmit Done.\n", __LINE__); */
+
+/*
+ dev_dbg(od->dev, "[SPI DUMP] rx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_b[0], rx_b[1], rx_b[2], rx_b[3], rx_b[4],
+ rx_b[5], rx_b[6], rx_b[7], rx_b[8], rx_b[9],
+ rx_b[10], rx_b[11], rx_b[12], rx_b[13], rx_b[14],
+ rx_b[15], rx_b[16], rx_b[17], rx_b[18], rx_b[19],
+ rx_b[EBL_PACKET_SIZE - 10], rx_b[EBL_PACKET_SIZE - 9], rx_b[EBL_PACKET_SIZE - 8], rx_b[EBL_PACKET_SIZE - 7], rx_b[EBL_PACKET_SIZE - 6],
+ rx_b[EBL_PACKET_SIZE - 5], rx_b[EBL_PACKET_SIZE - 4], rx_b[EBL_PACKET_SIZE - 3], rx_b[EBL_PACKET_SIZE - 2], rx_b[EBL_PACKET_SIZE - 1]);
+*/
+
+ if (type == 0x0208) /* ReqForceHwReset */
+ return 0;
+
+ memset(tx_b, 0, EBL_PACKET_SIZE);
+ memset(rx_b, 0, EBL_PACKET_SIZE);
+
+ down(&srdy_sem);
+
+ retval = ipc_spi_tx_rx_sync(tx_b, rx_b, EBL_PACKET_SIZE);
+ if (retval != 0)
+ dev_err(od->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ else
+ ;/*dev_dbg(od->dev, "(%d) transmit Done.\n", __LINE__); */
+
+ ipc_spi_swap_data_nth(rx_b, EBL_PACKET_SIZE);
+/*
+ dev_dbg(od->dev, "[SPI DUMP] rx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_b[0], rx_b[1], rx_b[2], rx_b[3], rx_b[4],
+ rx_b[5], rx_b[6], rx_b[7], rx_b[8], rx_b[9],
+ rx_b[10], rx_b[11], rx_b[12], rx_b[13], rx_b[14],
+ rx_b[15], rx_b[16], rx_b[17], rx_b[18], rx_b[19],
+ rx_b[EBL_PACKET_SIZE - 10], rx_b[EBL_PACKET_SIZE - 9], rx_b[EBL_PACKET_SIZE - 8], rx_b[EBL_PACKET_SIZE - 7], rx_b[EBL_PACKET_SIZE - 6],
+ rx_b[EBL_PACKET_SIZE - 5], rx_b[EBL_PACKET_SIZE - 4], rx_b[EBL_PACKET_SIZE - 3], rx_b[EBL_PACKET_SIZE - 2], rx_b[EBL_PACKET_SIZE - 1]);
+*/
+ if (rx_header->type != type) {
+ dev_err(od->dev, "(%d) execute cmd ack error : 0x%x(0x%x)\n", __LINE__, rx_header->type, type);
+
+ dev_dbg(od->dev, "[SPI DUMP] rx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_b[0], rx_b[1], rx_b[2], rx_b[3], rx_b[4],
+ rx_b[5], rx_b[6], rx_b[7], rx_b[8], rx_b[9],
+ rx_b[10], rx_b[11], rx_b[12], rx_b[13], rx_b[14],
+ rx_b[15], rx_b[16], rx_b[17], rx_b[18], rx_b[19],
+ rx_b[EBL_PACKET_SIZE - 10], rx_b[EBL_PACKET_SIZE - 9], rx_b[EBL_PACKET_SIZE - 8], rx_b[EBL_PACKET_SIZE - 7], rx_b[EBL_PACKET_SIZE - 6],
+ rx_b[EBL_PACKET_SIZE - 5], rx_b[EBL_PACKET_SIZE - 4], rx_b[EBL_PACKET_SIZE - 3], rx_b[EBL_PACKET_SIZE - 2], rx_b[EBL_PACKET_SIZE - 1]);
+
+ retval = -1;
+ } else {
+/* dev_dbg(od->dev, "(%d) execute cmd ack Done.\n", __LINE__); */
+ }
+
+ ipc_spi_set_MRDY_pin(0);
+
+ return retval;
+}
+
+enum image_type {
+ MODEM_PSI,
+ MODEM_EBL,
+ MODEM_MAIN,
+ MODEM_NV,
+};
+
+struct image_buf {
+ unsigned int length;
+ unsigned char *buf;
+};
+
+#define PSI_OFFSET 0
+#define EBL_OFFSET 0x10000
+#define MAIN_OFFSET 0x28000
+#define NV_OFFSET 0xA00000
+
+#define PSI_LEN (EBL_OFFSET - PSI_OFFSET - 1)
+#define EBL_LEN (MAIN_OFFSET - EBL_OFFSET)
+#define MAIN_LEN (NV_OFFSET - MAIN_OFFSET)
+#define NV_LEN (2 * 1024 * 1024)
+
+#define MAIN_OFFSET_VM 0
+#define NV_OFFSET_VM 0xD80000
+
+#define SPI_SEND_BLOCK_SIZE 4080
+
+static int ipc_spi_send_modem_bin_xmit_img(struct ipc_spi *od, enum image_type type, unsigned int *address)
+{
+ int retval = 0;
+ struct image_buf img;
+ unsigned int data_size;
+ unsigned int send_size = 0;
+ unsigned int rest_size = 0;
+ unsigned char *ptr;
+ int i;
+
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img type : %d.\n", __LINE__, type);
+ switch (type) {
+ case MODEM_MAIN:
+ img.buf = (unsigned char *)(p_virtual_buff + MAIN_OFFSET_VM);
+ img.length = MAIN_LEN;
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save MAIN to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_NV:
+ img.buf = (unsigned char *)(p_virtual_buff + NV_OFFSET_VM);
+ img.length = NV_LEN;
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save NV to img.\n", __LINE__);
+
+ break;
+
+ default:
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img wrong : %d.", __LINE__, type);
+ return -1;
+ }
+
+ /* Command : ReqFlashSetAddress(0x0802) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0802, sizeof(unsigned int), address);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd Done.\n", __LINE__);
+
+ dev_dbg(od->dev, "(%d) Start send img. size : %d\n", __LINE__, img.length);
+ ptr = img.buf;
+ data_size = SPI_SEND_BLOCK_SIZE;
+ rest_size = img.length;
+
+ for (i = 0 ; send_size < img.length ; i++) {
+ if (rest_size < SPI_SEND_BLOCK_SIZE)
+ data_size = rest_size;
+
+ /* Command : ReqFlashWriteBlock(0x0804) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0804, data_size, ptr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+
+ send_size += data_size;
+ rest_size -= data_size;
+ ptr += data_size;
+
+ if (!(i % 100))
+ dev_dbg(od->dev, "(%d) [%d] 0x%x size done, rest size: 0x%x\n", __LINE__, i, send_size, rest_size);
+ }
+
+ return retval;
+}
+
+static void ipc_spi_send_modem_bin(struct work_struct *send_modem_w)
+{
+ int retval = 0;
+ u32 int_cmd = 0xABCDABCD;
+ u32 int_cmd_fail = 0xDCBADCBA;
+ struct ipc_spi_send_modem_bin_workq_data *smw
+ = container_of(send_modem_w, struct ipc_spi_send_modem_bin_workq_data, send_modem_w);
+ struct ipc_spi *od = smw->od;
+
+ unsigned int modem_addr = 0x60300000;
+ unsigned int nvm_static_fix_addr = 0x60e80000;
+ unsigned int nvm_static_cal_addr = 0x60f00000;
+ unsigned int nvm_dynamic_addr = 0x60f80000;
+ unsigned int nvm_addr = 0x60C00000;
+ unsigned short sec_end = 0x0000;
+ unsigned int force_hw_reset = 0x00111001;
+
+ u8 *sec_start = NULL;
+
+ dev_dbg(od->dev, "[SPI DUMP] mb : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ *(u8 *)(p_virtual_buff), *(u8 *)(p_virtual_buff + 1), *(u8 *)(p_virtual_buff + 2), *(u8 *)(p_virtual_buff + 3), *(u8 *)(p_virtual_buff + 4),
+ *(u8 *)(p_virtual_buff + 5), *(u8 *)(p_virtual_buff + 6), *(u8 *)(p_virtual_buff + 7), *(u8 *)(p_virtual_buff + 8), *(u8 *)(p_virtual_buff + 9),
+ *(u8 *)(p_virtual_buff + 10), *(u8 *)(p_virtual_buff + 11), *(u8 *)(p_virtual_buff + 12), *(u8 *)(p_virtual_buff + 13), *(u8 *)(p_virtual_buff + 14),
+ *(u8 *)(p_virtual_buff + 15), *(u8 *)(p_virtual_buff + 16), *(u8 *)(p_virtual_buff + 17), *(u8 *)(p_virtual_buff + 18), *(u8 *)(p_virtual_buff + 19));
+
+ /* Command : ReqSecStart(0x0204) */
+ sec_start = kmalloc(2048, GFP_ATOMIC);
+ if (!sec_start) {
+ dev_err(od->dev, "(%d) sec_start kmalloc fail.", __LINE__);
+ goto err;
+ }
+ memset(sec_start, 0, 2048);
+
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0204, 2048, (void *)sec_start);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd Done.\n", __LINE__);
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_MAIN, &modem_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_MAIN Done.\n", __LINE__);
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &nvm_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_NV:nvm_addr Done.\n", __LINE__);
+
+/*
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &nvm_static_cal_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_NV:nvm_static_cal_addr Done.\n", __LINE__);
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &nvm_dynamic_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_NV:nvm_dynamic_addr Done.\n", __LINE__);
+*/
+
+ /* Command : ReqSecEnd(0x0205) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0205, sizeof(unsigned short), &sec_end);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd; ReqSecEnd Done.\n", __LINE__);
+
+ /* Command : ReqForceHwReset(0x0208) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0208, sizeof(unsigned int), &force_hw_reset);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd; ReqForceHwReset Done.\n", __LINE__);
+
+ kfree(sec_start);
+
+ ipc_spi_set_MRDY_pin(0);
+
+ ipc_spi_make_data_interrupt(int_cmd, od);
+
+ return;
+
+err:
+ ipc_spi_make_data_interrupt(int_cmd_fail, od);
+}
+#endif
+
+static int __devinit ipc_spi_platform_probe(struct platform_device *pdev)
+{
+ int r;
+ int irq;
+ struct ipc_spi *od = NULL;
+ struct ipc_spi_platform_data *pdata;
+ struct resource *res;
+ struct task_struct *th;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+ pdata = pdev->dev.platform_data;
+ if (!pdata || !pdata->cfg_gpio) {
+ dev_err(&pdev->dev, "No platform data\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ gpio_mrdy = pdata->gpio_ipc_mrdy;
+ gpio_srdy = pdata->gpio_ipc_srdy;
+
+ dev_dbg(&pdev->dev, "(%d) gpio_mrdy : %d, gpio_srdy : %d(%d)\n", __LINE__, gpio_mrdy, gpio_srdy, gpio_get_value(gpio_srdy));
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "(%d) failed to get irq number\n", __LINE__);
+
+ r = -EINVAL;
+ goto err;
+ }
+ irq = res->start;
+
+ od = kzalloc(sizeof(struct ipc_spi), GFP_KERNEL);
+ if (!od) {
+ dev_err(&pdev->dev, "(%d) failed to allocate device\n", __LINE__);
+
+ r = -ENOMEM;
+ goto err;
+ }
+ ipc_spi = od;
+
+ dev_dbg(&pdev->dev, "(%d) IpcSpi dev: %p\n", __LINE__, od);
+
+ od->base = 0;
+ od->size = 0x1000000; /* 16M */
+ r = _request_mem(od, pdev);
+ if (r)
+ goto err;
+
+ /* init mailbox state before registering irq handler */
+ onedram_init_mailbox();
+
+ _init_data(od);
+
+ printk(KERN_ERR "cfg_gpio run %p\n", pdata);
+
+ pdata->cfg_gpio();
+
+#ifndef FEATURE_SAMSUNG_SPI
+ irq = gpio_to_irq(gpio_srdy);
+ r = request_irq(irq, ipc_spi_irq_handler, IRQF_TRIGGER_RISING, "IPC_SRDY", od);
+ if (r) {
+ dev_err(&pdev->dev, "(%d) Failed to allocate an interrupt: %d\n", __LINE__, irq);
+
+ goto err;
+ }
+ od->irq = irq;
+ enable_irq_wake(irq);
+#endif
+
+ /* Init work structure */
+ ipc_spi_send_modem_work_data = kmalloc(sizeof(struct ipc_spi_send_modem_bin_workq_data), GFP_ATOMIC);
+ if (!ipc_spi_send_modem_work_data) {
+ dev_err(&pdev->dev, "(%d) memory alloc fail\n", __LINE__);
+
+ r = -ENOMEM;
+ goto err;
+ }
+ INIT_WORK(&ipc_spi_send_modem_work_data->send_modem_w, ipc_spi_send_modem_bin);
+
+ r = _register_chrdev(od);
+ if (r) {
+ dev_err(&pdev->dev, "(%d) Failed to register chrdev\n", __LINE__);
+
+ goto err;
+ }
+
+ r = sysfs_create_group(&od->dev->kobj, &ipc_spi_group);
+ if (r) {
+ dev_err(&pdev->dev, "(%d) Failed to create sysfs files\n", __LINE__);
+
+ goto err;
+ }
+ od->group = &ipc_spi_group;
+
+ platform_set_drvdata(pdev, od);
+
+#ifdef FEATURE_SAMSUNG_SPI
+ spi_main_init(pdata);
+#endif
+
+ th = kthread_create(ipc_spi_thread, (void *)od, "ipc_spi_thread");
+ if (IS_ERR(th)) {
+ dev_err(&pdev->dev, "kernel_thread() failed : %d\n", r);
+
+ goto err;
+ }
+ wake_up_process(th);
+
+ dev_info(&pdev->dev, "(%d) platform probe Done.\n", __LINE__);
+
+ return 0;
+
+err:
+ _release(od);
+ return r;
+}
+
+static int __devexit ipc_spi_platform_remove(struct platform_device *pdev)
+{
+ struct ipc_spi *od = platform_get_drvdata(pdev);
+
+ /* TODO: need onedram_resource clean? */
+ _unregister_all_handlers();
+ platform_set_drvdata(pdev, NULL);
+ ipc_spi = NULL;
+ _release(od);
+
+ /* Free work queue data */
+ kfree(ipc_spi_send_modem_work_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ipc_spi_platform_suspend(struct platform_device *pdev, pm_message_t state)
+{
+/* struct onedram *od = platform_get_drvdata(pdev); */
+
+ return 0;
+}
+
+static int ipc_spi_platform_resume(struct platform_device *pdev)
+{
+/* struct onedram *od = platform_get_drvdata(pdev); */
+
+ return 0;
+}
+#else
+# define ipc_spi_platform_suspend NULL
+# define ipc_spi_platform_resume NULL
+#endif
+
+static int ipc_spi_probe(struct spi_device *spi)
+{
+ int retval = 0;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ p_ipc_spi = spi;
+ p_ipc_spi->mode = SPI_MODE_1;
+ p_ipc_spi->bits_per_word = 32;
+
+ retval = spi_setup(p_ipc_spi);
+ if (retval != 0) {
+ printk(KERN_ERR "[%s] spi_setup ERROR : %d\n", __func__, retval);
+
+ return retval;
+ }
+
+ dev_info(&p_ipc_spi->dev, "(%d) spi probe Done.\n", __LINE__);
+
+ return retval;
+}
+
+static int ipc_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct platform_driver ipc_spi_platform_driver = {
+ .probe = ipc_spi_platform_probe,
+ .remove = __devexit_p(ipc_spi_platform_remove),
+ .suspend = ipc_spi_platform_suspend,
+ .resume = ipc_spi_platform_resume,
+ .driver = {
+ .name = DRVNAME,
+ },
+};
+
+static struct spi_driver ipc_spi_driver = {
+ .probe = ipc_spi_probe,
+ .remove = __devexit_p(ipc_spi_remove),
+ .driver = {
+ .name = "ipc_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+};
+
+int ipc_spi_thread_restart()
+{
+ int retval;
+
+ send_modem_spi = 1;
+ is_cp_reset = 1;
+
+ printk(KERN_ERR "[IPC_SPI] ipc_spi_thread_restart\n");
+
+ spi_set_restart();
+
+ platform_driver_unregister(&ipc_spi_platform_driver);
+
+ retval = platform_driver_register(&ipc_spi_platform_driver);
+ if (retval < 0) {
+ printk(KERN_ERR "[%s] platform_driver_register ERROR : %d\n", __func__, retval);
+
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(ipc_spi_thread_restart);
+
+static int __init ipc_spi_init(void)
+{
+ int retval = 0;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ retval = spi_register_driver(&ipc_spi_driver);
+ if (retval < 0) {
+ printk(KERN_ERR "[%s] spi_register_driver ERROR : %d\n", __func__, retval);
+
+ goto exit;
+ }
+
+ retval = platform_driver_register(&ipc_spi_platform_driver);
+ if (retval < 0) {
+ printk(KERN_ERR "[%s] platform_driver_register ERROR : %d\n", __func__, retval);
+
+ goto exit;
+ }
+
+ /* creat work queue thread */
+ ipc_spi_wq = create_singlethread_workqueue("ipc_spi_wq");
+
+ if (!ipc_spi_wq) {
+ printk(KERN_ERR "[%s] get workqueue thread fail\n", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ printk(KERN_ERR "[%s](%d) init Done - 1011260100.\n", __func__, __LINE__);
+
+ return 0;
+
+exit:
+ return retval;
+}
+
+static void __exit ipc_spi_exit(void)
+{
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ spi_unregister_driver(&ipc_spi_driver);
+ platform_driver_unregister(&ipc_spi_platform_driver);
+
+ if (ipc_spi_wq)
+ destroy_workqueue(ipc_spi_wq);
+}
+
+module_init(ipc_spi_init);
+module_exit(ipc_spi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Wonhee Seo <wonhee48.seo@samsung.com>");
+MODULE_DESCRIPTION("IpcSpi driver");
diff --git a/drivers/phone_svn/ipc_spi/spi_app.c b/drivers/phone_svn/ipc_spi/spi_app.c
new file mode 100644
index 0000000..110d193
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_app.c
@@ -0,0 +1,183 @@
+/**************************************************************
+
+ spi_app.c
+
+
+
+ interface spi and app
+
+
+
+ This is MASTER side.
+
+***************************************************************/
+
+
+
+/**************************************************************
+
+ Preprocessor by common
+
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_app.h"
+#include "spi_os.h"
+#include "spi_data.h"
+#include "spi_test.h"
+
+static unsigned int _pack_spi_data(enum SPI_DATA_TYPE_T type, void *buf,
+ void *data, unsigned int length);
+
+
+/**********************************************************
+Prototype void spi_app_receive_msg ( struct spi_os_msg * msg )
+Type function
+Description receive data from spi task message queue and
+ Pack data for spi data.
+ Then inqueue the message to spi_data_queue_XXX_tx
+Param input msg : message received from other task
+Return value (none)
+***********************************************************/
+void spi_receive_msg_from_app(struct spi_os_msg *msg)
+{
+ enum SPI_MAIN_MSG_T type;
+ enum SPI_DATA_QUEUE_TYPE_T q_type;
+ enum SPI_DATA_TYPE_T mux_type;
+ unsigned int in_length = 0, out_length = 0;
+ void *in_buffer = 0;
+ void *out_buffer = 0;
+
+ type = msg->signal_code;
+ in_length = msg->data_length;
+ in_buffer = msg->data;
+
+ switch (type) {
+ case SPI_MAIN_MSG_IPC_SEND:
+ q_type = SPI_DATA_QUEUE_TYPE_IPC_TX;
+ mux_type = SPI_DATA_MUX_IPC;
+ break;
+
+ case SPI_MAIN_MSG_RAW_SEND:
+ q_type = SPI_DATA_QUEUE_TYPE_RAW_TX;
+ mux_type = SPI_DATA_MUX_RAW;
+ break;
+
+ case SPI_MAIN_MSG_RFS_SEND:
+ q_type = SPI_DATA_QUEUE_TYPE_RFS_TX;
+ mux_type = SPI_DATA_MUX_RFS;
+ break;
+
+ default:
+ SPI_OS_ASSERT(("[SPI] spi_app_receive_msg Unknown type"));
+ return;
+ }
+
+ out_buffer = spi_os_malloc(in_length+SPI_DATA_HEADER_SIZE);
+ out_length = _pack_spi_data(mux_type, out_buffer, in_buffer, in_length);
+
+ if (spi_data_inqueue(&spi_queue_info[q_type], out_buffer,
+ out_length) == 0) {
+ SPI_OS_ASSERT(("[SPI] spi_app_receive_msg inqueue[%d] Fail",
+ q_type));
+ }
+
+ spi_os_free(in_buffer);
+ spi_os_free(out_buffer);
+}
+
+
+/**********************************************************
+Prototype void spi_send_msg ( void )
+Type function
+Description Dequeue a spi data from spi_data_queue_XXX_rx
+ Unpack the spi data for ipc, raw or rfs data
+ Send msg to other task until that all queues are empty
+ CP use this functions for other task as below
+ IPC : ipc_cmd_send_queue
+ RAW : data_send_queue
+ RFS : rfs_send_queue
+Param input (none)
+Return value (none)
+***********************************************************/
+void spi_send_msg_to_app(void)
+{
+ u32 int_cmd = 0;
+ struct ipc_spi *od_spi = NULL;
+
+ #define MB_VALID 0x0080
+ #define MB_DATA(x) (MB_VALID | x)
+ #define MBD_SEND_FMT 0x0002
+ #define MBD_SEND_RAW 0x0001
+ #define MBD_SEND_RFS 0x0100
+
+
+ od_spi = ipc_spi;
+
+
+ if (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_IPC_RX) == 0) {
+ int_cmd = MB_DATA(MBD_SEND_FMT);
+ ipc_spi_make_data_interrupt(int_cmd, od_spi);
+ }
+
+ if (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RAW_RX) == 0) {
+ int_cmd = MB_DATA(MBD_SEND_RAW);
+ ipc_spi_make_data_interrupt(int_cmd, od_spi);
+ }
+
+ if (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RFS_RX) == 0) {
+ int_cmd = MB_DATA(MBD_SEND_RFS);
+ ipc_spi_make_data_interrupt(int_cmd, od_spi);
+ }
+}
+
+
+/**********************************************************
+Prototype unsigned int _pack_spi_data (SPI_DATA_TYPE_T type,void * buf, void * data, unsigned int length)
+Type static function
+Description pack data for spi
+Param input type : type of data type
+ buf : address of buffer to be saved
+ data : address of data to pack
+ length : length of input data
+Return value length of packed data
+***********************************************************/
+static unsigned int _pack_spi_data(enum SPI_DATA_TYPE_T type, void *buf,
+ void *data, unsigned int length)
+{
+ char *spi_packet = NULL;
+ unsigned int out_length = 0;
+
+ spi_packet = (char *) buf;
+
+ spi_os_memset((char *)spi_packet, 0x00, (unsigned int)length);
+ spi_os_memset((char *)spi_packet, (unsigned char)SPI_DATA_BOF,
+ SPI_DATA_BOF_SIZE);
+ spi_os_memcpy((char *)spi_packet + SPI_DATA_BOF_SIZE, data, length);
+ spi_os_memset((char *)spi_packet + SPI_DATA_BOF_SIZE + length,
+ (unsigned char)SPI_DATA_EOF, SPI_DATA_EOF_SIZE);
+
+ out_length = SPI_DATA_BOF_SIZE + length + SPI_DATA_EOF_SIZE;
+
+ return out_length;
+}
+
+
+/**********************************************************
+Prototype int spi_app_ready ( void )
+Type function
+Description check if spi initialization is done.
+ Decide it as spi_main_state.
+Param input (none)
+Return value 1 : spi initialization is done.
+ 0 : spi initialization is not done.
+***********************************************************/
+int spi_is_ready(void)
+{
+ if ((spi_main_state == SPI_MAIN_STATE_START) ||
+ (spi_main_state == SPI_MAIN_STATE_END))
+ return 0;
+
+ return 1;
+}
+
diff --git a/drivers/phone_svn/ipc_spi/spi_app.h b/drivers/phone_svn/ipc_spi/spi_app.h
new file mode 100644
index 0000000..70a9d69
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_app.h
@@ -0,0 +1,15 @@
+#ifndef _SPI_APP_H_
+#define _SPI_APP_H_
+
+#include "spi_main.h"
+#include "spi_data.h"
+#include "spi_os.h"
+
+extern void spi_receive_msg_from_app(struct spi_os_msg *msg);
+extern void spi_send_msg_to_app(void);
+extern int spi_is_ready(void);
+
+extern struct ipc_spi *ipc_spi;
+extern void ipc_spi_make_data_interrupt(u32 cmd, struct ipc_spi *od);
+
+#endif
diff --git a/drivers/phone_svn/ipc_spi/spi_data.c b/drivers/phone_svn/ipc_spi/spi_data.c
new file mode 100644
index 0000000..ecd62ab
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_data.c
@@ -0,0 +1,981 @@
+/**************************************************************
+
+ spi_data.c
+
+
+
+ handling spi data
+
+
+
+ This is MASTER side.
+
+***************************************************************/
+
+
+
+/**************************************************************
+
+ Preprocessor by common
+
+***************************************************************/
+
+#include "spi_data.h"
+#include "spi_os.h"
+#include "spi_dev.h"
+
+
+
+/**************************************************************
+
+ Definition of Variables and Functions by common
+
+***************************************************************/
+
+struct spi_data_queue *spi_queue;
+struct spi_data_queue_info *spi_queue_info;
+struct spi_data_div_buf *spi_div_buf;
+
+char *gspi_data_prepare_packet;
+
+char *gspi_data_packet_buf;
+char *gspi_data_sync_buf;
+
+static int _prepare_tx_type_packet(void *buf,
+ struct spi_data_queue_info *queue_info,
+ struct spi_data_div_buf *spi_data_buf,
+ enum SPI_DATA_TYPE_T spi_type);
+static int _spi_data_verify(void *buf, unsigned int mux);
+
+
+/**********************************************************
+
+Prototype void spi_data_queue_init ( void )
+
+Type function
+
+Description init buffer and data variable
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+void spi_data_queue_init(void)
+{
+ int i = 0;
+
+ /* This is defined at ipc_spi.c file and copied. */
+ #define FMT_OUT 0x0FE000
+ #define FMT_IN 0x10E000
+ #define FMT_SZ 0x10000 /* 65536 bytes */
+
+ #define RAW_OUT 0x11E000
+ #define RAW_IN 0x21E000
+ #define RAW_SZ 0x100000 /* 1 MB */
+
+ #define RFS_OUT 0x31E000
+ #define RFS_IN 0x41E000
+ #define RFS_SZ 0x100000 /* 1 MB */
+
+ void *p_virtual_buff;
+ unsigned int buffer_offset[SPI_DATA_QUEUE_TYPE_NB] = {
+ FMT_OUT, FMT_IN, RAW_OUT, RAW_IN, RFS_OUT, RFS_IN};
+
+ p_virtual_buff = ipc_spi_get_queue_buff();
+ spi_queue = p_virtual_buff+sizeof(struct spi_data_queue)*2;
+
+
+ spi_queue_info = (struct spi_data_queue_info *) spi_os_vmalloc(
+ sizeof(struct spi_data_queue_info)*SPI_DATA_QUEUE_TYPE_NB);
+ spi_os_memset(spi_queue_info, 0x00,
+ sizeof(struct spi_data_queue_info)*SPI_DATA_QUEUE_TYPE_NB);
+
+ spi_div_buf = (struct spi_data_div_buf *) spi_os_vmalloc(
+ sizeof(struct spi_data_div_buf)*SPI_DATA_QUEUE_TYPE_NB);
+ spi_os_memset(spi_div_buf, 0x00, sizeof(struct spi_data_div_buf)
+ *SPI_DATA_QUEUE_TYPE_NB);
+ gspi_data_prepare_packet = (char *) spi_os_vmalloc(
+ SPI_DEV_MAX_PACKET_SIZE);
+ gspi_data_packet_buf = (char *) spi_os_malloc(SPI_DEV_MAX_PACKET_SIZE);
+ gspi_data_sync_buf = (char *) spi_os_malloc(SPI_DEV_MAX_PACKET_SIZE);
+
+ for (i = 0 ; i < SPI_DATA_QUEUE_TYPE_NB ; i++) {
+ spi_queue_info[i].header = &spi_queue[i];
+
+ switch (i) {
+ case SPI_DATA_QUEUE_TYPE_IPC_TX:
+ case SPI_DATA_QUEUE_TYPE_IPC_RX:
+ spi_queue_info[i].buf_size = SPI_DATA_IPC_QUEUE_SIZE;
+ spi_queue_info[i].type = SPI_DATA_MUX_IPC;
+ spi_div_buf[i].buffer = (char *)spi_os_vmalloc(
+ SPI_DATA_IPC_DIV_BUFFER_SIZE);
+ break;
+ case SPI_DATA_QUEUE_TYPE_RAW_TX:
+ case SPI_DATA_QUEUE_TYPE_RAW_RX:
+ spi_queue_info[i].buf_size = SPI_DATA_RAW_QUEUE_SIZE;
+ spi_queue_info[i].type = SPI_DATA_MUX_RAW;
+ spi_div_buf[i].buffer = (char *)spi_os_vmalloc(
+ SPI_DATA_RAW_DIV_BUFFER_SIZE);
+ break;
+ case SPI_DATA_QUEUE_TYPE_RFS_TX:
+ case SPI_DATA_QUEUE_TYPE_RFS_RX:
+ spi_queue_info[i].buf_size = SPI_DATA_RFS_QUEUE_SIZE;
+ spi_queue_info[i].type = SPI_DATA_MUX_RFS;
+ spi_div_buf[i].buffer = (char *)spi_os_vmalloc(
+ SPI_DATA_RFS_DIV_BUFFER_SIZE);
+ break;
+ }
+
+ if (spi_queue_info[i].buffer == 0)
+ spi_queue_info[i].buffer =
+ (char *)(p_virtual_buff + buffer_offset[i]);
+ }
+}
+
+
+/**********************************************************
+
+Prototype void spi_data_queue_destroy ( void )
+
+Type function
+
+Description memfree buffer and data variable
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+
+void spi_data_queue_destroy(void)
+{
+ int i = 0;
+
+ if (spi_div_buf != NULL) {
+ for (i = 0 ; i < SPI_DATA_QUEUE_TYPE_NB ; i++) {
+ if (spi_div_buf[i].buffer != NULL) {
+ spi_os_vfree(spi_div_buf[i].buffer);
+ spi_div_buf[i].buffer = NULL;
+ }
+ }
+ }
+
+ if (gspi_data_prepare_packet != NULL) {
+ spi_os_vfree(gspi_data_prepare_packet);
+ gspi_data_prepare_packet = NULL;
+ }
+
+ if (gspi_data_packet_buf != NULL) {
+ spi_os_free(gspi_data_packet_buf);
+ gspi_data_packet_buf = NULL;
+ }
+
+ if (gspi_data_sync_buf != NULL) {
+ spi_os_free(gspi_data_sync_buf);
+ gspi_data_sync_buf = NULL;
+ }
+
+ if (spi_div_buf != NULL) {
+ spi_os_vfree(spi_div_buf);
+ spi_div_buf = NULL;
+ }
+
+ if (spi_queue_info != NULL) {
+ spi_os_vfree(spi_queue_info);
+ spi_queue_info = NULL;
+ }
+}
+
+
+
+/**********************************************************
+
+Prototype int spi_data_inqueue (struct spi_data_queue_info * queue_info,
+ void * data, unsigned int length )
+
+Type function
+
+Description inqueue data to spi rx or tx buffer
+
+Param input queue_info : queue for inqueue
+
+ data : address of data
+
+ lenth : length of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+int spi_data_inqueue(struct spi_data_queue_info *queue_info,
+ void *data, unsigned int length)
+{
+ char *pdata = NULL;
+ struct spi_data_queue *queue = NULL;
+ pdata = data;
+ queue = queue_info->header;
+
+ if (queue->tail < queue->head) {
+ if ((queue->head - queue->tail) < length) {
+ SPI_OS_ASSERT(("%s%s[%u],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_inqueue : ",
+ "queue is overflow head", queue->head,
+ "tail", queue->tail, "length", length,
+ "buf_size", queue_info->buf_size));
+ return 0;
+ }
+ } else {
+ if ((queue_info->buf_size - (queue->tail - queue->head))
+ < length) {
+ SPI_OS_ASSERT(("%s%s[%u],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_inqueue : queue is overflow ",
+ "head", queue->head, "tail", queue->tail,
+ "request length", length,
+ "buf_size", queue_info->buf_size));
+ return 0;
+ }
+ }
+
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_RX] == queue_info) {
+ pdata += (SPI_DATA_MUX_SIZE+SPI_DATA_LENGTH_SIZE);
+ length -= (SPI_DATA_MUX_SIZE+SPI_DATA_LENGTH_SIZE);
+ }
+
+ if (queue_info->buf_size < (queue->tail + length)) {
+ /* maximum < tail + length */
+ unsigned int pre_data_len = 0;
+ pre_data_len = queue_info->buf_size - queue->tail;
+ spi_os_memcpy(queue_info->buffer + queue->tail,
+ pdata, pre_data_len);
+ spi_os_memcpy(queue_info->buffer, pdata + pre_data_len,
+ length - pre_data_len);
+ queue->tail = ((queue->tail+length)%queue_info->buf_size);
+ } else if (queue_info->buf_size == (queue->tail + length)) {
+ /* maximum == tail + length */
+ spi_os_memcpy((queue_info->buffer + queue->tail),
+ (char *)pdata, length);
+ queue->tail = 0;
+ } else {
+ /* maximum > tail + length */
+ spi_os_memcpy((queue_info->buffer + queue->tail),
+ (char *)pdata, length);
+ queue->tail = queue->tail + length;
+ }
+
+ return 1;
+}
+
+
+/**********************************************************
+
+Prototype unsigned int spi_data_dequeue
+ (struct spi_data_queue_info * queue_info, void * pdata)
+
+Type function
+
+Description dequeue data to spi
+
+Param input queue_info : queue for dequeue
+
+ pdata : address of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+unsigned int spi_data_dequeue(struct spi_data_queue_info *queue_info,
+ void *pdata)
+{
+ unsigned int length = 0, buf_length = 0, pre_data_len = 0;
+ struct spi_data_queue *queue = NULL;
+
+ queue = queue_info->header;
+
+ if (queue->tail == queue->head) { /* empty */
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : spi_data_dequeue:",
+ "queue is empty"));
+ return 0;
+ }
+
+ if (queue->head == queue_info->buf_size)
+ queue->head = 0;
+
+ /* check length of data */
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info) {
+ /* IPC Case */
+ if (queue_info->buf_size == (queue->head + SPI_DATA_BOF_SIZE)) {
+ /* maximum == head + pos_len */
+ spi_os_memcpy(&length, queue_info->buffer,
+ SPI_DATA_IPC_INNER_LENGTH_SIZE);
+ } else if (queue_info->buf_size < (queue->head +
+ SPI_DATA_BOF_SIZE +
+ SPI_DATA_IPC_INNER_LENGTH_SIZE)) {
+ /* maximum < head + pos_len */
+ char data_header[SPI_DATA_IPC_INNER_LENGTH_SIZE] = {0,};
+ pre_data_len = queue_info->buf_size - queue->head -
+ SPI_DATA_BOF_SIZE;
+
+ spi_os_memcpy(data_header, (queue_info->buffer +
+ queue->head + SPI_DATA_BOF_SIZE), pre_data_len);
+ spi_os_memcpy(data_header + pre_data_len,
+ queue_info->buffer,
+ SPI_DATA_IPC_INNER_LENGTH_SIZE - pre_data_len);
+ spi_os_memcpy(&length, data_header,
+ SPI_DATA_IPC_INNER_LENGTH_SIZE);
+ } else { /* maximum > head + pos_len */
+ spi_os_memcpy(&length,
+ (queue_info->buffer + queue->head +
+ SPI_DATA_BOF_SIZE),
+ SPI_DATA_IPC_INNER_LENGTH_SIZE);
+ }
+ } else { /* RAW, RFS Case */
+ if (queue_info->buf_size == (queue->head + SPI_DATA_BOF_SIZE)) {
+ /* maximum == head + pos_len */
+ spi_os_memcpy(&length, queue_info->buffer,
+ SPI_DATA_INNER_LENGTH_SIZE);
+ } else if (queue_info->buf_size < (queue->head +
+ SPI_DATA_BOF_SIZE + SPI_DATA_INNER_LENGTH_SIZE)) {
+ /* maximum < head + pos_len */
+ char data_header[SPI_DATA_INNER_LENGTH_SIZE] = {0,};
+ pre_data_len = queue_info->buf_size -
+ queue->head - SPI_DATA_BOF_SIZE;
+
+ spi_os_memcpy(data_header,
+ (queue_info->buffer + queue->head +
+ SPI_DATA_BOF_SIZE),
+ pre_data_len);
+ spi_os_memcpy(data_header + pre_data_len,
+ queue_info->buffer,
+ SPI_DATA_INNER_LENGTH_SIZE - pre_data_len);
+ spi_os_memcpy(&length, data_header,
+ SPI_DATA_INNER_LENGTH_SIZE);
+ } else { /* maximum > head + pos_len */
+ spi_os_memcpy(&length,
+ (queue_info->buffer + queue->head +
+ SPI_DATA_BOF_SIZE),
+ SPI_DATA_INNER_LENGTH_SIZE);
+ }
+ }
+ length += SPI_DATA_BOF_SIZE + SPI_DATA_EOF_SIZE;
+ buf_length = length + SPI_DATA_MUX_SIZE + SPI_DATA_LENGTH_SIZE;
+
+ if (length > SPI_DEV_MAX_PACKET_SIZE) {
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info ||
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info) {
+ /* IPC Case */
+ SPI_OS_ERROR(("%s %s[%x],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue: IPC error",
+ "length", length, "buf_size",
+ queue_info->buf_size, "head",
+ queue->head, "tail", queue->tail));
+ } else if (
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX] == queue_info) {
+ /* RAW Case */
+ SPI_OS_ERROR(("%s %s[%x],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue: RAW error",
+ "length", length,
+ "buf_size", queue_info->buf_size,
+ "head", queue->head, "tail", queue->tail));
+ } else { /* RFS Case */
+ SPI_OS_ERROR(("%s %s[%x],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue: RFS error",
+ "length", length,
+ "buf_size", queue_info->buf_size,
+ "head", queue->head, "tail", queue->tail));
+ }
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->head - 1, 16);
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->tail - 1, 16);
+ return 0;
+ }
+
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_TX] == queue_info) {
+ unsigned int templength;
+
+ spi_os_memcpy((char *) pdata, &queue_info->type,
+ SPI_DATA_MUX_SIZE);
+ pdata += SPI_DATA_MUX_SIZE;
+ templength = length-SPI_DATA_BOF_SIZE-SPI_DATA_EOF_SIZE;
+ spi_os_memcpy((char *) pdata, &templength,
+ SPI_DATA_LENGTH_SIZE);
+ pdata += SPI_DATA_LENGTH_SIZE;
+ }
+
+ if (queue->tail > queue->head) {
+ if (queue->tail - queue->head < length) {
+ SPI_OS_ERROR(("%s %s tail[%u], head[%u], length[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue:",
+ "request data length is less than queue`s remain data.",
+ queue->tail, queue->head, length));
+
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->head - 1, 16);
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->tail - 1, 16);
+ return 0;
+ }
+ } else if (queue->tail < queue->head) {
+ if ((queue_info->buf_size - queue->head + queue->tail)
+ < length) {
+ SPI_OS_ERROR(("%s %s tail[%u], head[%u], length[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue:",
+ "request data length is less than queue`s remain data.",
+ queue->tail, queue->head, length));
+
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->head - 1, 16);
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->tail - 1, 16);
+ return 0;
+ }
+ }
+
+ if (queue_info->buf_size < (queue->head+length)) {
+ /* maximum < head + length */
+ pre_data_len = queue_info->buf_size - queue->head;
+ spi_os_memcpy((char *)pdata,
+ queue_info->buffer + queue->head, pre_data_len);
+ spi_os_memcpy((char *)pdata + pre_data_len,
+ queue_info->buffer, length - pre_data_len);
+ queue->head = length - pre_data_len;
+ } else if (queue_info->buf_size == (queue->head+length)) {
+ /* maximum = head + length */
+ spi_os_memcpy((char *)pdata,
+ (queue_info->buffer + queue->head), length);
+ queue->head = 0;
+ } else { /* maximum > head + length */
+ spi_os_memcpy((char *)pdata,
+ (queue_info->buffer + queue->head), length);
+ queue->head = queue->head + length;
+ }
+
+ return buf_length;
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_queue_is_empty
+
+Type function
+
+Description check queue space empty or not
+
+Param input type : queue type
+
+Return value 0 : not empty
+
+ 1 : empty
+
+***********************************************************/
+
+int spi_data_queue_is_empty(enum SPI_DATA_QUEUE_TYPE_T type)
+{
+ if (spi_queue[type].head == spi_queue[type].tail)
+ return 1; /* empty */
+ else
+ return 0; /* not empty */
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_div_buf_is_empty
+
+Type function
+
+Description check queue space empty or not
+
+Param input type : queue type
+
+Return value 0 : not empty
+
+ 1 : empty
+
+***********************************************************/
+
+int spi_data_div_buf_is_empty(enum SPI_DATA_QUEUE_TYPE_T type)
+{
+ if (spi_div_buf[type].length > 0)
+ return 0; /* not empty */
+ else
+ return 1; /* Empty */
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_check_tx_queue( void )
+
+Type function
+
+Description check tx queue space empty or not
+
+Param input (none)
+
+Return value 0 : empty
+
+ 1 : data exist
+
+***********************************************************/
+
+int spi_data_check_tx_queue(void)
+{
+ if ((spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_IPC_TX) == 0)
+ || (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RAW_TX) == 0)
+ || (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RFS_TX) == 0))
+ return 1; /* has data */
+ else if ((spi_data_div_buf_is_empty(SPI_DATA_QUEUE_TYPE_IPC_TX) == 0)
+ || (spi_data_div_buf_is_empty(SPI_DATA_QUEUE_TYPE_RAW_TX) == 0)
+ || (spi_data_div_buf_is_empty(SPI_DATA_QUEUE_TYPE_RFS_TX) == 0))
+ return 1; /* has data */
+ else
+ return 0; /* empty */
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_prepare_tx_packet ( void * buf )
+
+Type function
+
+Description prepare packet for sync. attach spi_data_protocol_header,
+ mux, bof, data and eof
+
+Param input buf : address of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+int spi_data_prepare_tx_packet(void *buf)
+{
+ struct spi_data_queue *queue = NULL;
+ int flag_to_send = 0;
+
+ /* process IPC data */
+ queue = &spi_queue[SPI_DATA_QUEUE_TYPE_IPC_TX];
+ if ((queue->head != queue->tail)
+ || (spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_TX].length > 0)) {
+ if (_prepare_tx_type_packet(buf,
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX],
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_TX],
+ SPI_DATA_MUX_IPC) == 0)
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+
+ flag_to_send++;
+ }
+
+ /* process RAW data */
+ queue = &spi_queue[SPI_DATA_QUEUE_TYPE_RAW_TX];
+ if ((queue->head != queue->tail)
+ || (spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_TX].length > 0)) {
+ if (_prepare_tx_type_packet(buf,
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX],
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_TX],
+ SPI_DATA_MUX_RAW) == 0)
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+
+ flag_to_send++;
+ }
+
+ /* process RFS data */
+ queue = &spi_queue[SPI_DATA_QUEUE_TYPE_RFS_TX];
+ if ((queue->head != queue->tail)
+ || (spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_TX].length > 0)) {
+ if (_prepare_tx_type_packet(buf,
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_TX],
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_TX],
+ SPI_DATA_MUX_RFS) == 0)
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+
+ flag_to_send++;
+ }
+
+ if (flag_to_send == 0)
+ return 0;
+ else
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+}
+
+
+/**********************************************************
+
+Prototype static int _prepare_tx_type_packet
+
+Type static function
+
+Description prepare spi data for copy to spi packet from rx queue.
+ If spi data bigger than spi packet free size,
+ it need separate and inqueue extra data
+
+Param input buf : address of buffer to be saved
+ queue_info : tx queue for IPC or RAW or RFS
+ spi_data_buf : tx buffer for IPC or RAW or RFS
+
+Return value 0 : buffer full
+
+ (other) : packet size include header and tail
+
+***********************************************************/
+
+static int _prepare_tx_type_packet(void *buf,
+ struct spi_data_queue_info *queue_info,
+ struct spi_data_div_buf *spi_data_buf,
+ enum SPI_DATA_TYPE_T spi_type)
+{
+ char *spi_packet = NULL;
+
+ struct spi_data_packet_header *spi_packet_header = NULL;
+ unsigned int spi_packet_free_length = 0;
+
+ unsigned int cur_dequeue_length = 0;
+ unsigned int spi_packet_count = 0;
+ unsigned int spi_data_mux = 0;
+
+ struct spi_data_queue *queue = NULL;
+
+ queue = queue_info->header;
+
+ spi_packet = (char *)buf;
+ spi_packet_header = (struct spi_data_packet_header *)buf;
+ spi_packet_free_length = SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE -
+ spi_packet_header->current_data_size;
+
+ /* not enough space in spi packet */
+ /* spi_packet_header->current_data_size > 2022(2048 - 16) */
+ if (spi_packet_header->current_data_size >
+ SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE - SPI_DATA_MIN_SIZE) {
+ if (spi_data_check_tx_queue() == 1)
+ spi_packet_header->more = 1;
+ return 0;
+ }
+
+ while ((queue->head != queue->tail) || (spi_data_buf->length > 0)) {
+ spi_os_memset(gspi_data_prepare_packet,
+ 0, SPI_DEV_MAX_PACKET_SIZE);
+ cur_dequeue_length = 0;
+
+ /* dequeue SPI data */
+ if (spi_data_buf->length > 0) {
+ if ((*(unsigned int *)spi_data_buf->buffer)
+ == SPI_DATA_FF_PADDING_HEADER) {
+ /* if data has 0xFF padding header */
+ /* send packet directly */
+ spi_os_memcpy(spi_packet, spi_data_buf->buffer,
+ spi_data_buf->length);
+ spi_data_buf->length = 0;
+ return 0;
+ } else {
+ /* read from tx div buf */
+ spi_os_memcpy(gspi_data_prepare_packet,
+ spi_data_buf->buffer,
+ spi_data_buf->length);
+ cur_dequeue_length = spi_data_buf->length;
+ spi_data_buf->length = 0;
+ }
+ } else {
+ /* read from tx queue */
+ cur_dequeue_length = spi_data_dequeue(queue_info,
+ gspi_data_prepare_packet);
+ }
+
+ if (cur_dequeue_length == 0)
+ continue;
+
+ if (spi_packet_free_length < cur_dequeue_length) {
+ spi_os_memcpy(spi_data_buf->buffer,
+ gspi_data_prepare_packet, cur_dequeue_length);
+ spi_data_buf->length = cur_dequeue_length;
+ spi_packet_header->more = 1;
+ return 0;
+ }
+
+ /* check mux value */
+ spi_os_memcpy(&spi_data_mux, gspi_data_prepare_packet,
+ SPI_DATA_MUX_SIZE);
+ if (spi_data_mux == 0)
+ spi_os_memcpy(gspi_data_prepare_packet,
+ &spi_type, SPI_DATA_MUX_SIZE);
+
+ spi_os_memcpy(spi_packet + SPI_DATA_PACKET_HEADER_SIZE +
+ spi_packet_header->current_data_size,
+ gspi_data_prepare_packet, cur_dequeue_length);
+
+ /* update header */
+ spi_packet_header->current_data_size += cur_dequeue_length;
+ spi_packet_free_length -= cur_dequeue_length;
+
+ /* increase spi packet count */
+ spi_packet_count++;
+
+ /* check spi packet size */
+ if (spi_packet_free_length < SPI_DATA_MIN_SIZE) {
+ if (spi_data_check_tx_queue() == 1)
+ spi_packet_header->more = 1;
+ return 0;
+ }
+
+ /* check spi maximum count per packet */
+ if (spi_packet_count >= SPI_DATA_MAX_COUNT_PER_PACKET) {
+
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : spi _prepare_tx_type_packet :",
+ "spi_packet_count is full"));
+
+ return 0;
+ }
+ }
+
+ return spi_packet_header->current_data_size +
+ SPI_DATA_PACKET_HEADER_SIZE;
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_parsing_rx_packet
+ ( void * buf, unsigned int length )
+
+Type function
+
+Description parsing rx packet for transfer to application. It extract data
+
+ and inqueue each SPI_DATA_TYPE queue
+
+Param input buf : address of buffer to be saved
+
+ lenth : length of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+int spi_data_parsing_rx_packet(void *buf, unsigned int length)
+{
+ struct spi_data_packet_header *spi_packet_header = NULL;
+ char *spi_packet = NULL;
+ unsigned int spi_packet_length = 0;
+ unsigned int spi_packet_cur_pos = SPI_DATA_PACKET_HEADER_SIZE;
+
+ unsigned int spi_data_mux = 0;
+ unsigned int spi_data_length = 0;
+ char *spi_cur_data = NULL;
+
+ struct spi_data_queue_info *queue_info = NULL;
+ struct spi_data_div_buf *tx_div_buf = NULL;
+
+
+ /* check spi packet header */
+ if (*(unsigned int *)buf == 0x00000000
+ || *(unsigned int *)buf == 0xFFFFFFFF) {
+ /* if spi header is invalid, */
+ /* read spi header again with next 4 byte */
+ buf += SPI_DATA_PACKET_HEADER_SIZE;
+ }
+
+ spi_packet = (char *) buf;
+
+ /* read spi packet header */
+ spi_packet_header = (struct spi_data_packet_header *) buf;
+ spi_packet_length = SPI_DATA_PACKET_HEADER_SIZE +
+ spi_packet_header->current_data_size;
+
+
+ do {
+ /* read spi data mux and set current queue */
+ spi_os_memcpy(&spi_data_mux,
+ spi_packet + spi_packet_cur_pos, SPI_DATA_MUX_SIZE);
+
+ switch (spi_data_mux & SPI_DATA_MUX_NORMAL_MASK) {
+ case SPI_DATA_MUX_IPC:
+ queue_info =
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX];
+ tx_div_buf =
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_RX];
+ break;
+
+ case SPI_DATA_MUX_RAW:
+ queue_info =
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX];
+ tx_div_buf =
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_RX];
+ break;
+
+ case SPI_DATA_MUX_RFS:
+ queue_info =
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_RX];
+ tx_div_buf =
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_RX];
+ break;
+
+ default:
+ SPI_OS_ERROR(("%s len[%u], pos[%u]\n",
+ "[SPI] ERROR : spi_data_parsing_rx_packet : MUX error",
+ spi_packet_length, spi_packet_cur_pos));
+
+ spi_os_trace_dump_low("mux error",
+ spi_packet + spi_packet_cur_pos, 16);
+ return spi_packet_cur_pos - SPI_DATA_PACKET_HEADER_SIZE;
+ }
+
+ /* read spi data length */
+ spi_os_memcpy(&spi_data_length, spi_packet +
+ spi_packet_cur_pos + SPI_DATA_LENGTH_OFFSET,
+ SPI_DATA_LENGTH_SIZE);
+
+ if (spi_data_mux & SPI_DATA_MUX_MORE_H
+ || spi_data_mux & SPI_DATA_MUX_MORE_M)
+ spi_data_length += SPI_DATA_HEADER_SIZE_FRONT;
+ else if (spi_data_mux & SPI_DATA_MUX_MORE_T)
+ spi_data_length += SPI_DATA_HEADER_SIZE;
+ else
+ spi_data_length += SPI_DATA_HEADER_SIZE;
+
+ /* read data and make spi data */
+ spi_cur_data = spi_packet + spi_packet_cur_pos;
+
+ /* verify spi data */
+ if (_spi_data_verify(spi_cur_data, spi_data_mux) == 0) {
+ spi_packet_cur_pos += spi_data_length;
+ continue;
+ }
+
+ /* inqueue rx buffer */
+ if (spi_data_mux & SPI_DATA_MUX_MORE_H
+ || spi_data_mux & SPI_DATA_MUX_MORE_M) {
+ /* middle of divided packet. save to rx_div_buf */
+ spi_os_memcpy((void *)(tx_div_buf->buffer +
+ tx_div_buf->length),
+ spi_cur_data, spi_data_length);
+ tx_div_buf->length +=
+ (spi_data_length - SPI_DATA_HEADER_SIZE_FRONT);
+ } else if (spi_data_mux & SPI_DATA_MUX_MORE_T) {
+ unsigned int spi_origine_len = 0;
+
+ /* tail of divided packet. save to rx_div_buf */
+ spi_os_memcpy((void *)(tx_div_buf->buffer +
+ tx_div_buf->length),
+ spi_cur_data, spi_data_length);
+ tx_div_buf->length += spi_data_length;
+ /* update spi data length at spi header */
+ spi_origine_len =
+ tx_div_buf->length - SPI_DATA_HEADER_SIZE;
+ spi_os_memcpy(tx_div_buf->buffer +
+ SPI_DATA_LENGTH_OFFSET,
+ &(spi_origine_len), SPI_DATA_LENGTH_SIZE);
+
+ /* inqueue from rx_div_buf */
+ spi_data_inqueue(queue_info,
+ tx_div_buf->buffer, tx_div_buf->length);
+
+ spi_os_memset(tx_div_buf->buffer,
+ 0, SPI_DATA_DIVIDE_BUFFER_SIZE);
+ tx_div_buf->length = 0;
+ } else {
+ /* normal packet */
+ spi_data_inqueue(queue_info,
+ spi_cur_data, spi_data_length);
+ }
+
+ /* move spi packet current posision */
+ spi_packet_cur_pos += spi_data_length;
+ } while ((spi_packet_length - 1) > spi_packet_cur_pos);
+
+ return 1;
+}
+
+
+/**********************************************************
+
+Prototype int _spi_data_verify( void * buf, unsigned int mux )
+
+Type function
+
+Description verify integrity of packet
+
+Param input buf : address of packet data received
+
+ mux : data selection
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+int _spi_data_verify(void *buf, unsigned int mux)
+{
+ unsigned int length = 0;
+
+ unsigned int max_data_len = SPI_DATA_MAX_SIZE_PER_PACKET;
+ char bof = 0x00;
+ char eof = 0x00;
+
+ spi_os_memcpy(&length, (char *)buf+SPI_DATA_LENGTH_OFFSET,
+ SPI_DATA_LENGTH_SIZE);
+ spi_os_memcpy(&bof, (char *)buf+SPI_DATA_BOF_OFFSET, SPI_DATA_BOF_SIZE);
+
+ if (mux & SPI_DATA_MUX_MORE_H || mux & SPI_DATA_MUX_MORE_M)
+ max_data_len += SPI_DATA_EOF_SIZE;
+
+ if (bof == SPI_DATA_BOF) {
+ if (length <= max_data_len) {
+ if (mux & SPI_DATA_MUX_MORE_H
+ || mux & SPI_DATA_MUX_MORE_M)
+ return 1;
+ else {
+ spi_os_memcpy(&eof,
+ (char *)buf+SPI_DATA_EOF_OFFSET(length),
+ SPI_DATA_EOF_SIZE);
+
+ if (eof != SPI_DATA_EOF) {
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : _spi_data_verify:",
+ "invalid"));
+
+ return 0;
+ }
+ }
+ } else {
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : _spi_data_verify:",
+ "invalid : length error"));
+
+ return 0;
+ }
+ } else {
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : _spi_data_verify:",
+ "invalid : bof error"));
+
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_data.h b/drivers/phone_svn/ipc_spi/spi_data.h
new file mode 100644
index 0000000..ceb23c8
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_data.h
@@ -0,0 +1,129 @@
+#ifndef _SPI_DATA_H_
+#define _SPI_DATA_H_
+
+#include "spi_dev.h"
+
+#define SPI_TASK_EVENT_COUNT 64
+#define SPI_DATA_BOF 0x7F
+#define SPI_DATA_EOF 0x7E
+#define SPI_DATA_FF_PADDING_HEADER 0xFFFFFFFF
+
+#define SPI_DATA_MUX_NORMAL_MASK 0x0F
+#define SPI_DATA_MUX_MORE_H 0x10
+#define SPI_DATA_MUX_MORE_M 0x20
+#define SPI_DATA_MUX_MORE_T 0x30
+
+#define SPI_DATA_MUX_SIZE 2
+#define SPI_DATA_LENGTH_SIZE 4
+#define SPI_DATA_BOF_SIZE 1
+#define SPI_DATA_INNER_LENGTH_SIZE 4
+#define SPI_DATA_IPC_INNER_LENGTH_SIZE 2
+#define SPI_DATA_IPC_INNER_CONTROL_SIZE 1
+#define SPI_DATA_EOF_SIZE 1
+#define SPI_DATA_HEADER_SIZE (SPI_DATA_MUX_SIZE+ \
+ SPI_DATA_LENGTH_SIZE+SPI_DATA_BOF_SIZE+SPI_DATA_EOF_SIZE)
+#define SPI_DATA_HEADER_SIZE_FRONT (SPI_DATA_MUX_SIZE+ \
+ SPI_DATA_LENGTH_SIZE+SPI_DATA_BOF_SIZE)
+#define SPI_DATA_IPC_INNER_HEADER_SIZE \
+ (SPI_DATA_IPC_INNER_LENGTH_SIZE+ \
+ SPI_DATA_IPC_INNER_CONTROL_SIZE)
+#define SPI_DATA_SIZE(X) (SPI_DATA_HEADER_SIZE+X)
+
+#define SPI_DATA_LENGTH_OFFSET SPI_DATA_MUX_SIZE
+#define SPI_DATA_BOF_OFFSET (SPI_DATA_LENGTH_OFFSET+ \
+ SPI_DATA_LENGTH_SIZE)
+#define SPI_DATA_DATA_OFFSET (SPI_DATA_BOF_OFFSET+ \
+ SPI_DATA_BOF_SIZE)
+#define SPI_DATA_EOF_OFFSET(X) (SPI_DATA_DATA_OFFSET+X)
+
+#define SPI_DATA_PACKET_HEADER_SIZE 4
+#define SPI_DATA_PACKET_MUX_ERROR_SPARE_SIZE 4
+#define SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE \
+ (SPI_DEV_MAX_PACKET_SIZE-SPI_DATA_PACKET_HEADER_SIZE- \
+ SPI_DATA_PACKET_MUX_ERROR_SPARE_SIZE)
+
+#define SPI_DATA_MIN_SIZE (SPI_DATA_HEADER_SIZE*2)
+#define SPI_DATA_MAX_SIZE_PER_PACKET (SPI_DEV_MAX_PACKET_SIZE- \
+ SPI_DATA_PACKET_HEADER_SIZE-SPI_DATA_HEADER_SIZE- \
+ SPI_DATA_PACKET_MUX_ERROR_SPARE_SIZE)
+#define SPI_DATA_MAX_COUNT_PER_PACKET 240
+
+#define SPI_DATA_IPC_QUEUE_SIZE 0x10000
+#define SPI_DATA_RAW_QUEUE_SIZE 0x100000
+#define SPI_DATA_RFS_QUEUE_SIZE 0x100000
+
+#define SPI_DATA_IPC_DIV_BUFFER_SIZE 0x1000
+#define SPI_DATA_RAW_DIV_BUFFER_SIZE 0x1000
+#define SPI_DATA_RFS_DIV_BUFFER_SIZE 0x1000
+
+#define SPI_DATA_DIVIDE_BUFFER_SIZE SPI_DEV_MAX_PACKET_SIZE
+
+
+
+enum SPI_DATA_TYPE_T {
+ SPI_DATA_MUX_IPC = 0x01,
+ SPI_DATA_MUX_RAW = 0x02,
+ SPI_DATA_MUX_RFS = 0x03,
+ SPI_DATA_MUX_CMD = 0x04,
+};
+
+struct spi_data_packet_header {
+ /* 12bit : packet size less than SPI_DEV_PACKET_SIZE */
+ unsigned long current_data_size:31;
+ /* 1bit : packet division flag */
+ unsigned long more:1;
+};
+
+enum SPI_DATA_QUEUE_TYPE_T {
+ SPI_DATA_QUEUE_TYPE_IPC_TX, /* 0 : formatted(IPC) tx buffer */
+ SPI_DATA_QUEUE_TYPE_IPC_RX, /* 1 : formatted(IPC) rx buffer */
+ SPI_DATA_QUEUE_TYPE_RAW_TX, /* 2 : raw tx buffer */
+ SPI_DATA_QUEUE_TYPE_RAW_RX, /* 3 : raw rx buffer */
+ SPI_DATA_QUEUE_TYPE_RFS_TX, /* 4 : rfs tx buffer */
+ SPI_DATA_QUEUE_TYPE_RFS_RX, /* 5 : rfs rx buffer */
+ SPI_DATA_QUEUE_TYPE_NB /* 6 : number of buffer */
+};
+
+struct spi_data_queue {
+ unsigned int tail; /* circular queue header */
+ unsigned int head; /* circular queue tail */
+};
+
+struct spi_data_queue_info {
+ struct spi_data_queue *header;
+ enum SPI_DATA_TYPE_T type;
+ unsigned int buf_size; /* queue size */
+ char *buffer; /* queue data */
+};
+
+struct spi_data_div_buf {
+ unsigned int length;
+ char *buffer; /* queue data */
+};
+
+extern void *ipc_spi_get_queue_buff(void);
+
+extern struct spi_data_queue *spi_data_queue;
+extern struct spi_data_queue_info *spi_queue_info;
+extern char *gspi_data_packet_buf;
+extern char *gspi_data_sync_buf;
+
+extern void spi_data_queue_init(void);
+extern void spi_data_queue_destroy(void);
+extern unsigned int spi_data_dequeue(struct spi_data_queue_info *queue_info,
+ void *pdata);
+extern int spi_data_inqueue(struct spi_data_queue_info *queue, void *data,
+ unsigned int length);
+extern void spi_data_msg_inqueuefront(enum SPI_MAIN_MSG_T task_msg);
+extern int spi_data_queue_is_empty(enum SPI_DATA_QUEUE_TYPE_T type);
+extern int spi_data_div_buf_is_empty(enum SPI_DATA_QUEUE_TYPE_T type);
+extern int spi_data_check_tx_queue(void);
+
+extern int spi_data_prepare_tx_packet(void *buf);
+extern int spi_data_parsing_rx_packet(void *buf, unsigned int length);
+
+extern void spi_data_print_raw_data(void *data, unsigned int length);
+#endif
+
+
+
diff --git a/drivers/phone_svn/ipc_spi/spi_dev.c b/drivers/phone_svn/ipc_spi/spi_dev.c
new file mode 100644
index 0000000..54746d9
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_dev.c
@@ -0,0 +1,345 @@
+/**************************************************************
+
+ spi_dev.c
+
+ adapt device api and spi api
+
+ This is MASTER side.
+
+***************************************************************/
+
+
+
+/**************************************************************
+
+ Preprocessor by common
+
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_dev.h"
+#include "spi_os.h"
+
+
+
+/**************************************************************
+
+ Preprocessor by platform
+ (OMAP4430 && MSM7X30)
+
+***************************************************************/
+
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/phone_svn/ipc_spi.h>
+
+
+
+/**************************************************************
+
+ Definition of Variables and Functions by common
+
+***************************************************************/
+
+int spi_dev_gpio_mrdy;
+int spi_dev_gpio_srdy;
+int spi_dev_gpio_submrdy;
+int spi_dev_gpio_subsrdy;
+
+
+
+/**************************************************************
+
+ Preprocessor by platform
+ (OMAP4430 && MSM7X30)
+
+***************************************************************/
+
+int spi_is_restart;
+
+
+
+/**********************************************************
+
+Prototype void spi_dev_init ( void * data)
+
+Type function
+
+Description init spi gpio info
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+void spi_dev_init(void *data)
+{
+ struct ipc_spi_platform_data *pdata = NULL;
+
+
+ SPI_OS_TRACE(("[SPI] spi_dev_init\n"));
+
+
+ pdata = (struct ipc_spi_platform_data *)data;
+
+ spi_dev_gpio_mrdy = (int) pdata->gpio_ipc_mrdy;
+ spi_dev_gpio_srdy = (int) pdata->gpio_ipc_srdy;
+ spi_dev_gpio_submrdy = (int) pdata->gpio_ipc_sub_mrdy;
+ spi_dev_gpio_subsrdy = (int) pdata->gpio_ipc_sub_srdy;
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_LOW);
+ if (spi_is_restart == 0)
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+}
+
+
+/**********************************************************
+
+Prototype void spi_dev_destroy( void )
+
+Type function
+
+Description unregister irq handler
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+
+void spi_dev_destroy(void)
+{
+ spi_dev_unreigster_irq_handler(spi_dev_gpio_srdy, 0);
+ spi_dev_unreigster_irq_handler(spi_dev_gpio_subsrdy, 0);
+}
+
+
+
+/**********************************************************
+
+Prototype int spi_dev_send
+
+Type function
+
+Description starting data send by DMA(CP side)
+ starting send clock for data switching(AP side)
+
+Param input buf : data for send
+ length : data size. this lengt must be fixed
+
+Return value 0 : success
+ (others) : error cause
+
+***********************************************************/
+
+int spi_dev_send(void *buf, void *sync_buf, unsigned int length)
+{
+ int result = 0;
+
+ result = ipc_spi_tx_rx_sync(buf, sync_buf, length);
+
+ return result;
+}
+
+
+/**********************************************************
+
+Prototype int spi_dev_receive
+
+Type function
+
+Description starting data receive by DMA(CP side)
+ starting send clock for data switching(AP side)
+
+Param input buf : buffer for saving data
+ length : data size. this lengt must be fixed
+
+Return value 0 : success
+ (others) : error cause
+
+***********************************************************/
+
+int spi_dev_receive(void *sync_buf, void *buf, unsigned int length)
+{
+ int value = 0;
+
+ value = ipc_spi_tx_rx_sync(sync_buf, buf, length);
+
+ return value;
+}
+
+
+/**********************************************************
+
+Prototype void spi_dev_set_gpio
+
+Type function
+
+Description set gpio pin state
+
+Param input gpio_id : number of gpio id
+ value : SPI_DEV_GPIOLEVEL_HIGH for raising pin state up
+ : SPI_DEV_GPIOLEVEL_LOW for getting pin state down
+
+Return value (none)
+
+***********************************************************/
+void spi_dev_set_gpio(int gpio_id, enum SPI_DEV_GPIOLEVEL_T value)
+{
+ int level = 0;
+
+ SPI_OS_TRACE_MID(("%s gpio_id =[%d], value =[%d]\n",
+ "[SPI] spi_dev_set_gpio :", gpio_id, (int) value));
+
+ switch (value) {
+ case SPI_DEV_GPIOLEVEL_LOW:
+ level = 0;
+ break;
+ case SPI_DEV_GPIOLEVEL_HIGH:
+ level = 1;
+ break;
+ }
+
+ gpio_set_value((unsigned int) gpio_id, level);
+}
+
+
+
+/**********************************************************
+
+Prototype SPI_DEV_GPIOLEVEL_T spi_dev_get_gpio(int gpio_id)
+
+Type function
+
+Description get gpio pin state
+
+Param input gpio_id : number of gpio id
+
+Return value SPI_DEV_GPIOLEVEL
+
+***********************************************************/
+enum SPI_DEV_GPIOLEVEL_T spi_dev_get_gpio(int gpio_id)
+{
+ enum SPI_DEV_GPIOLEVEL_T value = SPI_DEV_GPIOLEVEL_LOW;
+ int level = 0;
+
+ level = gpio_get_value((unsigned int) gpio_id);
+
+ switch (level) {
+ case 0:
+ value = SPI_DEV_GPIOLEVEL_LOW;
+ break;
+ case 1:
+ value = SPI_DEV_GPIOLEVEL_HIGH;
+ break;
+ }
+
+ return value;
+}
+
+
+/**********************************************************
+
+Prototype int spi_dev_reigster_irq_handler
+
+Type function
+
+Description regist irq callback function to each gpio interrupt
+
+Param input gpio_id : gpio pin id
+ tigger : interrupt detection mode
+ handler : interrupt handler function
+ name : register name
+
+Return value 0 : fail
+ 1 : success
+
+***********************************************************/
+int spi_dev_reigster_irq_handler(int gpio_id,
+ enum SPI_DEV_IRQ_TRIGGER_T trigger,
+ SPI_DEV_IRQ_HANDLER_T handler,
+ char *name, void *data)
+{
+#if defined(SPI_FEATURE_OMAP4430)
+ int value = 0;
+ int _trigger = IRQF_TRIGGER_NONE;
+
+ switch (trigger) {
+ case SPI_DEV_IRQ_TRIGGER_RISING:
+ _trigger = IRQF_TRIGGER_RISING;
+ break;
+ case SPI_DEV_IRQ_TRIGGER_FALLING:
+ _trigger = IRQF_TRIGGER_FALLING;
+ break;
+ default:
+ _trigger = IRQF_TRIGGER_NONE;
+ break;
+ }
+
+ value = request_irq(OMAP_GPIO_IRQ(gpio_id), handler,
+ _trigger, name, data);
+
+ if (value != 0) {
+ SPI_OS_ERROR(("%s regist fail(%d)",
+ "[SPI] ERROR : spi_dev_reigster_irq_handler :",
+ value));
+ return 0;
+ }
+
+#elif defined(SPI_FEATURE_S5PC210)
+ int value = 0;
+
+ int _trigger = IRQF_TRIGGER_NONE;
+ int irq = 0;
+
+
+ switch (trigger) {
+ case SPI_DEV_IRQ_TRIGGER_RISING:
+ _trigger = IRQF_TRIGGER_RISING;
+ break;
+ case SPI_DEV_IRQ_TRIGGER_FALLING:
+ _trigger = IRQF_TRIGGER_FALLING;
+ break;
+ default:
+ _trigger = IRQF_TRIGGER_NONE;
+ break;
+ }
+
+ irq = gpio_to_irq(gpio_id);
+ value = request_irq(irq, handler, _trigger, name, data);
+ if (value != 0) {
+ SPI_OS_ERROR(("spi_dev_reigster_irq_handler: regist fail(%d)",
+ value));
+ return 0;
+ }
+ enable_irq_wake(irq);
+#endif
+
+ return 1;
+}
+
+
+/**********************************************************
+
+void spi_dev_unreigster_irq_handler (int gpio_id, void * data)
+
+Type function
+
+Description unregister irq hanger by gpio api
+
+Param input gpio_id : gpio pin id
+ data : param
+
+Return value (none)
+
+***********************************************************/
+
+void spi_dev_unreigster_irq_handler(int gpio_id, void *data)
+{
+#if defined(SPI_FEATURE_OMAP4430)
+ free_irq(OMAP_GPIO_IRQ(gpio_id), data);
+#elif defined(SPI_FEATURE_S5PC210)
+ free_irq(gpio_to_irq(gpio_id), data);
+#endif
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_dev.h b/drivers/phone_svn/ipc_spi/spi_dev.h
new file mode 100644
index 0000000..6da9e64
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_dev.h
@@ -0,0 +1,49 @@
+#ifndef _SPI_DEV_H_
+#define _SPI_DEV_H_
+
+#include "spi_main.h"
+
+#include <linux/interrupt.h>
+
+#define SPI_DEV_MAX_PACKET_SIZE (2048 * 6)
+
+enum SPI_DEV_SYNC_STATE_T {
+ SPI_DEV_SYNC_OFF = 0,
+ SPI_DEV_SYNC_ON
+};
+
+enum SPI_DEV_GPIOLEVEL_T {
+ SPI_DEV_GPIOLEVEL_LOW = 0,
+ SPI_DEV_GPIOLEVEL_HIGH
+};
+
+enum SPI_DEV_IRQ_TRIGGER_T {
+ SPI_DEV_IRQ_TRIGGER_RISING = 1,
+ SPI_DEV_IRQ_TRIGGER_FALLING
+};
+
+typedef irqreturn_t (*SPI_DEV_IRQ_HANDLER_T)(int, void *);
+#define SPI_DEV_IRQ_HANDLER(X) irqreturn_t X(int irq, void *data)
+
+extern int spi_dev_gpio_mrdy;
+extern int spi_dev_gpio_srdy;
+extern int spi_dev_gpio_submrdy;
+extern int spi_dev_gpio_subsrdy;
+
+extern int spi_is_restart;
+
+extern void spi_dev_init(void *data);
+extern void spi_dev_destroy(void);
+extern int spi_dev_send(void *buf, void * sync_buf, unsigned int length);
+extern int spi_dev_receive(void *sync_buf, void *buf, unsigned int length);
+extern void spi_dev_set_gpio(int gpio_id, enum SPI_DEV_GPIOLEVEL_T value);
+extern enum SPI_DEV_GPIOLEVEL_T spi_dev_get_gpio(int gpio_id);
+extern int spi_dev_reigster_irq_handler(int gpio_id,
+ enum SPI_DEV_IRQ_TRIGGER_T trigger,
+ SPI_DEV_IRQ_HANDLER_T handler,
+ char *name, void *data);
+extern void spi_dev_unreigster_irq_handler(int gpio_id, void *data);
+
+extern int ipc_spi_tx_rx_sync(u8 *tx_d, u8 *rx_d, unsigned len);
+
+#endif
diff --git a/drivers/phone_svn/ipc_spi/spi_main.c b/drivers/phone_svn/ipc_spi/spi_main.c
new file mode 100644
index 0000000..6b104fa
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_main.c
@@ -0,0 +1,563 @@
+/**************************************************************
+ spi_main.c
+
+ process of spi
+
+ This is MASTER side.
+***************************************************************/
+
+/**************************************************************
+ Preprocessor by common
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_os.h"
+#include "spi_dev.h"
+#include "spi_app.h"
+#include "spi_data.h"
+#include "spi_test.h"
+
+/**************************************************************
+ Preprocessor by platform
+ (OMAP4430 && MSM7X30)
+***************************************************************/
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+#include <linux/semaphore.h>
+static struct wake_lock spi_wakelock;
+
+/**************************************************************
+ Definition of Variables and Functions by common
+***************************************************************/
+enum SPI_MAIN_STATE_T spi_main_state = SPI_MAIN_STATE_END;
+
+
+
+static int _start_data_send(void);
+
+static void _start_packet_tx(void);
+
+static void _start_packet_tx_send(void);
+
+static void _start_packet_receive(void);
+
+
+
+
+/**************************************************************
+ Definition of Variables and Functions by platform
+***************************************************************/
+
+#define MRDY_GUARANTEE_MRDY_TIME_GAP 0 /* under 1ms */
+
+#define MRDY_GUARANTEE_MRDY_TIME_SLEEP 2
+
+#define MRDY_GUARANTEE_MRDY_LOOP_COUNT 10000 /* 120us */
+
+
+static void spi_main_process(struct work_struct *pspi_wq);
+
+
+
+#ifdef SPI_GUARANTEE_MRDY_GAP
+
+unsigned long mrdy_low_time_save, mrdy_high_time_save;
+
+int check_mrdy_time_gap(unsigned long x, unsigned long y)
+{
+ if (x == y)
+ return 1;
+ else if ((x < y) && ((y-x) <= MRDY_GUARANTEE_MRDY_TIME_GAP))
+ return 1;
+ else if ((x > y))
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+
+/*=====================================
+* Description set state of spi
+ (Common)
+=====================================*/
+void spi_main_set_state(enum SPI_MAIN_STATE_T state)
+{
+ spi_main_state = state;
+ SPI_OS_TRACE_MID(("[SPI] spi_main_set_state %d=>%d\n",
+ (int)spi_main_state, (int)state));
+}
+
+
+/*=====================================
+* Description an interrupt handler for mrdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_mrdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ return result;
+}
+
+
+/*=====================================
+//Description an interrupt handler for srdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_srdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ if (!boot_done)
+ return result;
+
+ if (!wake_lock_active(&spi_wakelock)) {
+ wake_lock(&spi_wakelock);
+ SPI_OS_TRACE_MID(("[SPI] [%s](%d) spi_wakelock locked .\n",
+ __func__, __LINE__));
+ }
+
+ if (send_modem_spi == 1)
+ up(&srdy_sem); /* signal srdy event */
+
+ /* SRDY interrupt work on SPI_MAIN_STATE_IDLE state for receive data */
+ if (spi_main_state == SPI_MAIN_STATE_IDLE
+ || spi_main_state == SPI_MAIN_STATE_RX_TERMINATE
+ || spi_main_state == SPI_MAIN_STATE_TX_TERMINATE) {
+ spi_main_send_signalfront(SPI_MAIN_MSG_RECEIVE);
+ return result;
+ }
+
+ return result;
+}
+
+
+/*=====================================
+* Description an interrupt handler for submrdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_submrdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ return result;
+}
+
+
+/*=====================================
+* Description an interrupt handler for subsrdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_subsrdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ /* SRDY interrupt work on SPI_MAIN_STATE_TX_WAIT state for send data */
+ if (spi_main_state == SPI_MAIN_STATE_TX_WAIT)
+ return result;
+
+ SPI_OS_TRACE_MID(("%s spi_main_state[%d]\n",
+ "[SPI] spi_main_subsrdy_rising_handler :",
+ (int)spi_main_state));
+
+ return result;
+}
+
+
+/*=====================================
+* Description Send the signal to SPI Task
+=====================================*/
+void spi_main_send_signal(enum SPI_MAIN_MSG_T spi_sigs)
+{
+ struct spi_work *spi_wq = NULL;
+ spi_wq = spi_os_malloc(sizeof(struct spi_work));
+ spi_wq->signal_code = spi_sigs;
+ INIT_WORK(&spi_wq->work, spi_main_process);
+ queue_work(ipc_spi_wq, (struct work_struct *)spi_wq);
+}
+
+
+/*=====================================
+* Description Send the signal to SPI Task
+=====================================*/
+void spi_main_send_signalfront(enum SPI_MAIN_MSG_T spi_sigs)
+{
+ struct spi_work *spi_wq = NULL;
+ spi_wq = spi_os_malloc(sizeof(struct spi_work));
+ spi_wq->signal_code = spi_sigs;
+ INIT_WORK(&spi_wq->work, spi_main_process);
+ queue_work_front(ipc_spi_wq, (struct work_struct *)spi_wq);
+}
+
+
+/*=====================================
+* Description check each queue data and start send routine
+=====================================*/
+static int _start_data_send(void)
+{
+ if (spi_data_check_tx_queue() == 1) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*=====================================
+* Description start to send packet data
+=====================================*/
+static void _start_packet_tx(void)
+{
+ int i = 0;
+
+ if (spi_data_check_tx_queue() == 0)
+ return;
+
+
+ /* check SUB SRDY state */
+ if (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_HIGH) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return;
+ }
+
+ /* check SRDY state */
+ if (spi_dev_get_gpio(spi_dev_gpio_srdy) ==
+ SPI_DEV_GPIOLEVEL_HIGH) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return;
+ }
+
+ if (get_console_suspended()) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return;
+ }
+
+ /* change state SPI_MAIN_STATE_IDLE to SPI_MAIN_STATE_TX_WAIT */
+ spi_main_state = SPI_MAIN_STATE_TX_WAIT;
+
+#ifdef SPI_GUARANTEE_MRDY_GAP
+ mrdy_high_time_save = spi_os_get_tick();
+ if (check_mrdy_time_gap(mrdy_low_time_save, mrdy_high_time_save))
+ spi_os_sleep(1);
+#endif
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ /* check SUBSRDY state */
+ while (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW) {
+ if (i == 0) {
+ spi_os_sleep(1);
+ i++;
+ continue;
+ } else
+ spi_os_sleep(MRDY_GUARANTEE_MRDY_TIME_SLEEP);
+
+ i++;
+ if (i > MRDY_GUARANTEE_MRDY_TIME_SLEEP * 20) {
+ SPI_OS_ERROR(("%s spi_main_state=[%d]\n",
+ "[SPI] === spi Fail to receiving SUBSRDY CONF :",
+ (int)spi_main_state));
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy,
+ SPI_DEV_GPIOLEVEL_LOW);
+#ifdef SPI_GUARANTEE_MRDY_GAP
+ mrdy_low_time_save = spi_os_get_tick();
+#endif
+ /* change state SPI_MAIN_STATE_TX_WAIT */
+ /* to SPI_MAIN_STATE_IDLE */
+ if (spi_main_state != SPI_MAIN_STATE_START
+ && spi_main_state != SPI_MAIN_STATE_END
+ && spi_main_state != SPI_MAIN_STATE_INIT) {
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ _start_data_send();
+ }
+ return;
+ }
+ }
+ if (spi_main_state != SPI_MAIN_STATE_START
+ && spi_main_state != SPI_MAIN_STATE_END
+ && spi_main_state != SPI_MAIN_STATE_INIT) {
+ _start_packet_tx_send();
+ } else
+ SPI_OS_ERROR(("[SPI] ERR : _start_packet_tx:spi_main_state[%d]",
+ (int)spi_main_state));
+
+ return;
+}
+
+
+/*=====================================
+* Description send data
+=====================================*/
+static void _start_packet_tx_send(void)
+{
+ char *spi_packet_buf = NULL;
+ char *spi_sync_buf = NULL;
+
+ /* change state SPI_MAIN_STATE_TX_WAIT to SPI_MAIN_STATE_TX_SENDING */
+ spi_main_state = SPI_MAIN_STATE_TX_SENDING;
+
+ spi_packet_buf = gspi_data_packet_buf;
+ spi_sync_buf = gspi_data_sync_buf;
+
+ spi_os_memset(spi_packet_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+ spi_os_memset(spi_sync_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+
+ spi_data_prepare_tx_packet(spi_packet_buf);
+ if (spi_dev_send((void *)spi_packet_buf, (void *)spi_sync_buf,
+ SPI_DEV_MAX_PACKET_SIZE) != 0) {
+ /* TODO: save failed packet */
+ /* back data to each queue */
+ SPI_OS_ERROR(("[SPI] spi_dev_send fail\n"));
+ panic("[SPI] spi_dev_send\n");
+ }
+
+ spi_main_state = SPI_MAIN_STATE_TX_TERMINATE;
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_LOW);
+#ifdef SPI_GUARANTEE_MRDY_GAP
+ mrdy_low_time_save = spi_os_get_tick();
+#endif
+
+ /* change state SPI_MAIN_STATE_TX_SENDING to SPI_MAIN_STATE_IDLE */
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ _start_data_send();
+}
+
+
+/*=====================================
+* Description start to receive packet data
+=====================================*/
+static void _start_packet_receive(void)
+{
+ char *spi_packet_buf = NULL;
+ char *spi_sync_buf = NULL;
+ struct spi_data_packet_header spi_receive_packet_header = {0, };
+ int i = 0;
+
+ if (!wake_lock_active(&spi_wakelock))
+ return;
+
+ if (spi_dev_get_gpio(spi_dev_gpio_srdy) == SPI_DEV_GPIOLEVEL_LOW)
+ return;
+
+ if (get_console_suspended())
+ return;
+
+ spi_main_state = SPI_MAIN_STATE_RX_WAIT;
+
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+
+ /* check SUBSRDY state */
+ while (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW) {
+ if (i == 0) {
+ spi_os_sleep(1);
+ i++;
+ continue;
+ } else
+ spi_os_sleep(MRDY_GUARANTEE_MRDY_TIME_SLEEP);
+
+ i++;
+ if (i > MRDY_GUARANTEE_MRDY_TIME_SLEEP * 20) {
+ SPI_OS_ERROR(("[SPI] ERROR(Failed MASTER RX:%d/%d)",
+ i, MRDY_GUARANTEE_MRDY_TIME_SLEEP * 20));
+ if (spi_main_state != SPI_MAIN_STATE_START
+ && spi_main_state != SPI_MAIN_STATE_END
+ && spi_main_state != SPI_MAIN_STATE_INIT) {
+ spi_dev_set_gpio(spi_dev_gpio_submrdy,
+ SPI_DEV_GPIOLEVEL_LOW);
+
+ /* change state SPI_MAIN_STATE_RX_WAIT */
+ /* to SPI_MAIN_STATE_IDLE */
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ }
+ return;
+ }
+ }
+
+ if (spi_main_state == SPI_MAIN_STATE_START
+ || spi_main_state == SPI_MAIN_STATE_END
+ || spi_main_state == SPI_MAIN_STATE_INIT)
+ return;
+
+ spi_packet_buf = gspi_data_packet_buf;
+ spi_sync_buf = gspi_data_sync_buf;
+
+ spi_os_memset(spi_packet_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+ spi_os_memset(spi_sync_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+
+ if (spi_dev_receive((void *)spi_sync_buf, (void *)spi_packet_buf,
+ SPI_DEV_MAX_PACKET_SIZE) == 0) {
+ /* parsing SPI packet */
+ spi_os_memcpy(&spi_receive_packet_header, spi_packet_buf,
+ SPI_DATA_PACKET_HEADER_SIZE);
+
+ if (spi_data_parsing_rx_packet((void *)spi_packet_buf,
+ spi_receive_packet_header.current_data_size) > 0) {
+ /* call function for send data to IPC, RAW, RFS */
+ spi_send_msg_to_app();
+ }
+ } else{
+ SPI_OS_ERROR(("[SPI] spi_dev_receive fail\n"));
+ panic("[SPI] spi_dev_receive\n");
+ }
+
+ spi_main_state = SPI_MAIN_STATE_RX_TERMINATE;
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+
+ /* change state SPI_MAIN_STATE_RX_WAIT to SPI_MAIN_STATE_IDLE */
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ _start_data_send();
+
+ return;
+}
+
+
+/*=====================================
+* Description creating a task
+=====================================*/
+void spi_main_init(void *data)
+{
+ struct ipc_spi_platform_data *pdata;
+
+ SPI_OS_TRACE(("[SPI] spi_main_init\n"));
+
+ spi_main_state = SPI_MAIN_STATE_START;
+
+
+ pdata = (struct ipc_spi_platform_data *)data;
+
+ wake_lock_init(&spi_wakelock, WAKE_LOCK_SUSPEND,
+ "samsung-spiwakelock");
+
+ spi_dev_init(pdata);
+
+ spi_dev_reigster_irq_handler (spi_dev_gpio_srdy,
+ SPI_DEV_IRQ_TRIGGER_RISING,
+ spi_main_srdy_rising_handler,
+ "spi_srdy_rising", 0);
+ spi_dev_reigster_irq_handler (spi_dev_gpio_subsrdy,
+ SPI_DEV_IRQ_TRIGGER_RISING,
+ spi_main_subsrdy_rising_handler,
+ "spi_subsrdy_rising", 0);
+}
+
+
+/*=====================================
+* Description main process
+=====================================*/
+
+static void spi_main_process(struct work_struct *work)
+{
+ int signal_code;
+
+ struct spi_work *spi_wq = container_of(work, struct spi_work, work);
+ signal_code = spi_wq->signal_code;
+
+
+ if (spi_main_state == SPI_MAIN_STATE_END
+ || spi_main_state == SPI_MAIN_STATE_START) {
+ spi_os_free(spi_wq);
+ return;
+ }
+
+ switch (signal_code) {
+ case SPI_MAIN_MSG_SEND:
+ if (spi_main_state == SPI_MAIN_STATE_IDLE)
+ _start_packet_tx();
+
+ break;
+
+ case SPI_MAIN_MSG_PACKET_SEND:
+ _start_packet_tx_send();
+ break;
+
+ case SPI_MAIN_MSG_RECEIVE:
+ if (spi_main_state == SPI_MAIN_STATE_IDLE
+ || spi_main_state == SPI_MAIN_STATE_RX_TERMINATE
+ || spi_main_state == SPI_MAIN_STATE_TX_TERMINATE)
+ _start_packet_receive();
+ break;
+
+ /* Receive data from IPC,RAW,RFS. */
+ /* It need analyze and save to tx queue */
+ case SPI_MAIN_MSG_IPC_SEND:
+ case SPI_MAIN_MSG_RAW_SEND:
+ case SPI_MAIN_MSG_RFS_SEND:
+ /* start send data during SPI_MAIN_STATE_IDLE state */
+ if (spi_main_state == SPI_MAIN_STATE_IDLE)
+ _start_data_send();
+ break;
+
+ default:
+ SPI_OS_ERROR(("[SPI] ERROR(No signal_code in spi_main[%d])\n",
+ signal_code));
+ break;
+ }
+
+ spi_os_free(spi_wq);
+ if (wake_lock_active(&spi_wakelock)) {
+ wake_unlock(&spi_wakelock);
+ SPI_OS_TRACE_MID(("[SPI] [%s](%d) spi_wakelock unlocked .\n",
+ __func__, __LINE__));
+ }
+}
+
+
+/*=====================================
+//Description main task
+=====================================*/
+void spi_main(unsigned long argc, void *argv)
+{
+ /* queue init */
+ spi_data_queue_init();
+
+ SPI_OS_TRACE(("[SPI] spi_main %x\n", (unsigned int)argv));
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ do {
+ spi_os_sleep(30);
+ } while (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW);
+
+ if (spi_is_restart)
+ spi_os_sleep(100);
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ spi_is_restart = 0;
+}
+
+
+/*=====================================
+* Description spi restart for CP slient reset
+=====================================*/
+
+void spi_set_restart(void)
+{
+ SPI_OS_ERROR(("[SPI] spi_set_restart(spi_main_state=[%d])\n",
+ (int)spi_main_state));
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+
+ spi_main_state = SPI_MAIN_STATE_END;
+
+ spi_is_restart = 1;
+
+ flush_workqueue(ipc_spi_wq);
+
+ spi_data_queue_destroy();
+
+ spi_dev_destroy();
+
+ if (wake_lock_active(&spi_wakelock)) {
+ wake_unlock(&spi_wakelock);
+ SPI_OS_TRACE_MID(("[SPI] [%s](%d) spi_wakelock unlocked.\n",
+ __func__, __LINE__));
+ }
+ wake_lock_destroy(&spi_wakelock);
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_main.h b/drivers/phone_svn/ipc_spi/spi_main.h
new file mode 100644
index 0000000..b15465a
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_main.h
@@ -0,0 +1,80 @@
+#ifndef __SPI_MAIN_H__
+#define __SPI_MAIN_H__
+
+#define SPI_FEATURE_S5PC210
+#define SPI_FEATURE_MASTER
+
+#define SPI_FEATURE_NOLOG
+/* #define SPI_FEATURE_DEBUG */
+#define SPI_GUARANTEE_MRDY_GAP
+
+/*
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_MASTER_SENDING
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_SLAVE_SENDING
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_PHYSICAL
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_NONE
+#define SPI_FEATURE_TEST_DURATION 1000
+*/
+
+#define SPI_SLAVE_TX 0
+#define SPI_SLAVE_RX 0
+#define SPI_MASTER_TX 0
+#define SPI_MASTER_RX 0
+
+#include "spi_os.h"
+
+enum SPI_MAIN_MSG_T {
+ SPI_MAIN_MSG_BASE,
+ SPI_MAIN_MSG_SEND,
+ SPI_MAIN_MSG_RECEIVE,
+ SPI_MAIN_MSG_PACKET_SEND,
+ SPI_MAIN_MSG_PACKET_RECEIVE,
+ SPI_MAIN_MSG_IPC_SEND, /* IPC sends message to SPI */
+ SPI_MAIN_MSG_RAW_SEND, /* RAW sends message to SPI */
+ SPI_MAIN_MSG_RFS_SEND /* RFS sends message to SPI */
+};
+
+enum SPI_MAIN_STATE_T {
+ SPI_MAIN_STATE_START, /* before init complete */
+ SPI_MAIN_STATE_INIT, /* initialising */
+ SPI_MAIN_STATE_IDLE, /* suspend. Waiting for event */
+
+ /* state to start tx. Become from idle */
+ SPI_MAIN_STATE_TX_START,
+ SPI_MAIN_STATE_TX_CONFIRM,
+
+ /* (in case of master) */
+ /* wait srdy rising interrupt to check slave preparing */
+ /* (in case of slave) */
+ /* wait submrdy rising interrupt to check sync complete */
+ SPI_MAIN_STATE_TX_WAIT,
+ SPI_MAIN_STATE_TX_SENDING, /* tx data sending */
+ SPI_MAIN_STATE_TX_TERMINATE,
+ SPI_MAIN_STATE_TX_MORE,
+
+ /* in case of slave, wait submrdy rising interrupt to */
+ SPI_MAIN_STATE_RX_WAIT,
+
+ /* check sync complete then it starts to read buffer */
+ SPI_MAIN_STATE_RX_MORE,
+ SPI_MAIN_STATE_RX_TERMINATE,
+ SPI_MAIN_STATE_END /* spi task is stopped */
+};
+
+extern struct workqueue_struct *ipc_spi_wq;
+extern int send_modem_spi;
+extern int boot_done;
+extern struct semaphore srdy_sem;
+
+
+extern enum SPI_MAIN_STATE_T spi_main_state;
+
+extern void spi_main(unsigned long argc, void *argv);
+extern void spi_main_init(void *data);
+extern void spi_main_send_signal(enum SPI_MAIN_MSG_T spi_sigs);
+extern void spi_main_send_signalfront(enum SPI_MAIN_MSG_T spi_sigs);
+extern void spi_set_restart(void);
+extern int get_console_suspended(void);
+
+#endif
+
diff --git a/drivers/phone_svn/ipc_spi/spi_os.c b/drivers/phone_svn/ipc_spi/spi_os.c
new file mode 100644
index 0000000..f1d2550
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_os.c
@@ -0,0 +1,634 @@
+/**************************************************************
+ spi_os.c
+
+ adapt os api and spi api
+
+ This is MATER side.
+***************************************************************/
+
+/**************************************************************
+ Preprocessor by common
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_os.h"
+
+
+/**************************************************************
+ Preprocessor by platform
+ (Android)
+***************************************************************/
+
+#include <linux/vmalloc.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/in.h>
+#include <linux/time.h>
+
+/**********************************************************
+Prototype void * spi_os_malloc ( unsigned int length )
+
+Type function
+
+Description allocate memory
+
+Param input length : length of size
+
+Return value 0 : fail
+ (other) : address of memory allocated
+***********************************************************/
+void *spi_os_malloc(unsigned int length)
+{
+ if (length <= 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_malloc fail : len 0\n"));
+ return 0;
+ }
+
+ return kmalloc(length, GFP_ATOMIC);
+}
+
+
+/*====================================
+Prototype void * spi_os_vmalloc ( unsigned int length )
+
+Type function
+
+Description allocate memory with vmalloc
+
+Param input length : length of size
+
+Return value 0 : fail
+ (other) : address of memory allocated
+====================================*/
+void *spi_os_vmalloc(unsigned int length)
+{
+ if (length <= 0) {
+ SPI_OS_ERROR(("spi_os_malloc fail : length is 0\n"));
+ return 0;
+ }
+ return vmalloc(length);
+}
+
+
+/**********************************************************
+Prototype int spi_os_free ( void * addr )
+
+Type function
+
+Description free memory
+
+Param input addr : address of memory to be released
+
+Return value 0 : fail
+ 1 : success
+***********************************************************/
+int spi_os_free(void *addr)
+{
+ if (addr == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_free fail : addr is 0\n"));
+ return 0;
+ }
+
+ kfree(addr);
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_vfree ( void * addr )
+
+Type function
+
+Description free memory with vfree
+
+Param input addr : address of memory to be released
+
+Return value 0 : fail
+ 1 : success
+***********************************************************/
+int spi_os_vfree(void *addr)
+{
+ if (addr == 0) {
+ SPI_OS_ERROR(("spi_os_free fail : addr is 0\n"));
+ return 0;
+ }
+
+#ifdef SPI_FEATURE_OMAP4430
+ vfree(addr);
+#elif defined SPI_FEATURE_SC8800G
+ SCI_FREE(addr);
+#endif
+
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_memcpy ( void * dest, void * src, unsigned int length )
+
+Type function
+
+Description copy memory
+
+Param input dest : address of memory to be save
+ src : address of memory to copy
+ length : length of memory to copy
+
+Return value 0 : fail
+ 1 : success
+***********************************************************/
+int spi_os_memcpy(void *dest, void *src, unsigned int length)
+{
+ if (dest == 0 || src == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ memcpy(dest, src, length);
+
+ return 1;
+}
+
+
+/**********************************************************
+Prototype void * spi_os_memset ( void * addr, int value, unsigned int length )
+
+Type function
+
+Description set memory as parameter
+
+Param input addr : address of memory to be set
+ value : value to set
+ length : length of memory to be set
+
+Return value (none)
+***********************************************************/
+void *spi_os_memset(void *addr, int value, unsigned int length)
+{
+ if (addr == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ return memset(addr, value, length);
+}
+
+
+/**********************************************************
+Prototype int spi_os_create_mutex( char * name, unsigned int priority_inherit )
+
+Type function
+
+Description create mutex
+
+Param input name : name of mutex
+ priority_inherit : mutex inheritance
+
+Return value id of mutex created
+***********************************************************/
+int spi_os_create_mutex(char *name, unsigned int priority_inherit)
+{
+ if (name == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_delete_mutex ( int pmutex )
+
+Type function
+
+Description delete mutex
+
+Param input pmutex : id of mutex
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_delete_mutex(int pmutex)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_acquire_mutex ( int pmutex, unsigned int wait )
+
+Type function
+
+Description acquire mutex
+
+Param input pmutex : id of mutex to acquire
+ wait : mutex waiting time
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_acquire_mutex(int pmutex, unsigned int wait)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_release_mutex (int pmutex )
+
+Type function
+
+Description release mutex
+
+Param input pmutex : id of mutex to release
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_release_mutex(int pmutex)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_create_sem ( char * name, unsigned int init_count)
+
+Type function
+
+Description create semaphore
+
+Param input name : name of semaphore
+ init_count : semaphore count
+
+Return value id of semaphore created
+***********************************************************/
+int spi_os_create_sem(char *name, unsigned int init_count)
+{
+ if (name == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_delete_sem ( int sem )
+
+Type function
+
+Description delete semaphore
+
+Param input sem : id of semaphore to delete
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_delete_sem(int sem)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_acquire_sem (int sem, unsigned int wait )
+
+Type function
+
+Description acquire semaphore
+
+Param input sem : id of semaphore to acquire
+ wait : mutex waiting time
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_acquire_sem(int sem, unsigned int wait)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_release_sem (int sem )
+
+Type function
+
+Description release semaphore
+
+Param input sem : id of semaphore to release
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_release_sem(int sem)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype void spi_os_sleep ( unsigned long msec )
+
+Type function
+
+Description sleep os
+
+Param input msec : time to sleep
+
+Return value (none)
+***********************************************************/
+void spi_os_sleep(unsigned long msec)
+{
+ if (msec <= 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_sleep fail\n"));
+ return;
+ }
+
+ msleep(msec);
+}
+
+
+/**********************************************************
+Prototype void spi_os_loop_delay ( unsigned long cnt )
+
+Type function
+
+Description delay task with loop
+
+Param input cnt : delay count
+
+Return value (none)
+***********************************************************/
+void spi_os_loop_delay(unsigned long cnt)
+{
+ unsigned int timeout;
+ timeout = 0;
+ while (++timeout < cnt)
+ ;
+}
+
+
+/**********************************************************
+Prototype void * spi_os_create_timer
+
+Type function
+
+Description create timer
+
+Param input name : timer name
+ callback : timer callback function
+ param : timer param
+ duration : timer expire duration
+
+Return value timer ptr
+***********************************************************/
+int spi_os_create_timer(void *timer, char *name,
+ SPI_OS_TIMER_T callback, int param, unsigned long duration)
+{
+ struct timer_list *tm = timer;
+
+
+ if (name == 0 || callback == 0 || param <= 0 || duration <= 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_create_timer fail\n"));
+ return 0;
+ }
+
+ init_timer(tm);
+
+ tm->expires = jiffies + ((duration * HZ) / 1000);
+ tm->data = (unsigned long) param;
+ tm->function = callback;
+
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_start_timer
+
+Type function
+
+Description start timer
+
+Param input timer : timer ptr
+ callback : timer callback function
+ param : timer param
+ duration : timer expire duration
+
+Return value 1 : success
+ 0 : fail
+***********************************************************/
+int spi_os_start_timer(void *timer, SPI_OS_TIMER_T callback,
+ int param, unsigned long duration)
+{
+ add_timer((struct timer_list *) timer);
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_stop_timer (void * timer)
+
+Type function
+
+Description stop timer
+
+Param input timer : timer ptr
+
+Return value 1 : success
+ 0 : fail
+***********************************************************/
+int spi_os_stop_timer(void *timer)
+{
+ int value = 0;
+
+ value = del_timer((struct timer_list *) timer);
+
+ return value;
+}
+
+
+/**********************************************************
+Prototype int spi_os_delete_timer (void * timer)
+
+Type function
+
+Description delete timer
+
+Param input timer : timer ptr
+
+Return value 1 : success
+ 0 : fail
+***********************************************************/
+int spi_os_delete_timer(void *timer)
+{
+ return 1;
+}
+
+
+/**********************************************************
+Prototype unsigned long spi_os_get_tick (void)
+
+Type function
+
+Description get system tick
+
+Param input (none)
+
+Return value system tick
+
+***********************************************************/
+unsigned long spi_os_get_tick(void)
+{
+ unsigned long tick = 0;
+
+ tick = jiffies_to_msecs(jiffies);
+ return tick;
+}
+
+
+/**********************************************************
+Prototype void spi_os_get_tick_by_log (char * name)
+
+Type function
+
+Description print tick time to log
+
+Param input name : print name
+
+Return value (none)
+***********************************************************/
+void spi_os_get_tick_by_log(char *name)
+{
+ SPI_OS_TRACE(("[SPI] %s tick %lu ms\n", name, spi_os_get_tick()));
+
+}
+
+
+/**********************************************************
+Prototype void spi_os_trace_dump (char * name, void * data, int length)
+
+Description print buffer value by hex code
+ if buffer size too big, it change to....
+ and print 64 byte of front and 64 byte of tail
+
+Param input name : print name
+ data : buffer for print
+ length : print length
+
+Return value (none)
+***********************************************************/
+void spi_os_trace_dump(char *name, void *data, int length)
+{
+#ifdef SPI_FEATURE_DEBUG
+ #define SPI_OS_TRACE_DUMP_PER_LINE 16
+ #define SPI_OS_TRACE_MAX_LINE 8
+ #define SPI_OS_TRACE_HALF_LINE
+ (SPI_OS_TRACE_MAX_LINE / 2)
+ #define SPI_OS_TRACE_MAX_DUMP_SIZE
+ (SPI_OS_TRACE_DUMP_PER_LINE*SPI_OS_TRACE_MAX_LINE)
+
+ int i = 0, lines = 0, halflinemode = 0;
+
+ char buf[SPI_OS_TRACE_DUMP_PER_LINE * 3 + 1];
+ char *pdata = NULL;
+
+ char ch = 0;
+
+ SPI_OS_TRACE_MID(("[SPI] spi_os_trace_dump (%s length[%d])\n",
+ name, length));
+
+ spi_os_memset(buf, 0x00, sizeof(buf));
+
+ if (length > SPI_OS_TRACE_MAX_DUMP_SIZE)
+ halflinemode = 1;
+
+ pdata = data;
+ for (i = 0 ; i < length ; i++) {
+ if ((i != 0) && ((i % SPI_OS_TRACE_DUMP_PER_LINE) == 0)) {
+ buf[SPI_OS_TRACE_DUMP_PER_LINE*3] = 0;
+ SPI_OS_TRACE_MID(("%s\n", buf));
+ spi_os_memset(buf, 0x00, sizeof(buf));
+ lines++;
+ if (SPI_OS_TRACE_HALF_LINE == lines
+ && halflinemode == 1) {
+ SPI_OS_TRACE_MID((" ......\n"));
+ pdata += (length - SPI_OS_TRACE_MAX_DUMP_SIZE);
+ i += (length - SPI_OS_TRACE_MAX_DUMP_SIZE);
+ }
+ }
+
+ ch = (*pdata&0xF0)>>4;
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ ch = (*pdata&0x0F);
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+1] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+2] = 0x20;
+ pdata++;
+ }
+
+ if (buf[0] != '\0')
+ SPI_OS_TRACE_MID(("%s\n", buf));
+
+ #undef SPI_OS_TRACE_DUMP_PER_LINE
+ #undef SPI_OS_TRACE_MAX_LINE
+ #undef SPI_OS_TRACE_HALF_LINE
+ #undef SPI_OS_TRACE_MAX_DUMP_SIZE
+#endif
+}
+
+
+/**********************************************************
+Prototype void spi_os_trace_dump (char * name, void * data, int length)
+
+Description print buffer value by hex code as SPI_OS_TRACE
+
+ this function print only 16 byte
+
+Param input name : print name
+ data : buffer for print
+ length : print length
+
+Return value (none)
+***********************************************************/
+
+void spi_os_trace_dump_low(char *name, void *data, int length)
+{
+ #define SPI_OS_TRACE_DUMP_PER_LINE 16
+
+ int i = 0;
+ char buf[SPI_OS_TRACE_DUMP_PER_LINE * 3 + 1] = {0,};
+ char *pdata = NULL;
+ char ch = 0;
+
+ SPI_OS_ERROR(("[SPI] spi_os_trace_dump_low (%s length[%d])\n",
+ name, length));
+
+ spi_os_memset(buf, 0x00, sizeof(buf));
+
+ if (length > SPI_OS_TRACE_DUMP_PER_LINE)
+ length = SPI_OS_TRACE_DUMP_PER_LINE;
+
+ pdata = data;
+ for (i = 0 ; i < length ; i++) {
+ ch = (*pdata&0xF0)>>4;
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ ch = (*pdata&0x0F);
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+1] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+2] = 0x20;
+ pdata++;
+ }
+
+ if (buf[0] != '\0')
+ SPI_OS_ERROR(("%s\n", buf));
+
+ #undef SPI_OS_TRACE_DUMP_PER_LINE
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_os.h b/drivers/phone_svn/ipc_spi/spi_os.h
new file mode 100644
index 0000000..5174144
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_os.h
@@ -0,0 +1,82 @@
+#ifndef __SPI_OS_H__
+#define __SPI_OS_H__
+
+#include "spi_main.h"
+
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+
+
+#define SPI_OS_ASSERT(x) printk x
+#define SPI_OS_ERROR(x) printk x
+
+#ifdef SPI_FEATURE_NOLOG
+#define SPI_OS_TRACE_MID(x)
+#define SPI_OS_TRACE(x)
+#else
+#define SPI_OS_TRACE(x) printk x
+#ifdef SPI_FEATURE_DEBUG
+#define SPI_OS_TRACE_MID(x) printk x
+#else
+#define SPI_OS_TRACE_MID(x)
+#endif /* SPI_FEATURE_DEBUG */
+#endif /* SPI_FEATURE_NOLOG */
+
+struct spi_work {
+ struct work_struct work;
+ int signal_code;
+};
+
+struct spi_os_msg {
+ unsigned int signal_code;
+ unsigned int data_length;
+ void *data;
+};
+
+typedef void (*SPI_OS_TIMER_T)(unsigned long);
+/* Inherit option */
+#define SPI_OS_MUTEX_NO_INHERIT 0
+#define SPI_OS_MUTEX_INHERIT 1
+/* Wait option. */
+#define SPI_OS_MUTEX_NO_WAIT /* TBD */
+#define SPI_OS_MUTEX_WAIT_FOREVER /* TBD */
+#define SPI_OS_TIMER_CALLBACK(X) void X(unsigned long param)
+
+/* Memory */
+extern void *spi_os_malloc(unsigned int length);
+extern void *spi_os_vmalloc(unsigned int length);
+extern int spi_os_free(void *addr);
+extern int spi_os_vfree(void *addr);
+extern int spi_os_memcpy(void *dest, void *src, unsigned int length);
+extern void *spi_os_memset(void *addr, int value, unsigned int length);
+
+/* Mutex */
+extern int spi_os_create_mutex(char *name,
+ unsigned int priority_inherit);
+extern int spi_os_delete_mutex(int sem);
+extern int spi_os_acquire_mutex(int sem, unsigned int wait);
+extern int spi_os_release_mutex(int sem);
+
+
+/* Semaphore */
+extern int spi_os_create_sem(char *name, unsigned int init_count);
+extern int spi_os_delete_sem(int sem);
+extern int spi_os_acquire_sem(int sem, unsigned int wait);
+extern int spi_os_release_sem(int sem);
+
+/* Timer */
+extern void spi_os_sleep(unsigned long msec);
+extern void spi_os_loop_delay(unsigned long cnt);
+extern int spi_os_create_timer(void *timer, char *name,
+ SPI_OS_TIMER_T callback, int param, unsigned long duration);
+extern int spi_os_start_timer(void *timer, SPI_OS_TIMER_T callback,
+ int param, unsigned long duration);
+extern int spi_os_stop_timer(void *timer);
+extern int spi_os_delete_timer(void *timer);
+
+/* Log */
+extern unsigned long spi_os_get_tick(void);
+extern void spi_os_get_tick_by_log(char *name);
+extern void spi_os_trace_dump(char *name, void *data, int length);
+extern void spi_os_trace_dump_low(char *name, void *data, int length);
+#endif
diff --git a/drivers/phone_svn/ipc_spi/spi_test.c b/drivers/phone_svn/ipc_spi/spi_test.c
new file mode 100644
index 0000000..31f717f
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_test.c
@@ -0,0 +1,270 @@
+#include "spi_main.h"
+#include "spi_test.h"
+#include "spi_os.h"
+#include "spi_dev.h"
+#include "spi_app.h"
+
+enum SPI_TEST_SCENARIO_T spi_test_scenario_mode = SPI_TEST_SCENARIO_NONE;
+
+static void _scenario_physical(void);
+static void _scenario_sending(int param);
+
+
+static void _scenario_physical(void)
+{
+ int count = 0;
+ int failcount = 0;
+ int i;
+ char txbuf[SPI_DEV_MAX_PACKET_SIZE];
+ char rxbuf[SPI_DEV_MAX_PACKET_SIZE];
+
+ SPI_OS_TRACE_MID(("spi_scenario_physical\n"));
+
+ spi_os_memset(txbuf, 0x00, sizeof(txbuf));
+ for (i = 0 ; i < SPI_DEV_MAX_PACKET_SIZE ; i++)
+ txbuf[i] = i%100;
+
+ while (count < 100) {
+ SPI_OS_TRACE_MID(("spi _scenario_physical %d\n", count));
+ SPI_OS_TRACE_MID(("%s mrdy %d srdy %d submrdy %d subsrdy %d\n",
+ "spi_scenario_physical test start",
+ spi_dev_get_gpio(spi_dev_gpio_mrdy),
+ spi_dev_get_gpio(spi_dev_gpio_srdy),
+ spi_dev_get_gpio(spi_dev_gpio_submrdy),
+ spi_dev_get_gpio(spi_dev_gpio_subsrdy)));
+
+ txbuf[0] = count;
+ spi_os_memset(rxbuf, 0x00, sizeof(rxbuf));
+
+#ifdef SPI_FEATURE_MASTER
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+ SPI_OS_TRACE_MID(("%s, subsrdy high\n",
+ "spi_scenario_physical test wait srdy"));
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ while (spi_dev_get_gpio(spi_dev_gpio_srdy) ==
+ SPI_DEV_GPIOLEVEL_LOW)
+ ;
+
+ /* spreadtrum recommend. */
+ /* master should send/receive after that slave is ready. */
+ spi_os_sleep(20);
+
+ if (count % 2 == 0) {
+ spi_dev_send(txbuf, SPI_DEV_MAX_PACKET_SIZE);
+ } else {
+ spi_dev_receive(rxbuf, SPI_DEV_MAX_PACKET_SIZE);
+ for (i = 1 ; i < SPI_DEV_MAX_PACKET_SIZE ; i++) {
+ if (rxbuf[i] != txbuf[i]) {
+ failcount++;
+ spi_os_trace_dump("spi_scenario_physical receiving fail",
+ &rxbuf[i-8], 16);
+ SPI_OS_TRACE_MID(("%s %d count %d/%d\n",
+ "spi_scenario_physical test receiving fail",
+ i, failcount, count));
+ i = sizeof(rxbuf);
+ break;
+ }
+ }
+ }
+
+ spi_os_sleep(20);
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+#elif defined SPI_FEATURE_SLAVE
+ spi_dev_set_gpio(spi_dev_gpio_srdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+ spi_dev_set_gpio(spi_dev_gpio_subsrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+ while (spi_dev_get_gpio(spi_dev_gpio_mrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW)
+ ;
+
+ spi_dev_set_gpio(spi_dev_gpio_srdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ if (count % 2 == 0) {
+ spi_dev_receive(rxbuf, SPI_DEV_MAX_PACKET_SIZE);
+ for (i = 1 ; i < SPI_DEV_MAX_PACKET_SIZE ; i++) {
+ if (rxbuf[i] != txbuf[i]) {
+ failcount++;
+ spi_os_trace_dump("spi_scenario_phy rx fail",
+ &rxbuf[i-8], 16);
+ SPI_OS_TRACE_MID(("%s %d count %d/%d\n",
+ "spi_scenario_physical test receiving fail",
+ i, failcount, count));
+ i = sizeof(rxbuf);
+ break;
+ }
+ }
+ } else
+ spi_dev_send(txbuf, SPI_DEV_MAX_PACKET_SIZE);
+
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+#endif
+ count++;
+ SPI_OS_TRACE_MID(("%s %d/%d\n",
+ "spi_scenario_physical test receiving result count",
+ failcount, count));
+ }
+}
+
+
+SPI_OS_TIMER_CALLBACK(spi_test_timer_callback)
+{
+ SPI_OS_TRACE_MID(("spi_test_timer_callback\n"));
+ _scenario_sending(0);
+}
+
+static char tempdata1[135]; /* temp code. becuase can not allocate */
+static char tempdata2[367]; /* temp code. becuase can not allocate */
+static char tempdata3[1057]; /* temp code. becuase can not allocate */
+static char tempdata4[35]; /* temp code. becuase can not allocate */
+static char tempdata5[2079]; /* temp code. becuase can not allocate */
+static char tempdata6[200]; /* temp code. becuase can not allocate */
+static char tempdata7[2052]; /* temp code. becuase can not allocate */
+
+static void _scenario_sending(int param)
+{
+ #define NB_COUNT 50
+ #define NB_STEP 7
+ static int step;
+ static int duration;
+ static int count;
+ static void *timer_id;
+
+ char *data = NULL;
+ int i, value;
+ struct DATABYSTEP_T {
+ SPI_MAIN_MSG_T type;
+ unsigned int size;
+ char *buf;
+ } databystep[NB_STEP] = {
+ {SPI_MAIN_MSG_IPC_SEND, 135, tempdata1},
+ {SPI_MAIN_MSG_IPC_SEND, 187, tempdata2},
+ {SPI_MAIN_MSG_RAW_SEND, 1057, tempdata3},
+ {SPI_MAIN_MSG_IPC_SEND, 35, tempdata4},
+ {SPI_MAIN_MSG_RAW_SEND, 2079, tempdata5},
+ {SPI_MAIN_MSG_IPC_SEND, 100, tempdata6},
+ {SPI_MAIN_MSG_RAW_SEND, 2052, tempdata7}
+ };
+
+ if (spi_test_scenario_mode == SPI_TEST_SCENARIO_SLAVE_SENDING)
+ data = databystep[step].buf;
+
+ /* param is 0 to fix duration. */
+ /* call this function with param to change timer duration. */
+ if (param != 0)
+ duration = param;
+
+ if (spi_test_scenario_mode != SPI_TEST_SCENARIO_SLAVE_SENDING)
+ data = (char *)spi_os_malloc(databystep[step].size);
+
+ spi_os_memset(data, 0x00, databystep[step].size);
+
+ SPI_OS_TRACE_MID(("spi _scenario_sending step %d\n", step));
+
+ /* generate data to send, It is serial number from 0 to 99 */
+ for (i = 0 ; i < databystep[step].size ; i++)
+ data[i] = i%100;
+
+ do {
+#ifdef SPI_FEATURE_OMAP4430
+ if (spi_is_ready() != 0) {
+ struct spi_os_msg *msg;
+ SPI_MAIN_MSG_T signal_code;
+ signal_code = databystep[step].type;
+
+ msg = (struct spi_os_msg *)
+ spi_os_malloc(sizeof(struct spi_os_msg));
+ msg->signal_code = signal_code;
+ msg->data_length = databystep[step].size;
+ msg->data = data;
+
+ spi_receive_msg_from_app(msg);
+ spi_main_send_signal(signal_code);
+ break;
+ } else
+ spi_os_sleep(50);
+#elif defined SPI_FEATURE_SC8800G
+ if (app_send_data_to_spi(databystep[step].type,
+ data, databystep[step].size) == 0)
+ /* send fail */
+ spi_os_sleep(50);
+ else
+ /* send success */
+ break;
+#endif
+ } while (1);
+
+ if (spi_test_scenario_mode == SPI_TEST_SCENARIO_MASTER_SENDING)
+ return;
+
+ step++;
+ count++;
+ step %= NB_STEP;
+
+ if (timer_id == 0)
+ timer_id = spi_os_create_timer("spi_test_timer",
+ spi_test_timer_callback, step, duration);
+
+ if (timer_id == 0) {
+ SPI_OS_TRACE_MID(("spi _scenario_sending invalid timer id\n"));
+ return;
+ }
+
+ SPI_OS_TRACE_MID(("spi _scenario_sending timer %x\n", timer_id));
+ SPI_OS_TRACE_MID(("spi _scenario_sending start timer count %d\n",
+ count));
+
+ if (count == NB_COUNT) {
+ spi_os_stop_timer(timer_id);
+ return;
+ }
+
+ value = spi_os_start_timer(timer_id, spi_test_timer_callback,
+ step, duration);
+ SPI_OS_TRACE_MID(("spi _scenario_sending start timer%d\n", value));
+
+ #undef NB_STEP
+}
+
+
+void spi_test_run(enum SPI_TEST_SCENARIO_T scenario, int param)
+{
+ SPI_OS_TRACE_MID(("spi_test_run %d\n", (int) scenario));
+
+ if (scenario == SPI_TEST_SCENARIO_NONE)
+ return;
+
+ spi_test_scenario_mode = scenario;
+
+ switch ((int)scenario) {
+ case SPI_TEST_SCENARIO_PHYSICAL:
+ _scenario_physical();
+ break;
+ case SPI_TEST_SCENARIO_MASTER_SENDING:
+#ifdef SPI_FEATURE_MASTER
+ _scenario_sending(param);
+#endif
+ break;
+ case SPI_TEST_SCENARIO_SLAVE_SENDING:
+#ifdef SPI_FEATURE_SLAVE
+ _scenario_sending(param);
+#endif
+ break;
+ case SPI_TEST_SCENARIO_COMPLEX_SENDING:
+ _scenario_sending(param);
+ break;
+ case SPI_TEST_SCENARIO_NONE:
+ default:
+ break;
+ }
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_test.h b/drivers/phone_svn/ipc_spi/spi_test.h
new file mode 100644
index 0000000..251d057
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_test.h
@@ -0,0 +1,14 @@
+#ifndef __SPI_TEST_H__
+#define __SPI_TEST_H__
+
+enum SPI_TEST_SCENARIO_T {
+ SPI_TEST_SCENARIO_NONE,
+ SPI_TEST_SCENARIO_PHYSICAL,
+ SPI_TEST_SCENARIO_MASTER_SENDING,
+ SPI_TEST_SCENARIO_SLAVE_SENDING,
+ SPI_TEST_SCENARIO_COMPLEX_SENDING,
+};
+
+extern enum SPI_TEST_SCENARIO_T spi_test_scenario_mode;
+extern void spi_test_run(enum SPI_TEST_SCENARIO_T scenario, int param);
+#endif