aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/cmc7xx/hardware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wimax/cmc7xx/hardware.c')
-rwxr-xr-xdrivers/net/wimax/cmc7xx/hardware.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/drivers/net/wimax/cmc7xx/hardware.c b/drivers/net/wimax/cmc7xx/hardware.c
new file mode 100755
index 0000000..87100d4
--- /dev/null
+++ b/drivers/net/wimax/cmc7xx/hardware.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "headers.h"
+#include "download.h"
+
+static irqreturn_t wimax_hostwake_isr(int irq, void *dev)
+{
+ struct net_adapter *adapter = dev;
+ wake_lock_timeout(&adapter->pdata->g_cfg->wimax_wake_lock, 1 * HZ);
+
+ return IRQ_HANDLED;
+}
+
+static int cmc732_setup_wake_irq(struct net_adapter *adapter)
+{
+ struct wimax732_platform_data *pdata = adapter->pdata;
+ int rc;
+ int irq;
+
+ rc = gpio_request(pdata->wimax_int, "gpio_wimax_int");
+ if (rc < 0) {
+ pr_debug("%s: gpio %d request failed (%d)\n",
+ __func__, pdata->wimax_int, rc);
+ return rc;
+ }
+
+ rc = gpio_direction_input(pdata->wimax_int);
+ if (rc < 0) {
+ pr_debug("%s: failed to set gpio %d as input (%d)\n",
+ __func__, pdata->wimax_int, rc);
+ goto err_gpio_direction_input;
+ }
+
+ irq = gpio_to_irq(pdata->wimax_int);
+
+ rc = request_threaded_irq(irq, NULL, wimax_hostwake_isr,
+ IRQF_TRIGGER_FALLING, "wimax_int", adapter);
+ if (rc < 0) {
+ pr_debug("%s: request_irq(%d) failed for gpio %d (%d)\n",
+ __func__, irq,
+ pdata->wimax_int, rc);
+ goto err_request_irq;
+ }
+
+ rc = enable_irq_wake(irq);
+ if (rc < 0) {
+ pr_err("%s: enable_irq_wake(%d) failed for gpio %d (%d)\n",
+ __func__, irq, pdata->wimax_int, rc);
+ goto err_enable_irq_wake;
+ }
+
+ adapter->wake_irq = irq;
+
+ return 0;
+
+err_enable_irq_wake:
+ free_irq(irq, adapter);
+err_request_irq:
+err_gpio_direction_input:
+ gpio_free(pdata->wimax_int);
+ return rc;
+}
+
+static void cmc732_release_wake_irq(struct net_adapter *adapter)
+{
+ if (!adapter->wake_irq)
+ return;
+
+ disable_irq_wake(adapter->wake_irq);
+ free_irq(adapter->wake_irq, adapter);
+ gpio_free(adapter->pdata->wimax_int);
+}
+
+int wimax_hw_start(struct net_adapter *adapter)
+{
+ int retry = 0;
+ struct wimax732_platform_data *pdata = adapter->pdata;
+
+ pdata->g_cfg->wimax_status = WIMAX_STATE_READY;
+ adapter->download_complete = false;
+
+ adapter->rx_task = kthread_create(
+ cmc732_receive_thread, adapter, "%s",
+ "cmc732_receive_thread");
+
+ adapter->tx_task = kthread_create(
+ cmc732_send_thread, adapter, "%s",
+ "cmc732_send_thread");
+
+ init_waitqueue_head(&adapter->receive_event);
+ init_waitqueue_head(&adapter->send_event);
+
+ if (adapter->rx_task && adapter->tx_task) {
+ wake_up_process(adapter->rx_task);
+ wake_up_process(adapter->tx_task);
+ } else {
+ pr_debug("Unable to create send-receive threads");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (load_wimax_image(pdata->g_cfg->wimax_mode, adapter))
+ return STATUS_UNSUCCESSFUL;
+
+ if (adapter->downloading) {
+
+ while (!adapter->modem_resp) {
+ send_cmd_packet(adapter, MSG_DRIVER_OK_REQ);
+ wait_event_interruptible_timeout(
+ adapter->modem_resp_event,
+ adapter->modem_resp,
+ HZ/10);
+ if (!adapter->modem_resp)
+ pr_err("no modem response");
+ if (++retry > MODEM_RESP_RETRY)
+ goto download_fail;
+ }
+
+ switch (wait_event_interruptible_timeout(
+ adapter->download_event,
+ (adapter->download_complete),
+ HZ*FWDOWNLOAD_TIMEOUT)) {
+ case 0:
+ /* timeout */
+ pr_debug("Error wimax_hw_start : \
+ F/W Download timeout failed");
+ goto download_fail;
+ case -ERESTARTSYS:
+ /* Interrupted by signal */
+ pr_debug("Error wimax_hw_start :"
+ "-ERESTARTSYS retry");
+ goto download_fail;
+ default:
+ /* normal condition check */
+ if (adapter->removed || adapter->halted) {
+ pr_debug("Error wimax_hw_start : \
+ F/W Download surprise removed");
+ goto download_fail;
+ }
+ pr_debug("wimax_hw_start : F/W Download Complete");
+ unload_wimax_image(adapter);
+
+ if (cmc732_setup_wake_irq(adapter) < 0)
+ pr_debug("wimax_hw_start :"
+ "Error setting up wimax_int");
+
+ break;
+ }
+ adapter->downloading = false;
+ }
+
+ return STATUS_SUCCESS;
+
+download_fail:
+ adapter->halted = true;
+ wake_up_interruptible(&adapter->receive_event);
+ msleep(20);
+ unload_wimax_image(adapter);
+ return STATUS_UNSUCCESSFUL;
+}
+
+int wimax_hw_stop(struct net_adapter *adapter)
+{
+ adapter->halted = true;
+
+ /*Remove wakeup interrupt*/
+ cmc732_release_wake_irq(adapter);
+
+ /* Stop Sdio Interface */
+ sdio_claim_host(adapter->func);
+ sdio_release_irq(adapter->func);
+ sdio_disable_func(adapter->func);
+ sdio_release_host(adapter->func);
+
+ return STATUS_SUCCESS;
+}
+
+int wimax_hw_init(struct net_adapter *adapter)
+{
+ struct wimax732_platform_data *pdata = adapter->pdata;
+
+ /* set pdata->wimax_wakeup & pdata->wimax_if_mode0 */
+ pdata->set_mode();
+
+ /* initilize hardware info structure */
+ memset(&adapter->hw, 0x0, sizeof(struct hardware_info));
+
+ adapter->hw.receive_buffer = kzalloc(SDIO_BANK_SIZE, GFP_KERNEL);
+ if (adapter->hw.receive_buffer == NULL) {
+ pr_debug("kmalloc fail!!");
+ return -ENOMEM;
+ }
+
+ /* For sending data and control packets */
+ INIT_LIST_HEAD(&adapter->hw.q_send);
+ spin_lock_init(&adapter->hw.lock);
+
+ init_waitqueue_head(&adapter->download_event);
+ init_waitqueue_head(&adapter->modem_resp_event);
+ init_completion(&adapter->wakeup_event);
+
+ return STATUS_SUCCESS;
+}
+
+void wimax_hw_remove(struct net_adapter *adapter)
+{
+ struct buffer_descriptor *bufdsc;
+ struct list_head *pos, *nxt;
+
+ list_for_each_safe(pos, nxt, &adapter->hw.q_send) {
+ bufdsc = list_entry(pos, struct buffer_descriptor, list);
+ list_del(pos);
+ kfree(bufdsc->buffer);
+ kfree(bufdsc);
+ }
+
+ if (adapter->hw.receive_buffer != NULL)
+ kfree(adapter->hw.receive_buffer);
+
+}