📄 sm_drv_spi_io.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 + -