📄 sm_drv_spi.c
字号:
/* * src/sm_drv_spi.c * * Copyright (C) 2003 Conexant Americas Inc. All Rights Reserved. * Copyright (C) 2004, 2005, 2006 Nokia Corporation * Author: Samuel Ortiz <samuel.ortiz@nokia.com> * * * 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. * */#define __KERNEL_SYSCALLS__#include <linux/version.h>#ifdef MODULE#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/module.h>#else#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT#endif#include <linux/init.h>#include <linux/netdevice.h>#include <linux/random.h>#include <linux/clk.h>#include <linux/spi/spi.h>#include <linux/platform_device.h>#include <linux/string.h>#include <linux/firmware.h>#include <linux/config.h>#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE)#error No Firmware Loading configured in the kernel !#endif#include <asm/irq.h>#include <asm/hardware.h>#include "sm_drv.h"#include "sm_drv_spi.h"#include "sm_drv_sysfs.h"#include "sm_drv_ioctl.h"#include "sm_drv_pda.h"#include "pda.h"static int sm_drv_spi_up(struct net_device *dev);static int sm_drv_spi_down(struct net_device *dev);static void sm_drv_spi_cli(struct net_device *dev);static void sm_drv_spi_initialize(struct net_device *dev);static void sm_drv_spi_reset_device(struct net_device *dev, unsigned boot);static irqreturn_t sm_drv_spi_interrupt(int irq, void *config, struct pt_regs *regs);static struct net_device *sm_drv_spi_probe(void);#define DRIVER_NAME "CX3110x"#define VERSIONID "0.8"const char driver_name[64] = DRIVER_NAME;char wlan_fw_version[32] = "N/A";char * firmware_file;struct omap_wlan_cx3110x_config * wlan_config;#define DEV_NAME "wlan%d"extern struct net_device *sm_net_device;extern unsigned int driver_type;static u8 wlan_wait_bit(struct net_device * dev, u16 reg, u32 mask, u32 expected ){ int i; char buffer[4]; for (i = 0; i < 2000; i++) { sm_spi_read(dev, reg, buffer, 4); if (((*(u32*)buffer) & mask) == expected){ return 1; } msleep(1); } return 0;}/****************************************************************************** * SPI Interconnect Handling (Bottom halve and helpers) ******************************************************************************/struct s_txdata { struct s_ic_msg *ic_msg; /* ic message associated with packet */ uint32_t ic_msg_flags;};extern struct completion softmac_init_comp;static int sm_drv_spi_wakeup(struct net_device *dev) { struct net_local *lp = dev->priv; uint32_t host_ints, host_ints_ack, target_ints; unsigned long timeout; int result; DEBUG(DBG_BH, "w\n"); /* Here we wake the target up */ target_ints = SPI_TARGET_INT_WAKEUP; sm_spi_write(dev, SPI_ADRS_ARM_INTERRUPTS, (unsigned char *)&target_ints, sizeof target_ints ); /* And wait for the READY interrupt */ timeout = jiffies + 2 * HZ; sm_spi_read(dev, SPI_ADRS_HOST_INTERRUPTS, (unsigned char *)&host_ints, sizeof(host_ints)); while (!(host_ints & SPI_HOST_INT_READY)) { DEBUG(DBG_BH, ".\n"); if (time_after(jiffies, timeout)) { printk(KERN_WARNING "We haven't got a READY interrupt" " from WAKEUP. (firmware crashed?)\n"); lp->device_state = DEVSTATE_DEAD; result = -1; goto exit; } sm_spi_read(dev, SPI_ADRS_HOST_INTERRUPTS, (unsigned char *)&host_ints, sizeof(host_ints)); } host_ints_ack = SPI_HOST_INT_READY; sm_spi_write(dev, SPI_ADRS_HOST_INT_ACK, (unsigned char *)&host_ints_ack, sizeof(host_ints_ack)); result = 0; exit: DEBUG(DBG_BH, "W\n"); return result;}static int sm_drv_spi_sleep(struct net_device *dev) { struct net_local *lp = dev->priv; uint32_t target_ints; /* The target can go back to sleep again */ target_ints = SPI_TARGET_INT_SLEEP; sm_spi_write(dev, SPI_ADRS_ARM_INTERRUPTS, (unsigned char *)&target_ints, sizeof(target_ints)); return 0;}static int sm_drv_spi_rx(struct net_device *dev) { struct net_local *lp = dev->priv; struct spi_hif_local_data *hif_lp = HIF_LP(lp); struct s_sm_frame *frame; struct s_ic_msg *ic_msg; int result, err; unsigned short length; int32_t callb_mask = 0; err = sm_drv_spi_wakeup(dev); if (err < 0) { result = -1; goto exit; } frame = frame_skb_alloc(dev, lp->sm_descr.mtu + lp->sm_descr.rxoffset, 0); if (frame != NULL) { ic_msg = FRAME_ICMSG(frame); ic_msg->frame = frame; /* dummy read to flush SPI DMA controller bug */ sm_spi_read(dev, SPI_ADRS_GEN_PURP_1, (unsigned char *)&length, sizeof(length)); sm_spi_read(dev, SPI_ADRS_DMA_DATA, (unsigned char *)&length, sizeof(length)); DEBUG(DBG_BH, "%s: received frame len=%d\n", DRIVER_NAME, length); if (length > SPI_MAX_PACKET_SIZE) length = SPI_MAX_PACKET_SIZE; sm_spi_dma_read(dev, SPI_ADRS_DMA_DATA, (unsigned char *) frame->data, length); ic_msg->channel = 0; ic_msg->flags = 0; ic_msg->length = length; ic_msg->address = 0; ic_msg->data = frame->data; hif_lp->spi_packets++; spin_lock_bh(&lp->sm_lock); callb_mask = prism_interconnect_message_handle(lp->sm_context, ic_msg); spin_unlock_bh(&lp->sm_lock); DEBUG(DBG_IC, "After prism_interconnect_message_handle" "(%d, %x, %d, %x, %p)\n", ic_msg->channel, ic_msg->flags, ic_msg->length, ic_msg->address, ic_msg->data); DEBUG(DBG_IC,"Callback mask: %d\n", callb_mask); if(callb_mask < 0) printk(KERN_WARNING "prism_interconnect_message_handle" "returned error %d\n", callb_mask); } else printk("Couldn't allocate RX frame\n"); handle_sm_callback(dev, callb_mask); result = 0;exit: return result;}static int sm_drv_spi_tx(struct net_device *dev) { struct net_local *lp = dev->priv; struct spi_hif_local_data *hif_lp = HIF_LP(lp); struct s_ic_msg *ic_msg; struct s_txdata txdata; struct s_dma_regs dma_regs; int32_t callb_mask = 0; uint32_t host_ints, host_ints_ack, ic_mask; unsigned long timeout; int result, err; /* See if the UMAC has ic messages pending for us to send */ while(1) { ic_mask = IC_MASK_CTRL | IC_MASK_FRAME; spin_lock_bh(&lp->sm_lock); callb_mask = prism_interconnect_message_query(lp->sm_context, ic_mask, &ic_msg); spin_unlock_bh(&lp->sm_lock); if (!ic_msg) { result = 0; goto exit; } DEBUG(DBG_IC, "prism_interconnect_message_query" "(%d, %x, %d, %x, %p)\n", ic_msg->channel, ic_msg->flags, ic_msg->length, ic_msg->address, ic_msg->data); err = sm_drv_spi_wakeup(dev); if (err < 0) { result = -1; goto exit; } /* Firmware bug...First TX packets needs to be horribly * delayed */ if (hif_lp->initial_packets < SPI_DELAY_THRESHOLD) mdelay(5); txdata.ic_msg_flags = ic_msg->flags; txdata.ic_msg = ic_msg; /* program DMA and transfer TX buffer */ dma_regs.cmd = SPI_DMA_WRITE_CTRL_ENABLE; dma_regs.len = cpu_to_le16(ic_msg->length); dma_regs.addr = cpu_to_le32(ic_msg->address); sm_spi_write(dev, SPI_ADRS_DMA_WRITE_CTRL, (unsigned char *) &dma_regs, sizeof(struct s_dma_regs)); sm_spi_dma_write(dev, SPI_ADRS_DMA_DATA, ic_msg->data, ic_msg->length); /* We wait for the DMA Ready interrupt */ host_ints = 0; sm_spi_read(dev, SPI_ADRS_HOST_INTERRUPTS, (unsigned char *) &host_ints, sizeof(host_ints)); timeout = jiffies + 2 * HZ; while(!(host_ints & SPI_HOST_INT_WR_READY)) { if (time_after(jiffies, timeout)) { printk(KERN_WARNING "cx3110x: Haven't got a " "WR_READY for DMA write." "(firmware crashed?)\n"); result = -1; goto exit; } sm_spi_read(dev, SPI_ADRS_HOST_INTERRUPTS, (unsigned char *) &host_ints, sizeof(host_ints)); } host_ints_ack = SPI_HOST_INT_WR_READY; sm_spi_write(dev, SPI_ADRS_HOST_INT_ACK, (unsigned char *)&host_ints_ack, sizeof(host_ints_ack)); DEBUG(DBG_BH, "%s: sent frame len=%d\n", DRIVER_NAME, ic_msg->length); if (txdata.ic_msg_flags & IC_FLAG_FREE) { if (txdata.ic_msg->frame) prism_driver_frame_free(lp->sm_context, txdata.ic_msg->frame); else prism_driver_free(lp->sm_context, txdata.ic_msg); } } handle_sm_callback(dev, callb_mask);exit: return result;}static void sm_drv_spi_tasklet_action(unsigned long data){ struct net_device *dev = (struct net_device *)data; struct net_local *lp = dev->priv; struct spi_hif_local_data *hif_lp = HIF_LP(lp); uint32_t host_ints, host_ints_en, host_ints_ack, target_ints; int err; HIF_CLK_USE(hif_lp); sm_spi_read(dev, SPI_ADRS_HOST_INTERRUPTS, (unsigned char *)&host_ints, sizeof(host_ints)); DEBUG(DBG_BH, "%s interrupts 0x%x\n", DRIVER_NAME, host_ints); if (host_ints & SPI_HOST_INT_READY) { host_ints_ack = SPI_HOST_INT_READY; sm_spi_write(dev, SPI_ADRS_HOST_INT_ACK, (unsigned char *)&host_ints_ack, sizeof(host_ints_ack)); if (hif_lp->upload_state == UPLOAD_STATE_BOOTING) { sm_drv_spi_initialize(dev); hif_lp->upload_state = UPLOAD_STATE_RUNNING; host_ints_en = SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE; sm_spi_write(dev, SPI_ADRS_HOST_INT_EN, (unsigned char *)&host_ints_en, sizeof(host_ints_en)); /* Now we can wait ifconfig...*/ complete(&softmac_init_comp); } } if (lp->sm_descr.mtu == 0) { DEBUG(DBG_BH, "%s SoftMAC not initialized\n", DRIVER_NAME); goto out; } /* Check if LMAC has rx frame */ if ((host_ints & SPI_HOST_INT_UPDATE) || (host_ints & SPI_HOST_INT_SW_UPDATE)) { host_ints_ack = SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE; sm_spi_write(dev, SPI_ADRS_HOST_INT_ACK, (unsigned char *)&host_ints_ack, sizeof(host_ints_ack)); err = sm_drv_spi_rx(dev); if (err < 0) goto out; } err = sm_drv_spi_tx(dev); if (err < 0) goto out;out: sm_drv_spi_sleep(dev); HIF_CLK_UNUSE(hif_lp);}/****************************************************************************** * Initialization and Firmware Upload. PDA loading too... ******************************************************************************/static void wlan_omap_device_release(struct device * dev){ }struct platform_device wlan_omap_device = { .name = "wlan-omap", .id = -1, .dev = { .release = wlan_omap_device_release, },};static int wlan_omap_suspend(struct device *dev, pm_message_t state){ return 0;#if 0 int ret = 0; uint32_t hibernate = 1; struct net_device * net_dev; struct net_local *lp; DEBUG(DBG_ALL, "WLAN suspending...\n"); net_dev = (struct net_device *)dev_get_drvdata(dev); lp = net_dev->priv; if (level == SUSPEND_POWER_DOWN && lp->sm_initialization) ret = sm_drv_oid_set((struct net_device *)dev_get_drvdata(dev), GEN_OID_HIBERNATE, &hibernate, sizeof(uint32_t)); return ret;#endif}static int wlan_omap_resume(struct device *dev){ return 0;#if 0 int ret = 0; uint32_t hibernate = 0; struct net_device * net_dev; struct net_local *lp; DEBUG(DBG_ALL, "WLAN resuming...\n"); net_dev = (struct net_device *)dev_get_drvdata(dev); lp = net_dev->priv; if (level == RESUME_POWER_ON && lp->sm_initialization) ret = sm_drv_oid_set((struct net_device *)dev_get_drvdata(dev), GEN_OID_HIBERNATE, &hibernate, sizeof(uint32_t)); return ret;#endif}static int __init wlan_drv_probe(struct device *dev){ return 0;}static int wlan_drv_remove(struct device *dev){ return 0;}static struct device_driver wlan_omap_driver = { .name = "wlan-omap", .bus = &platform_bus_type, .probe = wlan_drv_probe, .remove = wlan_drv_remove, .suspend = wlan_omap_suspend, .resume = wlan_omap_resume};int sm_drv_register_platform(struct net_device * sm_drv){ int ret; DEBUG(DBG_SYSFS, "Registering WLAN platform device\n"); ret = platform_device_register(&wlan_omap_device); if (ret) { printk("Couldn't register wlan_omap device\n"); return ret; } /* Our net_device will be our private data */ dev_set_drvdata(&(wlan_omap_device.dev), (void *)sm_drv); return 0;}void sm_drv_unregister_platform(void){ platform_device_unregister(&wlan_omap_device);}static int sm_drv_spi_up(struct net_device *dev){ DEBUG(DBG_CALLS, "%s\n", __FUNCTION__); DEBUG(DBG_ALL, "Loading %s firmware\n", firmware_file); if (sm_drv_spi_upload_firmware(dev) < 0) { DEBUG(DBG_ALL, "%s failed\n", firmware_file); return -1; } return 0;}static int sm_drv_spi_down(struct net_device *dev){ struct net_local *lp = dev->priv; struct spi_hif_local_data *hif_lp = HIF_LP(lp); DEBUG(DBG_CALLS, "%s\n", __FUNCTION__); HIF_CLK_USE(hif_lp); sm_drv_spi_reset_device(dev, 0); HIF_CLK_UNUSE(hif_lp); return 0;}static void sm_drv_spi_cli(struct net_device *dev){ struct net_local *lp = dev->priv; struct spi_hif_local_data *hif_lp = HIF_LP(lp); unsigned int host_reg; HIF_CLK_USE(hif_lp); host_reg = 0; sm_spi_write(dev, SPI_ADRS_HOST_INT_EN, (unsigned char *)&host_reg, sizeof host_reg ); cx3110x_disable_irq(dev); HIF_CLK_UNUSE(hif_lp);}static void sm_drv_spi_initialize(struct net_device *dev){ struct net_local *lp = dev->priv; struct s_sm_setup setup; unsigned long rand;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -