aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/omap_hsi/hsi_protocol_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/omap_hsi/hsi_protocol_if.c')
-rw-r--r--drivers/omap_hsi/hsi_protocol_if.c896
1 files changed, 896 insertions, 0 deletions
diff --git a/drivers/omap_hsi/hsi_protocol_if.c b/drivers/omap_hsi/hsi_protocol_if.c
new file mode 100644
index 0000000..ced5dae
--- /dev/null
+++ b/drivers/omap_hsi/hsi_protocol_if.c
@@ -0,0 +1,896 @@
+/*
+ * File - hsi_protocol_if.c
+ *
+ * Implements HSI protocol for Infineon Modem.
+ *
+ * Copyright (C) 2011 Samsung Electronics.
+ *
+ * Author: Rupesh Gujare <rupesh.g@samsung.com>
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/bitmap.h>
+#include <linux/poll.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+
+#include <linux/hsi_driver_if.h>
+#include "hsi-protocol-if.h"
+
+//#define DEBUG 1
+//#define DEBUG_PHY_DATA 1
+
+#define HSI_CHANNEL_STATE_UNAVAIL (1 << 0)
+#define HSI_CHANNEL_STATE_READING (1 << 1)
+#define HSI_CHANNEL_STATE_WRITING (1 << 2)
+
+
+struct if_hsi_iface hsi_protocol_iface;
+wait_queue_head_t ipc_read_wait, ipc_write_wait;
+
+
+static void if_hsi_protocol_port_event(struct hsi_device *dev, unsigned int event,
+ void *arg);
+static int __devinit hsi_protocol_probe(struct hsi_device *dev);
+static int __devexit hsi_protocol_remove(struct hsi_device *dev);
+
+static struct hsi_device_driver if_hsi_protocol_driver = {
+ .ctrl_mask = ANY_HSI_CONTROLLER,
+ .probe = hsi_protocol_probe,
+ .remove = __devexit_p(hsi_protocol_remove),
+ .driver = {
+ .name = "hsi_protocol"
+ },
+};
+
+struct if_hsi_cmd hsi_cmd_history;
+int tx_cmd_history_p = 0;
+int rx_cmd_history_p = 0;
+
+static int if_hsi_read_on(int ch, u32 *data, unsigned int count)
+{
+ struct if_hsi_channel *channel;
+ int ret;
+
+ channel = &hsi_protocol_iface.channels[ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch);
+
+ spin_lock(&channel->lock);
+ if (channel->state & HSI_CHANNEL_STATE_READING) {
+ pr_err("Read still pending on channel %d\n", ch);
+ spin_unlock(&channel->lock);
+ return -EBUSY;
+ }
+ channel->state |= HSI_CHANNEL_STATE_READING;
+ channel->rx_data = data;
+ channel->rx_count = count;
+ spin_unlock(&channel->lock);
+
+ ret = hsi_read(channel->dev, data, count / 4);
+ dev_dbg(&channel->dev->device, "%s, ch = %d, ret = %d\n", __func__, ch,
+ ret);
+
+ return ret;
+}
+
+static void if_hsi_proto_read_done(struct hsi_device *dev, unsigned int size)
+{
+ struct if_hsi_channel *channel;
+ struct hsi_event ev;
+
+#ifdef DEBUG_PHY_DATA
+ u32 *tmp;
+ u32 i;
+#endif
+
+ //printk(KERN_INFO "if_hsi_proto_read_done() is called for ch-> %d\n", dev->n_ch);
+ channel = &hsi_protocol_iface.channels[dev->n_ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, dev->n_ch);
+ spin_lock(&channel->lock);
+ channel->state &= ~HSI_CHANNEL_STATE_READING;
+ ev.event = HSI_EV_IN;
+ ev.data = channel->rx_data;
+ ev.count = 4 * size;
+ spin_unlock(&channel->lock);
+
+#ifdef DEBUG_PHY_DATA
+ //Check received data -> Commented as it adds delay which causes MSG_BREAK
+ tmp = channel->rx_data;
+ printk(KERN_INFO "[%s](%d)(%d) RX = ", __func__, dev->n_ch, ev.count);
+ for (i = 0; i < ((size > 5) ? 5 : size); i++) {
+ printk(KERN_INFO "%08x ", *tmp);
+ tmp++;
+ }
+ printk(KERN_INFO "\n");
+#endif
+
+ if_notify(dev->n_ch, &ev);
+}
+
+int if_hsi_read(int ch, u32 *data, unsigned int count)
+{
+ int ret = 0;
+ struct if_hsi_channel *channel;
+ channel = &hsi_protocol_iface.channels[ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch);
+ ret = if_hsi_read_on(ch, data, count);
+ return ret;
+}
+
+int if_hsi_poll(int ch)
+{
+ struct if_hsi_channel *channel;
+ int ret = 0;
+ channel = &hsi_protocol_iface.channels[ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch);
+ ret = hsi_poll(channel->dev);
+ return ret;
+}
+
+static int if_hsi_write_on(int ch, u32 *address, unsigned int count)
+{
+ struct if_hsi_channel *channel;
+ int ret;
+
+ channel = &hsi_protocol_iface.channels[ch];
+
+ spin_lock(&channel->lock);
+ if (channel->state & HSI_CHANNEL_STATE_WRITING) {
+ pr_err("Write still pending on channel %d\n", ch);
+ printk(KERN_INFO "Write still pending on channel %d\n", ch);
+ spin_unlock(&channel->lock);
+ return -EBUSY;
+ }
+
+ channel->tx_data = address;
+ channel->tx_count = count;
+ channel->state |= HSI_CHANNEL_STATE_WRITING;
+ spin_unlock(&channel->lock);
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch);
+ ret = hsi_write(channel->dev, address, count / 4);
+ return ret;
+}
+
+
+static void if_hsi_proto_write_done(struct hsi_device *dev, unsigned int size)
+{
+ struct if_hsi_channel *channel;
+ struct hsi_event ev;
+
+#ifdef DEBUG_PHY_DATA
+ u32 *tmp;
+ u32 i;
+#endif
+
+ //printk(KERN_INFO "if_hsi_proto_write_done() is called for ch-> %d\n", dev->n_ch);
+ channel = &hsi_protocol_iface.channels[dev->n_ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, dev->n_ch);
+
+ spin_lock(&channel->lock);
+ channel->state &= ~HSI_CHANNEL_STATE_WRITING;
+ ev.event = HSI_EV_OUT;
+ ev.data = channel->tx_data;
+ ev.count = 4 * size;
+ spin_unlock(&channel->lock);
+
+#ifdef DEBUG_PHY_DATA
+ //Check Outgoing data, Commented as it adds delay which causes MSG_BREAK
+ tmp = channel->tx_data;
+ printk(KERN_INFO "[%s](%d)(%d) TX = ", __func__, dev->n_ch, ev.count);
+ for (i = 0; i < ((size > 5) ? 5 : size); i++) {
+ printk(KERN_INFO "%08x ", *tmp);
+ tmp++;
+ }
+ printk(KERN_INFO "\n");
+#endif
+
+ if_notify(dev->n_ch, &ev);
+
+}
+
+int if_hsi_write(int ch, u32 *data, unsigned int count)
+{
+ int ret = 0;
+ struct if_hsi_channel *channel;
+ channel = &hsi_protocol_iface.channels[ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch);
+ ret = if_hsi_write_on(ch, data, count);
+ return ret;
+}
+
+void if_hsi_cancel_read(int ch)
+{
+ struct if_hsi_channel *channel;
+ channel = &hsi_protocol_iface.channels[ch];
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__, ch);
+ if (channel->state & HSI_CHANNEL_STATE_READING)
+ hsi_read_cancel(channel->dev);
+ spin_lock(&channel->lock);
+ channel->state &= ~HSI_CHANNEL_STATE_READING;
+ spin_unlock(&channel->lock);
+}
+
+void if_hsi_set_wakeline(int ch, unsigned int state)
+{
+ struct if_hsi_channel *channel;
+ channel = &hsi_protocol_iface.channels[ch];
+ hsi_ioctl(channel->dev,
+ state ? HSI_IOCTL_ACWAKE_UP : HSI_IOCTL_ACWAKE_DOWN, NULL);
+}
+
+
+static void if_hsi_protocol_port_event(struct hsi_device *dev, unsigned int event,
+ void *arg)
+{
+ struct hsi_event ev;
+ int i;
+
+ ev.event = HSI_EV_EXCEP;
+ ev.data = (u32 *) 0;
+ ev.count = 0;
+
+
+ switch (event) {
+ case HSI_EVENT_BREAK_DETECTED:
+ pr_debug("%s, HWBREAK detected\n", __func__);
+ ev.data = (u32 *) HSI_HWBREAK;
+ for (i = 0; i < HSI_MAX_CHANNELS; i++) {
+ if (hsi_protocol_iface.channels[i].opened)
+ if_notify(i, &ev);
+ }
+ break;
+ case HSI_EVENT_HSR_DATAAVAILABLE:
+ i = (int)arg;
+ pr_debug("%s, HSI_EVENT_HSR_DATAAVAILABLE channel = %d\n",
+ __func__, i);
+ ev.event = HSI_EV_AVAIL;
+ if (hsi_protocol_iface.channels[i].opened)
+ if_notify(i, &ev);
+ break;
+ case HSI_EVENT_CAWAKE_UP:
+ pr_debug("%s, CAWAKE up\n", __func__);
+ break;
+ case HSI_EVENT_CAWAKE_DOWN:
+ pr_debug("%s, CAWAKE down\n", __func__);
+ break;
+ case HSI_EVENT_ERROR:
+ pr_debug("%s, HSI ERROR occured\n", __func__);
+ break;
+ default:
+ pr_warning("%s, Unknown event(%d)\n", __func__, event);
+ break;
+ }
+}
+
+int if_hsi_openchannel(struct if_hsi_channel *channel)
+{
+ int ret = 0;
+
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__,
+ channel->channel_id);
+ spin_lock(&channel->lock);
+
+ if (channel->state == HSI_CHANNEL_STATE_UNAVAIL) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ if (channel->opened) {
+ ret = -EBUSY;
+ goto leave;
+ }
+
+ if (!channel->dev) {
+ pr_err("Channel %d is not ready??\n", channel->channel_id);
+ ret = -ENODEV;
+ goto leave;
+ }
+ spin_unlock(&channel->lock);
+
+ ret = hsi_open(channel->dev);
+ spin_lock(&channel->lock);
+ if (ret < 0) {
+ pr_err("Could not open channel %d\n", channel->channel_id);
+ goto leave;
+ }
+
+ channel->opened = 1;
+ channel->tx_state = HSI_LL_TX_STATE_IDLE;
+ channel->rx_state = HSI_LL_RX_STATE_TO_CONN_READY;
+ printk(KERN_INFO "setting channel->opened=1 for channel %d\n", channel->dev->n_ch);
+leave:
+ spin_unlock(&channel->lock);
+ return ret;
+}
+
+int if_hsi_closechannel(struct if_hsi_channel *channel)
+{
+ int ret = 0;
+
+ dev_dbg(&channel->dev->device, "%s, ch = %d\n", __func__,
+ channel->channel_id);
+ spin_lock(&channel->lock);
+
+ if (!channel->opened)
+ goto leave;
+
+ if (!channel->dev) {
+ pr_err("Channel %d is not ready??\n", channel->channel_id);
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ /* Stop any pending read/write */
+ if (channel->state & HSI_CHANNEL_STATE_READING) {
+ channel->state &= ~HSI_CHANNEL_STATE_READING;
+ spin_unlock(&channel->lock);
+ hsi_read_cancel(channel->dev);
+ spin_lock(&channel->lock);
+ }
+ if (channel->state & HSI_CHANNEL_STATE_WRITING) {
+ channel->state &= ~HSI_CHANNEL_STATE_WRITING;
+
+ spin_unlock(&channel->lock);
+ hsi_write_cancel(channel->dev);
+ } else
+ spin_unlock(&channel->lock);
+
+ hsi_close(channel->dev);
+
+ spin_lock(&channel->lock);
+ channel->opened = 0;
+ channel->tx_state = HSI_LL_TX_STATE_CLOSED;
+ channel->rx_state = HSI_LL_RX_STATE_CLOSED;
+leave:
+ spin_unlock(&channel->lock);
+ return ret;
+}
+
+
+/* Read Thread
+* Should be responsible for handling commands
+* Should wait on port events - waitqueue
+*
+*/
+static int hsi_read_thrd(void *data)
+{
+ u32 cmd_data[4], cmd, channel, param = 0;
+ int ret;
+
+ printk(KERN_INFO "Inside read thread\n");
+ while (1) {
+ /*Call hsi_proto_read*/
+ /*Read 16 bytes due to Modem limitation*/
+ //hsi_proto_read(0, cmd_data, (4 * 4));
+
+ // For es 2.1 ver.
+ hsi_proto_read(0, cmd_data, 4);
+
+ hsi_cmd_history.rx_cmd[rx_cmd_history_p] = cmd_data[0];
+ hsi_cmd_history.rx_cmd_time[rx_cmd_history_p] = CURRENT_TIME;
+ rx_cmd_history_p++;
+ if (rx_cmd_history_p >= 50)
+ rx_cmd_history_p = 0;
+
+ /*Decode Command*/
+ ret = hsi_decode_cmd(&cmd_data[0], &cmd, &channel, &param);
+ if (ret != 0) {
+ pr_err("Can not decode command\n");
+ } else {
+ printk(KERN_INFO "%s(),CMD Received-> %x, ch-> %d, param-> %d.\n", __func__, cmd, channel, param);
+ /*Rx State Machine*/
+ rx_stm(cmd, channel, param);
+ }
+ }
+ return 0;
+}
+
+
+int hsi_start_protocol(void)
+{
+ struct hst_ctx tx_config;
+ struct hsr_ctx rx_config;
+ int i, ret = 0;
+
+ printk(KERN_INFO "In function %s()\n", __func__);
+ /*Open All channels */
+ for (i = 0; i <= 5; i++) {
+ ret = if_hsi_openchannel(&hsi_protocol_iface.channels[i]);
+ if (ret < 0)
+ pr_err("Can not Open channel->%d . Can not start HSI protocol\n", i);
+ else
+ printk(KERN_INFO "Channel->%d Open Successful\n", i);
+
+ /*Set Rx Config*/
+ hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_GET_RX, &rx_config);
+ rx_config.mode = 2;
+ rx_config.divisor = 1;
+ rx_config.channels = HSI_MAX_CHANNELS;
+ ret = hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_SET_RX, &rx_config);
+ if (ret == 0)
+ printk(KERN_INFO "SET_RX Successful for ch->%d\n", i);
+
+ /*Set Tx Config*/
+ hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_GET_TX, &tx_config);
+ tx_config.mode = 2;
+ tx_config.divisor = 1;
+ tx_config.channels = HSI_MAX_CHANNELS;
+ ret = hsi_ioctl(hsi_protocol_iface.channels[i].dev, HSI_IOCTL_SET_TX, &tx_config);
+ if (ret == 0)
+ printk(KERN_INFO "SET_TX Successful for ch->%d\n", i);
+ }
+ /*Make channel-0 tx_state to IDLE*/
+ hsi_protocol_iface.channels[0].tx_state = HSI_LL_TX_STATE_IDLE;
+ return ret;
+}
+EXPORT_SYMBOL(hsi_start_protocol);
+
+static int hsi_protocol_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ char *p = page;
+ int len, i;
+
+ p += sprintf(p, "======= HISTORY OF CMD =======\n");
+ p += sprintf(p, " tx_cmd_history_p : %d\n", tx_cmd_history_p);
+ p += sprintf(p, " rx_cmd_history_p : %d\n", rx_cmd_history_p);
+ for (i = 0; i < 50; i++) {
+ p += sprintf(p, " [%d] tx : 0x%08x(%lu.%09lu), rx : 0x%08x(%lu.%09lu)\n",
+ i, hsi_cmd_history.tx_cmd[i], (unsigned long)hsi_cmd_history.tx_cmd_time[i].tv_sec, (unsigned long)hsi_cmd_history.tx_cmd_time[i].tv_nsec,
+ hsi_cmd_history.rx_cmd[i], (unsigned long)hsi_cmd_history.rx_cmd_time[i].tv_sec, (unsigned long)hsi_cmd_history.rx_cmd_time[i].tv_nsec);
+ }
+ p += sprintf(p, "======= HISTORY OF CMD =======\n");
+
+ len = (p - page) - off;
+ if (len < 0)
+ len = 0;
+
+ *eof = (len <= count) ? 1 : 0;
+ *start = page + off;
+
+ return len;
+}
+
+int __devexit hsi_protocol_remove(struct hsi_device *dev)
+{
+ struct if_hsi_channel *channel;
+ unsigned long *address;
+ int port, ret;
+
+ //dev_dbg(&dev->device, "%s, port = %d, ch = %d\n", __func__, dev->n_p,
+ // dev->n_ch);
+
+ for (port = 0; port < HSI_MAX_PORTS; port++) {
+ if (if_hsi_protocol_driver.ch_mask[port])
+ break;
+ }
+
+ address = &if_hsi_protocol_driver.ch_mask[port];
+
+ spin_lock_bh(&hsi_protocol_iface.lock);
+ if (test_bit(dev->n_ch, address) && (dev->n_p == port)) {
+ hsi_set_read_cb(dev, NULL);
+ hsi_set_write_cb(dev, NULL);
+ hsi_set_port_event_cb(dev, NULL);
+ channel = &hsi_protocol_iface.channels[dev->n_ch];
+ channel->dev = NULL;
+ channel->state = HSI_CHANNEL_STATE_UNAVAIL;
+ ret = 0;
+ }
+ spin_unlock_bh(&hsi_protocol_iface.lock);
+
+ return ret;
+}
+
+int __devinit hsi_protocol_probe(struct hsi_device *dev)
+{
+ struct if_hsi_channel *channel;
+ unsigned long *address;
+ int port;
+
+ printk(KERN_INFO "Inside Function %s\n", __func__);
+ for (port = 0; port < HSI_MAX_PORTS; port++) {
+ if (if_hsi_protocol_driver.ch_mask[port])
+ break;
+ }
+
+ address = &if_hsi_protocol_driver.ch_mask[port];
+
+ spin_lock_bh(&hsi_protocol_iface.lock);
+ if (test_bit(dev->n_ch, address) && (dev->n_p == port)) {
+ printk(KERN_INFO "Regestering callback functions\n");
+ hsi_set_read_cb(dev, if_hsi_proto_read_done);
+ hsi_set_write_cb(dev, if_hsi_proto_write_done);
+ hsi_set_port_event_cb(dev, if_hsi_protocol_port_event);
+ channel = &hsi_protocol_iface.channels[dev->n_ch];
+ channel->dev = dev;
+ channel->state = 0;
+ channel->rx_state = HSI_LL_RX_STATE_CLOSED;
+ channel->tx_state = HSI_LL_TX_STATE_CLOSED;
+ channel->tx_count = 0;
+ channel->rx_count = 0;
+ channel->tx_nak_count = 0;
+ channel->rx_nak_count = 0;
+ channel->rx_buf = NULL;
+ channel->tx_buf = NULL;
+ hsi_protocol_iface.init_chan_map ^= (1 << dev->n_ch);
+ }
+ spin_unlock_bh(&hsi_protocol_iface.lock);
+
+ return 0;
+
+}
+
+
+int __init if_hsi_init(void)
+{
+ struct if_hsi_channel *channel;
+ int i, ret;
+ struct proc_dir_entry *dir;
+
+ for (i = 0; i < HSI_MAX_PORTS; i++)
+ if_hsi_protocol_driver.ch_mask[i] = 0;
+
+ for (i = 0; i < HSI_MAX_CHANNELS; i++) {
+ channel = &hsi_protocol_iface.channels[i];
+ channel->dev = NULL;
+ channel->opened = 0;
+ channel->state = HSI_CHANNEL_STATE_UNAVAIL;
+ channel->channel_id = i;
+ spin_lock_init(&channel->lock);
+ }
+
+ /*Initialize waitqueue for IPC read*/
+ init_waitqueue_head(&ipc_read_wait);
+ init_waitqueue_head(&ipc_write_wait);
+
+ /*Select All Channels of PORT-1.*/
+ if_hsi_protocol_driver.ch_mask[0] = CHANNEL_MASK;
+
+ ret = hsi_register_driver(&if_hsi_protocol_driver);
+ if (ret)
+ pr_err("Error while registering HSI driver %d", ret);
+
+ dir = create_proc_read_entry("driver/hsi_cmd", 0, 0, hsi_protocol_proc, NULL);
+ if (dir == NULL)
+ printk(KERN_INFO "create_proc_read_entry Fail.\n");
+ printk(KERN_INFO "create_proc_read_entry Done.\n");
+
+ return ret;
+}
+
+int __devexit if_hsi_exit(void)
+{
+ struct if_hsi_channel *channel;
+ unsigned long *address;
+ int i, port;
+
+ pr_debug("%s\n", __func__);
+
+ for (port = 0; port < HSI_MAX_PORTS; port++) {
+ if (if_hsi_protocol_driver.ch_mask[port])
+ break;
+ }
+
+ address = &if_hsi_protocol_driver.ch_mask[port];
+
+ for (i = 0; i < HSI_MAX_CHANNELS; i++) {
+ channel = &hsi_protocol_iface.channels[i];
+ if (channel->opened) {
+ if_hsi_set_wakeline(i, HSI_IOCTL_ACWAKE_DOWN);
+ if_hsi_closechannel(channel);
+ }
+ }
+
+ hsi_unregister_driver(&if_hsi_protocol_driver);
+ return 0;
+
+}
+
+u32 initialization = 0;
+
+/*Write data to channel*/
+int write_hsi(u32 ch, u32 *data, int length)
+{
+ int ret;
+ //u32 cmd[4] = {0x00000000, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC};
+ struct if_hsi_channel *channel;
+ struct task_struct *read_thread;
+
+ channel = &hsi_protocol_iface.channels[ch];
+ channel->tx_buf = data;
+ channel->tx_count = 0;
+
+ //cmd[0] = protocol_create_cmd(HSI_LL_MSG_OPEN_CONN_OCTET, ch, (void *)&length);
+ //printk(KERN_INFO "data ptr is %x\n", data);
+
+ if (initialization == 0) {
+
+#if 0
+ /* ACWAKE ->HIGH */
+ ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL);
+ if (ret == 0)
+ printk(KERN_INFO "ACWAKE pulled high in %s()\n", __func__);
+ else
+ printk(KERN_INFO "ACWAKE pulled high in %s() ERROR : %d\n", __func__, ret);
+#endif
+
+ /*Creating read thread*/
+ read_thread = kthread_run(hsi_read_thrd, NULL, "hsi_read_thread");
+
+ initialization++;
+ }
+ /*Wait till previous data transfer is over*/
+ while (channel->tx_state != HSI_LL_TX_STATE_IDLE) {
+ //printk(KERN_INFO "Wait 5ms previous data transfer isn't over %s()\n", __func__);
+
+ //msleep(5);
+
+ return -EAGAIN;
+ }
+
+#if 1
+ /* ACWAKE ->HIGH */
+ ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL);
+ if (ret == 0)
+ printk(KERN_INFO "ACWAKE pulled high in %s()\n", __func__);
+ else
+ printk(KERN_INFO "ACWAKE pulled high in %s() ERROR : %d\n", __func__, ret);
+#endif
+
+ channel->tx_state = HSI_LL_TX_STATE_WAIT_FOR_ACK;
+
+ //send_cmd(cmd, channel, data)
+ //ret = hsi_proto_write(0, &cmd, 4*4);
+ //printk(KERN_INFO "Write returned %d\n", ret);
+ hsi_protocol_send_command(HSI_LL_MSG_OPEN_CONN_OCTET, ch, length);
+
+ wait_event_interruptible(ipc_write_wait, channel->tx_count != 0);
+
+ return channel->tx_count;
+
+
+}
+EXPORT_SYMBOL(write_hsi);
+
+
+int read_hsi(u8 *data, u32 ch, u32 *length)
+{
+ int ret, size, tmp, actual_length;
+ struct if_hsi_channel *channel;
+
+ channel = &hsi_protocol_iface.channels[ch];
+ channel->rx_state = HSI_LL_RX_STATE_IDLE;
+
+ //printk(KERN_INFO "In read_hsi() function, Sleeping ... channel-> %d\n", ch);
+ wait_event_interruptible(ipc_read_wait, (channel->rx_count != 0));
+ //printk(KERN_INFO "In read_hsi() function, Waking Up ... channel-> %d\n", ch);
+
+ actual_length = channel->rx_count;
+ size = channel->rx_count;
+
+#if 0
+ // TEMP: send/read by 16 byte unit for v.11A(CP)
+ if ((size > 16) && (size % 16))
+ size += (16 - (size % 16));
+ else if (size < 16)
+ size = 16;
+#endif
+
+ // For es 2.1 ver.
+ if (size % 4)
+ size += (4 - (size % 4));
+
+ ret = hsi_proto_read(ch, (u32 *)data, size);
+ if (ret < 0)
+ printk(KERN_INFO "Read in IPC failed, %s()\n", __func__);
+
+ //printk(KERN_INFO "%s() read returned %d, actual_length = %d, ch-> %d\n", __func__, ret, actual_length, ch);
+ //printk(KERN_INFO "%s() sending CONN_CLOSED.\n", __func__);
+ tmp = hsi_protocol_send_command(HSI_LL_MSG_CONN_CLOSED, ch, 0);
+ //printk(KERN_INFO "%s() Sending CONN_CLOSED Finished. ret = %d\n", __func__, tmp);
+
+ *length = actual_length;
+ channel->rx_count = 0;
+
+ //printk(KERN_INFO "%s() RETURNING TO IPC with ret = %d\n", __func__, ret);
+ return ret;
+
+}
+EXPORT_SYMBOL(read_hsi);
+
+
+//========================================================//
+// ++ Flashless Boot. ++ //
+//========================================================//
+int hsi_start_protocol_single(void)
+{
+ int ret = 0;
+
+ struct hst_ctx tx_config;
+ struct hsr_ctx rx_config;
+
+ /*Open channel 0 */
+ ret = if_hsi_openchannel(&hsi_protocol_iface.channels[0]);
+ if (ret < 0) {
+ pr_err("Can not Open channel 0. Can not start HSI protocol\n");
+ goto err;
+ } else
+ printk(KERN_INFO "if_hsi_openchannel() returned %d\n", ret);
+
+
+ /*Set Tx Config*/
+ hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_TX, &tx_config);
+ tx_config.mode = 2;
+ tx_config.channels = 1;
+ tx_config.divisor = 0;
+ ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_TX, &tx_config);
+ if (ret < 0) {
+ printk(KERN_INFO "write_hsi_direct : SET_TX Fail : %d\n", ret);
+ return ret;
+ }
+
+ hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_RX, &rx_config);
+ rx_config.mode = 2;
+ rx_config.channels = 1;
+ rx_config.divisor = 0;
+ //rx_config.timeout = HZ / 2;
+ ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_RX, &rx_config);
+ if (ret < 0) {
+ printk(KERN_INFO "write_hsi_direct : SET_RX Fail : %d\n", ret);
+ return ret;
+ }
+
+ /* ACWAKE ->HIGH */
+ ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL);
+ if (ret == 0)
+ printk(KERN_INFO "ACWAKE pulled high in %s()\n", __func__);
+
+err:
+
+ return ret;
+}
+EXPORT_SYMBOL(hsi_start_protocol_single);
+
+int hsi_reconfigure_protocol(void)
+{
+ int ret = 0;
+
+ /* ACWAKE ->LOW */
+ ret = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_DOWN, NULL);
+ if (ret == 0)
+ printk(KERN_INFO "ACWAKE pulled low in %s()\n", __func__);
+ else
+ printk(KERN_INFO "ACWAKE down fail!! %d\n", ret);
+
+
+ /*Clse channel 0 */
+ ret = if_hsi_closechannel(&hsi_protocol_iface.channels[0]);
+ if (ret < 0) {
+ pr_err("Can not Close channel 0. Can not Stop HSI protocol for flashless\n");
+ goto err;
+ }
+
+
+ printk(KERN_INFO "(%s)(%d) hsi_start_protocol Start.\n", __func__, __LINE__);
+ hsi_start_protocol();
+ printk(KERN_INFO "(%s)(%d) hsi_start_protocol Done.\n", __func__, __LINE__);
+
+err:
+
+ return ret;
+}
+EXPORT_SYMBOL(hsi_reconfigure_protocol);
+
+int write_hsi_direct(u32 *data, int length)
+{
+ int retval = 0;
+#if 0
+ struct hst_ctx tx_config;
+
+
+ printk(KERN_INFO "write_hsi_direct : len : %d\n", length);
+ hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_TX, &tx_config);
+ tx_config.mode = 2;
+ tx_config.channels = 1;
+ tx_config.divisor = 47;
+ retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_TX, &tx_config);
+ if (retval < 0) {
+ printk(KERN_INFO "write_hsi_direct : SET_TX Fail : %d\n", retval);
+ return retval;
+ }
+ printk(KERN_INFO "write_hsi_direct : SET_TX Successful\n");
+
+ retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL);
+ if (retval < 0) {
+ printk(KERN_INFO "write_hsi_direct : ACWAKE High Fail : %d\n", retval);
+ return retval;
+ }
+#endif
+
+#if 0
+ if ((length > 16) && (length % 4))
+ length += (4 - (length % 4));
+ else if (length < 16)
+ length = 16;
+#endif
+
+// printk(KERN_INFO "write_hsi_direct : new len : %d\n", length);
+
+ retval = hsi_proto_write(0, data, length);
+ if (retval < 0) {
+ printk(KERN_INFO "write_hsi_direct : hsi_proto_write Fail : %d\n", retval);
+ return retval;
+ }
+ //printk(KERN_INFO "write_hsi_direct : Write returned %d\n", retval);
+
+ return retval;
+}
+EXPORT_SYMBOL(write_hsi_direct);
+
+int read_hsi_direct(u32 *data, int length)
+{
+ int retval = 0;
+#if 0
+ struct hsr_ctx rx_config;
+
+
+ printk(KERN_INFO "read_hsi_direct : len : %d\n", length);
+ hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_GET_RX, &rx_config);
+ rx_config.mode = 2;
+ rx_config.channels = 1;
+ rx_config.divisor = 47;
+ retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_SET_RX, &rx_config);
+ if (retval < 0) {
+ printk(KERN_INFO "read_hsi_direct : SET_RX Fail : %d\n", retval);
+ return retval;
+ }
+ printk(KERN_INFO "read_hsi_direct : SET_RX Successful\n");
+
+ retval = hsi_ioctl(hsi_protocol_iface.channels[0].dev, HSI_IOCTL_ACWAKE_UP, NULL);
+ if (retval < 0) {
+ printk(KERN_INFO "read_hsi_direct : ACWAKE High Fail : %d\n", retval);
+ return retval;
+ }
+ printk(KERN_INFO "read_hsi_direct : ACWAKE High\n");
+#endif
+
+#if 0
+ if ((length > 16) && (length % 4))
+ length += (4 - (length % 4));
+ else if (length < 16)
+ length = 16;
+#endif
+ //printk(KERN_INFO "read_hsi_direct : new len : %d\n", length);
+
+ retval = hsi_proto_read(0, data, length);
+ if (retval < 0) {
+ printk(KERN_INFO "read_hsi_direct : hsi_proto_read Fail : %d\n", retval);
+ return retval;
+ }
+ //printk(KERN_INFO "read_hsi_direct : Read returned %d\n", retval);
+
+ return retval;
+}
+EXPORT_SYMBOL(read_hsi_direct);
+
+//========================================================//
+// -- Flashless Boot. -- //
+//========================================================//