⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sm_drv_spi.c

📁 cx3110 drivers for linux 2.6 (基于SPI)
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -