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

📄 sm_drv_spi_io.c

📁 cx3110 drivers for linux 2.6 (基于SPI)
💻 C
字号:
/* * src/sm_drv_spi_io.c * * SPI wrapper for Conexant Softmac driver. * * 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. * */#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/dma-mapping.h>#include <linux/clk.h>#include <linux/spi/spi.h>#include <asm/delay.h>#include <asm/string.h>#include <asm/irq.h>#include <asm/arch/gpio.h>#include <asm/arch/mcbsp.h>#include <asm/arch/dma.h>#include "sm_drv.h"#include "sm_drv_spi.h"#define WLAN_POWER_UP()   omap_set_gpio_dataout(wlan_config->power_gpio, 1);#define WLAN_POWER_DOWN() omap_set_gpio_dataout(wlan_config->power_gpio, 0);/* Bit 15 is read/write bit; ON = READ, OFF = WRITE */#define ADDR_READ_BIT_15  0x8000extern struct net_device *sm_net_device;extern struct omap_wlan_cx3110x_config * wlan_config;static void cx3110x_hw_reset(void){	WLAN_POWER_DOWN();	msleep(2);	WLAN_POWER_UP();	msleep(300);}int cx3110x_request_irq(irqreturn_t (*handler)(int, void *, struct pt_regs *),			const char * devname, void *dev_id){		int ret;		ret = request_irq(OMAP_GPIO_IRQ(wlan_config->irq_gpio),			  handler, SA_INTERRUPT , devname, dev_id);	if (ret < 0) {		printk(KERN_WARNING "%s could not install IRQ-handler %d\n", devname, ret);		return ret;	}		set_irq_type(OMAP_GPIO_IRQ(wlan_config->irq_gpio), IRQT_RISING);	return 0;}void cx3110x_free_irq(void *dev_id){	free_irq(OMAP_GPIO_IRQ(wlan_config->irq_gpio), dev_id);}void cx3110x_disable_irq(struct net_device *dev){	DEBUG(DBG_CALLS, "omap_wlan_disable_irq\n");		disable_irq(OMAP_GPIO_IRQ(wlan_config->irq_gpio));}/* * Nokia 770 I/O layer */#define SPI_CS_ON()  omap_set_gpio_dataout((wlan_config->spi_cs_gpio), 0)#define SPI_CS_OFF() omap_set_gpio_dataout((wlan_config->spi_cs_gpio), 1)struct omap_wlan_spi_dma {	int dma_tx_ch;	int dma_rx_ch;		int dma_tx_done;	int dma_rx_done;		uint16_t recv_buffer;};static struct omap_wlan_spi_dma spi_dma;#ifndef OMAP_DMA_TOUT_IRQ#define OMAP_DMA_TOUT_IRQ OMAP1_DMA_TOUT_IRQ#endif/* SPI DMA operations */static void dma_tx_callback(int lch, u16 ch_status, void *data){	if (ch_status & OMAP_DMA_TOUT_IRQ)		printk("McBSP TX DMA timeout\n");	if (ch_status & OMAP_DMA_DROP_IRQ)		printk("McBSP TX DMA drop\n");	spi_dma.dma_tx_done = 1;}static void dma_rx_callback(int lch, u16 ch_status, void *data){	if (ch_status & OMAP_DMA_TOUT_IRQ)		printk("McBSP RX DMA timeout\n");	if (ch_status & OMAP_DMA_DROP_IRQ)		printk("McBSP RX DMA drop\n");	spi_dma.dma_rx_done = 1;}int cx3110x_spi_dma_read(struct net_device *dev, unsigned long address, void * buffer, unsigned int length){	SPI_CS_ON();	omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, 				      (address << 8) | ADDR_READ_BIT_15);	/* Start writing */	omap_set_dma_transfer_params(spi_dma.dma_tx_ch,				     OMAP_DMA_DATA_TYPE_S16,				     length >> 1, 1,				     OMAP_DMA_SYNC_ELEMENT, 0, 0);	omap_set_dma_dest_params(spi_dma.dma_tx_ch,				 OMAP_DMA_PORT_TIPB,				 OMAP_DMA_AMODE_CONSTANT,				 OMAP1610_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,				 0, 0);	omap_set_dma_src_params(spi_dma.dma_tx_ch,				OMAP_DMA_PORT_EMIFF,				OMAP_DMA_AMODE_CONSTANT,				virt_to_phys(&spi_dma.recv_buffer),				0, 0);	/* Prepare for reading */	omap_set_dma_transfer_params(spi_dma.dma_rx_ch,				     OMAP_DMA_DATA_TYPE_S16,				     length >> 1, 1,				     OMAP_DMA_SYNC_ELEMENT, 0, 0);	omap_set_dma_src_params(spi_dma.dma_rx_ch,				OMAP_DMA_PORT_TIPB,				OMAP_DMA_AMODE_CONSTANT,				OMAP1610_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1,				0, 0);	omap_set_dma_dest_params(spi_dma.dma_rx_ch,				 OMAP_DMA_PORT_EMIFF,				 OMAP_DMA_AMODE_POST_INC,				 virt_to_phys(buffer),				 0, 0);	/* DMA doesn't use CPU cache */	flush_cache_all();	        /* We start writing first, for the clock */	omap_start_dma(spi_dma.dma_rx_ch);	omap_start_dma(spi_dma.dma_tx_ch);	/* Wait for reading to complete */	while(!spi_dma.dma_rx_done) {		udelay(5);	}	while(!spi_dma.dma_tx_done) {		udelay(5);	}	spi_dma.dma_rx_done = 0;	spi_dma.dma_tx_done = 0;	SPI_CS_OFF();	return 0;}int cx3110x_spi_dma_write(struct net_device *dev, unsigned long address, void * buffer, unsigned int length){	SPI_CS_ON();	omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, address << 8);	/* Prepare reading */	omap_set_dma_transfer_params(spi_dma.dma_rx_ch,				     OMAP_DMA_DATA_TYPE_S16,				     length >> 1, 1,				     OMAP_DMA_SYNC_ELEMENT, 0, 0);	omap_set_dma_src_params(spi_dma.dma_rx_ch,				OMAP_DMA_PORT_TIPB,				OMAP_DMA_AMODE_CONSTANT,				OMAP1610_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1,				0, 0);	omap_set_dma_dest_params(spi_dma.dma_rx_ch,				 OMAP_DMA_PORT_EMIFF,				 OMAP_DMA_AMODE_CONSTANT,				 virt_to_phys(&spi_dma.recv_buffer),				 0, 0);	/* Prepare writing */	omap_set_dma_transfer_params(spi_dma.dma_tx_ch,				     OMAP_DMA_DATA_TYPE_S16,				     length >> 1, 1,				     OMAP_DMA_SYNC_ELEMENT, 0, 0);	omap_set_dma_dest_params(spi_dma.dma_tx_ch,				 OMAP_DMA_PORT_TIPB,				 OMAP_DMA_AMODE_CONSTANT,				 OMAP1610_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,				 0, 0);	omap_set_dma_src_params(spi_dma.dma_tx_ch,				OMAP_DMA_PORT_EMIFF,				OMAP_DMA_AMODE_POST_INC,				virt_to_phys(buffer),				0, 0);	/* DMA doesn't use CPU cache */	flush_cache_all();		/* RX first, and then TX */	omap_start_dma(spi_dma.dma_rx_ch);	omap_start_dma(spi_dma.dma_tx_ch);	/* We don't want to turn CS off before transfer is done */		while(!spi_dma.dma_tx_done) {		udelay(5);	}	spi_dma.dma_tx_done = 0;	/* UMAC may send us odd number of bytes long frames */	if (length % 2) {		u16 last_word;				last_word = *(uint16_t *)(buffer + length - 1);				omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, last_word);	}	SPI_CS_OFF();	return 0;}int cx3110x_spi_read(struct net_device *dev, unsigned long address, unsigned char * buffer, unsigned int length){	int i;	u16 * short_buffer = (u16 *) buffer;	unsigned int r_length = length >> 1;	DEBUG(DBG_SPI_IO, "omap_wlan_spi_read\n");	SPI_CS_ON();			omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, 				      (address << 8) | ADDR_READ_BIT_15);	for (i = 0 ; i < r_length ; i++)		omap_mcbsp_spi_master_recv_word_poll(OMAP_MCBSP2, (u32*)(short_buffer + i));	SPI_CS_OFF();	return 0;}int cx3110x_spi_write(struct net_device *dev, unsigned long address, unsigned char * buffer, unsigned int length){	int i;	u16 * short_buffer = (u16 *) buffer;	unsigned int w_length = length >> 1;	DEBUG(DBG_SPI_IO, "omap_wlan_spi_write (%d bytes @ 0x%lx)\n", length, address << 8);	SPI_CS_ON();	omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, address << 8);		for (i = 0 ; i < w_length ; i++)		omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, short_buffer[i]); 	/* UMAC may send us odd number of bytes long frames */	if (length % 2) {		u16 last_word;		last_word = buffer[length - 1];		omap_mcbsp_spi_master_xmit_word_poll(OMAP_MCBSP2, last_word); 	}	SPI_CS_OFF();	return 0;}extern int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);int cx3110x_spi_start(struct net_device *dev){	struct omap_mcbsp_spi_cfg spi_cfg;	int r, div = 1, rate_mhz, max_mhz = 14;	struct net_local * lp;	struct spi_hif_local_data * spi_lp;	lp = dev->priv;	spi_lp = HIF_LP(lp);	if (wlan_config->irq_gpio >= OMAP_MPUIO(0)) {		printk("WLAN IRQ on MPUIO is not supported\n");		return -EPERM;	}				rate_mhz = clk_get_rate(HIF_CLK(spi_lp))/1000000;		DEBUG(DBG_CALLS, "omap_wlan_spi_probe at SPI rate: %d Mhz\n", rate_mhz);		if (omap_request_gpio(wlan_config->spi_cs_gpio)) {		printk(KERN_ERR "Cannot request GPIO %d\n", wlan_config->spi_cs_gpio);		return -1;	}		if (omap_request_gpio(wlan_config->power_gpio)) {		printk(KERN_ERR "Cannot request GPIO %d\n", wlan_config->power_gpio);		return -1;	}	if (omap_request_gpio(wlan_config->irq_gpio)) {		printk(KERN_ERR "Cannot request MPUIO %d\n", wlan_config->irq_gpio);		return -1;	}	/* GPIO21 controls the SPI_CS line */	omap_set_gpio_direction(wlan_config->spi_cs_gpio, 0);		/* GPIO59 (output gpio) powers the wlan chip up */	omap_set_gpio_direction(wlan_config->power_gpio, 0);	omap_set_gpio_direction(wlan_config->irq_gpio, 1);	set_irq_type(OMAP_GPIO_IRQ(wlan_config->irq_gpio), IRQT_RISING);		cx3110x_hw_reset();		while(rate_mhz/div >= max_mhz)		div++;			spi_dma.dma_tx_done = 0;	spi_dma.dma_rx_done = 0;		if (omap_request_dma(OMAP_DMA_MCBSP2_TX, "McBSP TX", dma_tx_callback,			     NULL,			     &spi_dma.dma_tx_ch)) {		printk("Unable to request DMA channel for McBSP2 TX.\n");		return -EAGAIN;	}		if (omap_request_dma(OMAP_DMA_MCBSP2_RX, "McBSP RX", dma_rx_callback,			     NULL,			     &spi_dma.dma_rx_ch)) {		printk("Unable to request DMA channel for McBSP2 TX.\n");		return -EAGAIN;	}	spi_cfg.spi_mode = OMAP_MCBSP_SPI_MASTER;	spi_cfg.rx_clock_polarity = OMAP_MCBSP_CLK_FALLING;	spi_cfg.tx_clock_polarity = OMAP_MCBSP_CLK_RISING;	spi_cfg.fsx_polarity = OMAP_MCBSP_FS_ACTIVE_LOW;	spi_cfg.clk_div = div;	spi_cfg.clk_stp_mode = OMAP_MCBSP_CLK_STP_MODE_DELAY;	spi_cfg.word_length = OMAP_MCBSP_WORD_16;	/* We will do polling */	r = omap_mcbsp_set_io_type(OMAP_MCBSP2, OMAP_MCBSP_POLL_IO);	if ( r < 0) 		return r;	r = omap_mcbsp_request(OMAP_MCBSP2);	if ( r < 0) 		return r;	omap_mcbsp_set_spi_mode(OMAP_MCBSP2, &spi_cfg);	omap_mcbsp_start(OMAP_MCBSP2);		return 0;}void cx3110x_spi_stop(struct net_device *dev){		DEBUG(DBG_CALLS, "omap_wlan_spi_disconnect\n");		WLAN_POWER_DOWN();	omap_mcbsp_free(OMAP_MCBSP2);	omap_mcbsp_stop(OMAP_MCBSP2);	omap_free_gpio(wlan_config->spi_cs_gpio);	omap_free_gpio(wlan_config->power_gpio);	omap_free_gpio(wlan_config->irq_gpio);	omap_free_dma(spi_dma.dma_tx_ch);	omap_free_dma(spi_dma.dma_rx_ch);}struct cx3110x_spi_reg_s{	u16  address;	u16  length;	char    *name;};static const struct cx3110x_spi_reg_s wlan_registers_array[] ={        { SPI_ADRS_ARM_INTERRUPTS,     32, "ARM_INT     "  },        { SPI_ADRS_ARM_INT_EN,         32, "ARM_INT_ENA "  },        { SPI_ADRS_HOST_INTERRUPTS,    32, "HOST_INT    "  },        { SPI_ADRS_HOST_INT_EN,        32, "HOST_INT_ENA"  },        { SPI_ADRS_HOST_INT_ACK,       32, "HOST_INT_ACK"  },        { SPI_ADRS_GEN_PURP_1,         32, "GP1_COMM    "  },        { SPI_ADRS_GEN_PURP_2,         32, "GP2_COMM    "  },        { SPI_ADRS_DEV_CTRL_STAT,      32, "DEV_CTRL_STA"  },        { SPI_ADRS_DMA_DATA,           16, "DMA_DATA    "  },        { SPI_ADRS_DMA_WRITE_CTRL,     16, "DMA_WR_CTRL "  },        { SPI_ADRS_DMA_WRITE_LEN,      16, "DMA_WR_LEN  "  },        { SPI_ADRS_DMA_WRITE_BASE,     32, "DMA_WR_BASE "  },        { SPI_ADRS_DMA_READ_CTRL,      16, "DMA_RD_CTRL "  },        { SPI_ADRS_DMA_READ_LEN,       16, "DMA_RD_LEN  "  },        { SPI_ADRS_DMA_WRITE_BASE,     32, "DMA_RD_BASE "  }};void cx3110x_dump_register(struct net_device * dev){	uint16_t i;	uint32_t buffer;	printk("**** WLAN registers ****\n");	for (i = 0; i < ARRAY_SIZE(wlan_registers_array); i++) {		cx3110x_spi_read(dev, wlan_registers_array[i].address, 				 (unsigned char *)&buffer, 				 (wlan_registers_array[i].length) >> 3);				if (wlan_registers_array[i].length == 32)			printk("%s -> 0x%08x (32 bits)\n", wlan_registers_array[i].name, buffer);		else			printk("%s -> 0x%04x (16 bits)\n", wlan_registers_array[i].name, buffer);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -