📄 pxaficp_ir.c
字号:
/* * linux/drivers/net/irda/pxaficp_ir.c * * Based on sa1100_ir.c by Russell King * * Changes copyright (C) 2003-2005 MontaVista Software, Inc. * * 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. * * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor * */#include <linux/module.h>#include <linux/types.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/slab.h>#include <linux/rtnetlink.h>#include <linux/interrupt.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <linux/pm.h>#include <net/irda/irda.h>#include <net/irda/irmod.h>#include <net/irda/wrapper.h>#include <net/irda/irda_device.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/delay.h>#include <asm/hardware.h>#include <asm/arch/irda.h>#include <asm/arch/pxa-regs.h>#ifdef CONFIG_MACH_MAINSTONE#include <asm/arch/mainstone.h>#endif#define IrSR_RXPL_NEG_IS_ZERO (1<<4)#define IrSR_RXPL_POS_IS_ZERO 0x0#define IrSR_TXPL_NEG_IS_ZERO (1<<3)#define IrSR_TXPL_POS_IS_ZERO 0x0#define IrSR_XMODE_PULSE_1_6 (1<<2)#define IrSR_XMODE_PULSE_3_16 0x0#define IrSR_RCVEIR_IR_MODE (1<<1)#define IrSR_RCVEIR_UART_MODE 0x0#define IrSR_XMITIR_IR_MODE (1<<0)#define IrSR_XMITIR_UART_MODE 0x0#define IrSR_IR_RECEIVE_ON (\ IrSR_RXPL_NEG_IS_ZERO | \ IrSR_TXPL_POS_IS_ZERO | \ IrSR_XMODE_PULSE_3_16 | \ IrSR_RCVEIR_IR_MODE | \ IrSR_XMITIR_UART_MODE)#define IrSR_IR_TRANSMIT_ON (\ IrSR_RXPL_NEG_IS_ZERO | \ IrSR_TXPL_POS_IS_ZERO | \ IrSR_XMODE_PULSE_3_16 | \ IrSR_RCVEIR_UART_MODE | \ IrSR_XMITIR_IR_MODE)struct pxa_irda { int speed; int newspeed; unsigned long last_oscr; unsigned char *dma_rx_buff; unsigned char *dma_tx_buff; dma_addr_t dma_rx_buff_phy; dma_addr_t dma_tx_buff_phy; unsigned int dma_tx_buff_len; int txdma; int rxdma; struct net_device_stats stats; struct irlap_cb *irlap; struct qos_info qos; iobuff_t tx_buff; iobuff_t rx_buff; struct device *dev; struct pxaficp_platform_data *pdata;};#define IS_FIR(si) ((si)->speed >= 4000000)#define IRDA_FRAME_SIZE_LIMIT 2047inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si){ DCSR(si->rxdma) = DCSR_NODESC; DSADR(si->rxdma) = __PREG(ICDR); DTADR(si->rxdma) = si->dma_rx_buff_phy; DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT; DCSR(si->rxdma) |= DCSR_RUN;}inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si){ DCSR(si->txdma) = DCSR_NODESC; DSADR(si->txdma) = si->dma_tx_buff_phy; DTADR(si->txdma) = __PREG(ICDR); DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len; DCSR(si->txdma) |= DCSR_RUN;}/* * Set the IrDA communications speed. */static int pxa_irda_set_speed(struct pxa_irda *si, int speed){ unsigned long flags; unsigned int divisor; switch (speed) { case 9600: case 19200: case 38400: case 57600: case 115200: /* refer to PXA250/210 Developer's Manual 10-7 */ /* BaudRate = 14.7456 MHz / (16*Divisor) */ divisor = 14745600 / (16 * speed); local_irq_save(flags); if (IS_FIR(si)) { /* stop RX DMA */ DCSR(si->rxdma) &= ~DCSR_RUN; /* disable FICP */ ICCR0 = 0; pxa_set_cken(CKEN13_FICP, 0); /* set board transceiver to SIR mode */ si->pdata->transceiver_mode(si->dev, IR_SIRMODE); /* configure GPIO46/47 */ pxa_gpio_mode(GPIO46_STRXD_MD); pxa_gpio_mode(GPIO47_STTXD_MD); /* enable the STUART clock */ pxa_set_cken(CKEN5_STUART, 1); } /* disable STUART first */ STIER = 0; /* access DLL & DLH */ STLCR |= LCR_DLAB; STDLL = divisor & 0xff; STDLH = divisor >> 8; STLCR &= ~LCR_DLAB; si->speed = speed; STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; local_irq_restore(flags); break; case 4000000: local_irq_save(flags); /* disable STUART */ STIER = 0; STISR = 0; pxa_set_cken(CKEN5_STUART, 0); /* disable FICP first */ ICCR0 = 0; /* set board transceiver to FIR mode */ si->pdata->transceiver_mode(si->dev, IR_FIRMODE); /* configure GPIO46/47 */ pxa_gpio_mode(GPIO46_ICPRXD_MD); pxa_gpio_mode(GPIO47_ICPTXD_MD); /* enable the FICP clock */ pxa_set_cken(CKEN13_FICP, 1); si->speed = speed; pxa_irda_fir_dma_rx_start(si); ICCR0 = ICCR0_ITR | ICCR0_RXE; local_irq_restore(flags); break; default: return -EINVAL; } return 0;}/* SIR interrupt service routine. */static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id){ struct net_device *dev = dev_id; struct pxa_irda *si = netdev_priv(dev); int iir, lsr, data; iir = STIIR; switch (iir & 0x0F) { case 0x06: /* Receiver Line Status */ lsr = STLSR; while (lsr & LSR_FIFOE) { data = STRBR; if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); si->stats.rx_errors++; if (lsr & LSR_FE) si->stats.rx_frame_errors++; if (lsr & LSR_OE) si->stats.rx_fifo_errors++; } else { si->stats.rx_bytes++; async_unwrap_char(dev, &si->stats, &si->rx_buff, data); } lsr = STLSR; } dev->last_rx = jiffies; si->last_oscr = OSCR; break; case 0x04: /* Received Data Available */ /* forth through */ case 0x0C: /* Character Timeout Indication */ do { si->stats.rx_bytes++; async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); } while (STLSR & LSR_DR); dev->last_rx = jiffies; si->last_oscr = OSCR; break; case 0x02: /* Transmit FIFO Data Request */ while ((si->tx_buff.len) && (STLSR & LSR_TDRQ)) { STTHR = *si->tx_buff.data++; si->tx_buff.len -= 1; } if (si->tx_buff.len == 0) { si->stats.tx_packets++; si->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; /* We need to ensure that the transmitter has finished. */ while ((STLSR & LSR_TEMT) == 0) cpu_relax(); si->last_oscr = OSCR; /* * Ok, we've finished transmitting. Now enable * the receiver. Sometimes we get a receive IRQ * immediately after a transmit... */ if (si->newspeed) { pxa_irda_set_speed(si, si->newspeed); si->newspeed = 0; } else { /* enable IR Receiver, disable IR Transmitter */ STISR = IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6; /* enable STUART and receive interrupts */ STIER = IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE; } /* I'm hungry! */ netif_wake_queue(dev); } break; } return IRQ_HANDLED;}/* FIR Receive DMA interrupt handler */static void pxa_irda_fir_dma_rx_irq(int channel, void *data){ int dcsr = DCSR(channel); DCSR(channel) = dcsr & ~DCSR_RUN; printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr);}/* FIR Transmit DMA interrupt handler */static void pxa_irda_fir_dma_tx_irq(int channel, void *data){ struct net_device *dev = data; struct pxa_irda *si = netdev_priv(dev); int dcsr; dcsr = DCSR(channel); DCSR(channel) = dcsr & ~DCSR_RUN; if (dcsr & DCSR_ENDINTR) { si->stats.tx_packets++; si->stats.tx_bytes += si->dma_tx_buff_len; } else { si->stats.tx_errors++; } while (ICSR1 & ICSR1_TBY) cpu_relax(); si->last_oscr = OSCR; /* * HACK: It looks like the TBY bit is dropped too soon. * Without this delay things break. */ udelay(120); if (si->newspeed) { pxa_irda_set_speed(si, si->newspeed); si->newspeed = 0; } else { ICCR0 = 0; pxa_irda_fir_dma_rx_start(si); ICCR0 = ICCR0_ITR | ICCR0_RXE; } netif_wake_queue(dev);}/* EIF(Error in FIFO/End in Frame) handler for FIR */static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev){ unsigned int len, stat, data; /* Get the current data position. */ len = DTADR(si->rxdma) - si->dma_rx_buff_phy; do { /* Read Status, and then Data. */ stat = ICSR1; rmb(); data = ICDR; if (stat & (ICSR1_CRE | ICSR1_ROR)) { si->stats.rx_errors++; if (stat & ICSR1_CRE) { printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); si->stats.rx_crc_errors++; } if (stat & ICSR1_ROR) { printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); si->stats.rx_frame_errors++; } } else { si->dma_rx_buff[len++] = data; } /* If we hit the end of frame, there's no point in continuing. */ if (stat & ICSR1_EOF) break; } while (ICSR0 & ICSR0_EIF); if (stat & ICSR1_EOF) { /* end of frame. */ struct sk_buff *skb = alloc_skb(len+1,GFP_ATOMIC); if (!skb) { printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); si->stats.rx_dropped++; return; } /* Align IP header to 20 bytes */ skb_reserve(skb, 1); memcpy(skb->data, si->dma_rx_buff, len); skb_put(skb, len); /* Feed it to IrLAP */ skb->dev = dev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); si->stats.rx_packets++; si->stats.rx_bytes += len; dev->last_rx = jiffies; }}/* FIR interrupt handler */static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id){ struct net_device *dev = dev_id; struct pxa_irda *si = netdev_priv(dev); int icsr0; /* stop RX DMA */ DCSR(si->rxdma) &= ~DCSR_RUN; si->last_oscr = OSCR; icsr0 = ICSR0; if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { if (icsr0 & ICSR0_FRE) { printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); si->stats.rx_frame_errors++; } else { printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); si->stats.rx_errors++; } ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB); } if (icsr0 & ICSR0_EIF) { /* An error in FIFO occured, or there is a end of frame */ pxa_irda_fir_irq_eif(si, dev); } ICCR0 = 0; pxa_irda_fir_dma_rx_start(si); ICCR0 = ICCR0_ITR | ICCR0_RXE; return IRQ_HANDLED;}/* hard_xmit interface of irda device */static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev){ struct pxa_irda *si = netdev_priv(dev); int speed = irda_get_next_speed(skb); /* * Does this packet contain a request to change the interface * speed? If so, remember it until we complete the transmission
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -