blob: 05a668216a0f0f3c7c81f875592e25dd2ad02135 [file] [log] [blame]
Nicolas Pitre6f475c02005-10-28 16:39:33 +01001/*
2 * linux/drivers/net/irda/pxaficp_ir.c
3 *
4 * Based on sa1100_ir.c by Russell King
5 *
6 * Changes copyright (C) 2003-2005 MontaVista Software, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor
13 *
14 */
Alexey Dobriyanb7f080c2011-06-16 11:01:34 +000015#include <linux/dma-mapping.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000016#include <linux/interrupt.h>
Nicolas Pitre6f475c02005-10-28 16:39:33 +010017#include <linux/module.h>
Nicolas Pitre6f475c02005-10-28 16:39:33 +010018#include <linux/netdevice.h>
Alexander Beregalovf6a26292009-04-16 15:23:03 +000019#include <linux/etherdevice.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010020#include <linux/platform_device.h>
Russell King82d553c2007-09-02 17:09:23 +010021#include <linux/clk.h>
Marek Vasutc4bd0172009-07-17 12:50:43 +020022#include <linux/gpio.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Nicolas Pitre6f475c02005-10-28 16:39:33 +010024
25#include <net/irda/irda.h>
26#include <net/irda/irmod.h>
27#include <net/irda/wrapper.h>
28#include <net/irda/irda_device.h>
29
Russell Kingdcea83a2008-11-29 11:40:28 +000030#include <mach/dma.h>
Arnd Bergmann293b2da2012-08-24 15:16:48 +020031#include <linux/platform_data/irda-pxaficp.h>
Robert Jarzmik89fa5722015-09-26 20:49:19 +020032#undef __REG
33#define __REG(x) ((x) & 0xffff)
Rob Herring121f3f92012-08-29 10:31:14 -050034#include <mach/regs-uart.h>
Nicolas Pitre6f475c02005-10-28 16:39:33 +010035
Robert Jarzmik89fa5722015-09-26 20:49:19 +020036#define ICCR0 0x0000 /* ICP Control Register 0 */
37#define ICCR1 0x0004 /* ICP Control Register 1 */
38#define ICCR2 0x0008 /* ICP Control Register 2 */
39#define ICDR 0x000c /* ICP Data Register */
40#define ICSR0 0x0014 /* ICP Status Register 0 */
41#define ICSR1 0x0018 /* ICP Status Register 1 */
Eric Miaob40ddf52008-11-28 11:13:47 +080042
43#define ICCR0_AME (1 << 7) /* Address match enable */
44#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */
Lucas De Marchi25985ed2011-03-30 22:57:33 -030045#define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */
Eric Miaob40ddf52008-11-28 11:13:47 +080046#define ICCR0_RXE (1 << 4) /* Receive enable */
47#define ICCR0_TXE (1 << 3) /* Transmit enable */
48#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */
49#define ICCR0_LBM (1 << 1) /* Loopback mode */
50#define ICCR0_ITR (1 << 0) /* IrDA transmission */
51
52#define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */
53#define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */
54#define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */
55#define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */
56#define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */
57#define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */
58
Eric Miaob40ddf52008-11-28 11:13:47 +080059#define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */
Eric Miaob40ddf52008-11-28 11:13:47 +080060#define ICSR0_FRE (1 << 5) /* Framing error */
61#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */
62#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */
63#define ICSR0_RAB (1 << 2) /* Receiver abort */
64#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */
65#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */
66
67#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */
68#define ICSR1_CRE (1 << 5) /* CRC error */
69#define ICSR1_EOF (1 << 4) /* End of frame */
70#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */
71#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */
72#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */
73#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */
Nicolas Pitre6f475c02005-10-28 16:39:33 +010074
Nicolas Pitre6f475c02005-10-28 16:39:33 +010075#define IrSR_RXPL_NEG_IS_ZERO (1<<4)
76#define IrSR_RXPL_POS_IS_ZERO 0x0
77#define IrSR_TXPL_NEG_IS_ZERO (1<<3)
78#define IrSR_TXPL_POS_IS_ZERO 0x0
79#define IrSR_XMODE_PULSE_1_6 (1<<2)
80#define IrSR_XMODE_PULSE_3_16 0x0
81#define IrSR_RCVEIR_IR_MODE (1<<1)
82#define IrSR_RCVEIR_UART_MODE 0x0
83#define IrSR_XMITIR_IR_MODE (1<<0)
84#define IrSR_XMITIR_UART_MODE 0x0
85
86#define IrSR_IR_RECEIVE_ON (\
87 IrSR_RXPL_NEG_IS_ZERO | \
88 IrSR_TXPL_POS_IS_ZERO | \
89 IrSR_XMODE_PULSE_3_16 | \
90 IrSR_RCVEIR_IR_MODE | \
91 IrSR_XMITIR_UART_MODE)
92
93#define IrSR_IR_TRANSMIT_ON (\
94 IrSR_RXPL_NEG_IS_ZERO | \
95 IrSR_TXPL_POS_IS_ZERO | \
96 IrSR_XMODE_PULSE_3_16 | \
97 IrSR_RCVEIR_UART_MODE | \
98 IrSR_XMITIR_IR_MODE)
99
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200100/* macros for registers read/write */
101#define ficp_writel(irda, val, off) \
102 do { \
103 dev_vdbg(irda->dev, \
104 "%s():%d ficp_writel(0x%x, %s)\n", \
105 __func__, __LINE__, (val), #off); \
106 writel_relaxed((val), (irda)->irda_base + (off)); \
107 } while (0)
108
109#define ficp_readl(irda, off) \
110 ({ \
111 unsigned int _v; \
112 _v = readl_relaxed((irda)->irda_base + (off)); \
113 dev_vdbg(irda->dev, \
114 "%s():%d ficp_readl(%s): 0x%x\n", \
115 __func__, __LINE__, #off, _v); \
116 _v; \
117 })
118
119#define stuart_writel(irda, val, off) \
120 do { \
121 dev_vdbg(irda->dev, \
122 "%s():%d stuart_writel(0x%x, %s)\n", \
123 __func__, __LINE__, (val), #off); \
124 writel_relaxed((val), (irda)->stuart_base + (off)); \
125 } while (0)
126
127#define stuart_readl(irda, off) \
128 ({ \
129 unsigned int _v; \
130 _v = readl_relaxed((irda)->stuart_base + (off)); \
131 dev_vdbg(irda->dev, \
132 "%s():%d stuart_readl(%s): 0x%x\n", \
133 __func__, __LINE__, #off, _v); \
134 _v; \
135 })
136
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100137struct pxa_irda {
138 int speed;
139 int newspeed;
Robert Jarzmikbe018912015-09-26 20:49:18 +0200140 unsigned long long last_clk;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100141
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200142 void __iomem *stuart_base;
143 void __iomem *irda_base;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100144 unsigned char *dma_rx_buff;
145 unsigned char *dma_tx_buff;
146 dma_addr_t dma_rx_buff_phy;
147 dma_addr_t dma_tx_buff_phy;
148 unsigned int dma_tx_buff_len;
149 int txdma;
150 int rxdma;
151
Rob Herring121f3f92012-08-29 10:31:14 -0500152 int uart_irq;
153 int icp_irq;
154
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100155 struct irlap_cb *irlap;
156 struct qos_info qos;
157
158 iobuff_t tx_buff;
159 iobuff_t rx_buff;
160
161 struct device *dev;
162 struct pxaficp_platform_data *pdata;
Russell King82d553c2007-09-02 17:09:23 +0100163 struct clk *fir_clk;
164 struct clk *sir_clk;
165 struct clk *cur_clk;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100166};
167
Russell King82d553c2007-09-02 17:09:23 +0100168static inline void pxa_irda_disable_clk(struct pxa_irda *si)
169{
170 if (si->cur_clk)
Philipp Zabel4823cd32012-03-15 08:19:29 +0000171 clk_disable_unprepare(si->cur_clk);
Russell King82d553c2007-09-02 17:09:23 +0100172 si->cur_clk = NULL;
173}
174
175static inline void pxa_irda_enable_firclk(struct pxa_irda *si)
176{
177 si->cur_clk = si->fir_clk;
Philipp Zabel4823cd32012-03-15 08:19:29 +0000178 clk_prepare_enable(si->fir_clk);
Russell King82d553c2007-09-02 17:09:23 +0100179}
180
181static inline void pxa_irda_enable_sirclk(struct pxa_irda *si)
182{
183 si->cur_clk = si->sir_clk;
Philipp Zabel4823cd32012-03-15 08:19:29 +0000184 clk_prepare_enable(si->sir_clk);
Russell King82d553c2007-09-02 17:09:23 +0100185}
186
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100187
188#define IS_FIR(si) ((si)->speed >= 4000000)
189#define IRDA_FRAME_SIZE_LIMIT 2047
190
191inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si)
192{
193 DCSR(si->rxdma) = DCSR_NODESC;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200194 DSADR(si->rxdma) = (unsigned long)si->irda_base + ICDR;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100195 DTADR(si->rxdma) = si->dma_rx_buff_phy;
196 DCMD(si->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_WIDTH1 | DCMD_BURST32 | IRDA_FRAME_SIZE_LIMIT;
197 DCSR(si->rxdma) |= DCSR_RUN;
198}
199
200inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si)
201{
202 DCSR(si->txdma) = DCSR_NODESC;
203 DSADR(si->txdma) = si->dma_tx_buff_phy;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200204 DTADR(si->txdma) = (unsigned long)si->irda_base + ICDR;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100205 DCMD(si->txdma) = DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST32 | si->dma_tx_buff_len;
206 DCSR(si->txdma) |= DCSR_RUN;
207}
208
209/*
Marek Vasutc4bd0172009-07-17 12:50:43 +0200210 * Set the IrDA communications mode.
211 */
212static void pxa_irda_set_mode(struct pxa_irda *si, int mode)
213{
214 if (si->pdata->transceiver_mode)
215 si->pdata->transceiver_mode(si->dev, mode);
216 else {
217 if (gpio_is_valid(si->pdata->gpio_pwdown))
218 gpio_set_value(si->pdata->gpio_pwdown,
219 !(mode & IR_OFF) ^
220 !si->pdata->gpio_pwdown_inverted);
221 pxa2xx_transceiver_mode(si->dev, mode);
222 }
223}
224
225/*
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100226 * Set the IrDA communications speed.
227 */
228static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
229{
230 unsigned long flags;
231 unsigned int divisor;
232
233 switch (speed) {
234 case 9600: case 19200: case 38400:
235 case 57600: case 115200:
236
237 /* refer to PXA250/210 Developer's Manual 10-7 */
238 /* BaudRate = 14.7456 MHz / (16*Divisor) */
239 divisor = 14745600 / (16 * speed);
240
241 local_irq_save(flags);
242
243 if (IS_FIR(si)) {
244 /* stop RX DMA */
245 DCSR(si->rxdma) &= ~DCSR_RUN;
246 /* disable FICP */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200247 ficp_writel(si, 0, ICCR0);
Russell King82d553c2007-09-02 17:09:23 +0100248 pxa_irda_disable_clk(si);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100249
250 /* set board transceiver to SIR mode */
Marek Vasutc4bd0172009-07-17 12:50:43 +0200251 pxa_irda_set_mode(si, IR_SIRMODE);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100252
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100253 /* enable the STUART clock */
Russell King82d553c2007-09-02 17:09:23 +0100254 pxa_irda_enable_sirclk(si);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100255 }
256
257 /* disable STUART first */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200258 stuart_writel(si, 0, STIER);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100259
260 /* access DLL & DLH */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200261 stuart_writel(si, stuart_readl(si, STLCR) | LCR_DLAB, STLCR);
262 stuart_writel(si, divisor & 0xff, STDLL);
263 stuart_writel(si, divisor >> 8, STDLH);
264 stuart_writel(si, stuart_readl(si, STLCR) & ~LCR_DLAB, STLCR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100265
266 si->speed = speed;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200267 stuart_writel(si, IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6,
268 STISR);
269 stuart_writel(si, IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE,
270 STIER);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100271
272 local_irq_restore(flags);
273 break;
274
275 case 4000000:
276 local_irq_save(flags);
277
278 /* disable STUART */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200279 stuart_writel(si, 0, STIER);
280 stuart_writel(si, 0, STISR);
Russell King82d553c2007-09-02 17:09:23 +0100281 pxa_irda_disable_clk(si);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100282
283 /* disable FICP first */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200284 ficp_writel(si, 0, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100285
286 /* set board transceiver to FIR mode */
Marek Vasutc4bd0172009-07-17 12:50:43 +0200287 pxa_irda_set_mode(si, IR_FIRMODE);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100288
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100289 /* enable the FICP clock */
Russell King82d553c2007-09-02 17:09:23 +0100290 pxa_irda_enable_firclk(si);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100291
292 si->speed = speed;
293 pxa_irda_fir_dma_rx_start(si);
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200294 ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100295
296 local_irq_restore(flags);
297 break;
298
299 default:
300 return -EINVAL;
301 }
302
303 return 0;
304}
305
306/* SIR interrupt service routine. */
David Howells7d12e782006-10-05 14:55:46 +0100307static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100308{
309 struct net_device *dev = dev_id;
310 struct pxa_irda *si = netdev_priv(dev);
311 int iir, lsr, data;
312
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200313 iir = stuart_readl(si, STIIR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100314
315 switch (iir & 0x0F) {
316 case 0x06: /* Receiver Line Status */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200317 lsr = stuart_readl(si, STLSR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100318 while (lsr & LSR_FIFOE) {
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200319 data = stuart_readl(si, STRBR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100320 if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) {
321 printk(KERN_DEBUG "pxa_ir: sir receiving error\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800322 dev->stats.rx_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100323 if (lsr & LSR_FE)
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800324 dev->stats.rx_frame_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100325 if (lsr & LSR_OE)
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800326 dev->stats.rx_fifo_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100327 } else {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800328 dev->stats.rx_bytes++;
329 async_unwrap_char(dev, &dev->stats,
330 &si->rx_buff, data);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100331 }
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200332 lsr = stuart_readl(si, STLSR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100333 }
Robert Jarzmikbe018912015-09-26 20:49:18 +0200334 si->last_clk = sched_clock();
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100335 break;
336
337 case 0x04: /* Received Data Available */
338 /* forth through */
339
340 case 0x0C: /* Character Timeout Indication */
341 do {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800342 dev->stats.rx_bytes++;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200343 async_unwrap_char(dev, &dev->stats, &si->rx_buff,
344 stuart_readl(si, STRBR));
345 } while (stuart_readl(si, STLSR) & LSR_DR);
Robert Jarzmikbe018912015-09-26 20:49:18 +0200346 si->last_clk = sched_clock();
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100347 break;
348
349 case 0x02: /* Transmit FIFO Data Request */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200350 while ((si->tx_buff.len) &&
351 (stuart_readl(si, STLSR) & LSR_TDRQ)) {
352 stuart_writel(si, *si->tx_buff.data++, STTHR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100353 si->tx_buff.len -= 1;
354 }
355
356 if (si->tx_buff.len == 0) {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800357 dev->stats.tx_packets++;
358 dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100359
360 /* We need to ensure that the transmitter has finished. */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200361 while ((stuart_readl(si, STLSR) & LSR_TEMT) == 0)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100362 cpu_relax();
Robert Jarzmikbe018912015-09-26 20:49:18 +0200363 si->last_clk = sched_clock();
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100364
365 /*
366 * Ok, we've finished transmitting. Now enable
367 * the receiver. Sometimes we get a receive IRQ
368 * immediately after a transmit...
369 */
370 if (si->newspeed) {
371 pxa_irda_set_speed(si, si->newspeed);
372 si->newspeed = 0;
373 } else {
374 /* enable IR Receiver, disable IR Transmitter */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200375 stuart_writel(si, IrSR_IR_RECEIVE_ON |
376 IrSR_XMODE_PULSE_1_6, STISR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100377 /* enable STUART and receive interrupts */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200378 stuart_writel(si, IER_UUE | IER_RLSE |
379 IER_RAVIE | IER_RTIOE, STIER);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100380 }
381 /* I'm hungry! */
382 netif_wake_queue(dev);
383 }
384 break;
385 }
386
387 return IRQ_HANDLED;
388}
389
390/* FIR Receive DMA interrupt handler */
David Howells7d12e782006-10-05 14:55:46 +0100391static void pxa_irda_fir_dma_rx_irq(int channel, void *data)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100392{
393 int dcsr = DCSR(channel);
394
395 DCSR(channel) = dcsr & ~DCSR_RUN;
396
397 printk(KERN_DEBUG "pxa_ir: fir rx dma bus error %#x\n", dcsr);
398}
399
400/* FIR Transmit DMA interrupt handler */
David Howells7d12e782006-10-05 14:55:46 +0100401static void pxa_irda_fir_dma_tx_irq(int channel, void *data)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100402{
403 struct net_device *dev = data;
404 struct pxa_irda *si = netdev_priv(dev);
405 int dcsr;
406
407 dcsr = DCSR(channel);
408 DCSR(channel) = dcsr & ~DCSR_RUN;
409
410 if (dcsr & DCSR_ENDINTR) {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800411 dev->stats.tx_packets++;
412 dev->stats.tx_bytes += si->dma_tx_buff_len;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100413 } else {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800414 dev->stats.tx_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100415 }
416
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200417 while (ficp_readl(si, ICSR1) & ICSR1_TBY)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100418 cpu_relax();
Robert Jarzmikbe018912015-09-26 20:49:18 +0200419 si->last_clk = sched_clock();
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100420
421 /*
422 * HACK: It looks like the TBY bit is dropped too soon.
423 * Without this delay things break.
424 */
425 udelay(120);
426
427 if (si->newspeed) {
428 pxa_irda_set_speed(si, si->newspeed);
429 si->newspeed = 0;
430 } else {
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100431 int i = 64;
432
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200433 ficp_writel(si, 0, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100434 pxa_irda_fir_dma_rx_start(si);
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200435 while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--)
436 ficp_readl(si, ICDR);
437 ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0);
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100438
439 if (i < 0)
440 printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100441 }
442 netif_wake_queue(dev);
443}
444
445/* EIF(Error in FIFO/End in Frame) handler for FIR */
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100446static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100447{
448 unsigned int len, stat, data;
449
450 /* Get the current data position. */
451 len = DTADR(si->rxdma) - si->dma_rx_buff_phy;
452
453 do {
454 /* Read Status, and then Data. */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200455 stat = ficp_readl(si, ICSR1);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100456 rmb();
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200457 data = ficp_readl(si, ICDR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100458
459 if (stat & (ICSR1_CRE | ICSR1_ROR)) {
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800460 dev->stats.rx_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100461 if (stat & ICSR1_CRE) {
462 printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800463 dev->stats.rx_crc_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100464 }
465 if (stat & ICSR1_ROR) {
466 printk(KERN_DEBUG "pxa_ir: fir receive overrun\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800467 dev->stats.rx_over_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100468 }
469 } else {
470 si->dma_rx_buff[len++] = data;
471 }
472 /* If we hit the end of frame, there's no point in continuing. */
473 if (stat & ICSR1_EOF)
474 break;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200475 } while (ficp_readl(si, ICSR0) & ICSR0_EIF);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100476
477 if (stat & ICSR1_EOF) {
478 /* end of frame. */
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100479 struct sk_buff *skb;
480
481 if (icsr0 & ICSR0_FRE) {
482 printk(KERN_ERR "pxa_ir: dropping erroneous frame\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800483 dev->stats.rx_dropped++;
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100484 return;
485 }
486
487 skb = alloc_skb(len+1,GFP_ATOMIC);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100488 if (!skb) {
489 printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800490 dev->stats.rx_dropped++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100491 return;
492 }
493
494 /* Align IP header to 20 bytes */
495 skb_reserve(skb, 1);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300496 skb_copy_to_linear_data(skb, si->dma_rx_buff, len);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100497 skb_put(skb, len);
498
499 /* Feed it to IrLAP */
500 skb->dev = dev;
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -0700501 skb_reset_mac_header(skb);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100502 skb->protocol = htons(ETH_P_IRDA);
503 netif_rx(skb);
504
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800505 dev->stats.rx_packets++;
506 dev->stats.rx_bytes += len;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100507 }
508}
509
510/* FIR interrupt handler */
David Howells7d12e782006-10-05 14:55:46 +0100511static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100512{
513 struct net_device *dev = dev_id;
514 struct pxa_irda *si = netdev_priv(dev);
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100515 int icsr0, i = 64;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100516
517 /* stop RX DMA */
518 DCSR(si->rxdma) &= ~DCSR_RUN;
Robert Jarzmikbe018912015-09-26 20:49:18 +0200519 si->last_clk = sched_clock();
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200520 icsr0 = ficp_readl(si, ICSR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100521
522 if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) {
523 if (icsr0 & ICSR0_FRE) {
524 printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800525 dev->stats.rx_frame_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100526 } else {
527 printk(KERN_DEBUG "pxa_ir: fir receive abort\n");
Stephen Hemmingeraf049082009-01-06 10:40:43 -0800528 dev->stats.rx_errors++;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100529 }
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200530 ficp_writel(si, icsr0 & (ICSR0_FRE | ICSR0_RAB), ICSR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100531 }
532
533 if (icsr0 & ICSR0_EIF) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300534 /* An error in FIFO occurred, or there is a end of frame */
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100535 pxa_irda_fir_irq_eif(si, dev, icsr0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100536 }
537
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200538 ficp_writel(si, 0, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100539 pxa_irda_fir_dma_rx_start(si);
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200540 while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--)
541 ficp_readl(si, ICDR);
542 ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100543
Guennadi Liakhovetski9a4d93d2007-03-30 08:49:55 +0100544 if (i < 0)
545 printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n");
546
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100547 return IRQ_HANDLED;
548}
549
550/* hard_xmit interface of irda device */
551static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
552{
553 struct pxa_irda *si = netdev_priv(dev);
554 int speed = irda_get_next_speed(skb);
555
556 /*
557 * Does this packet contain a request to change the interface
558 * speed? If so, remember it until we complete the transmission
559 * of this frame.
560 */
561 if (speed != si->speed && speed != -1)
562 si->newspeed = speed;
563
564 /*
565 * If this is an empty frame, we can bypass a lot.
566 */
567 if (skb->len == 0) {
568 if (si->newspeed) {
569 si->newspeed = 0;
570 pxa_irda_set_speed(si, speed);
571 }
572 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000573 return NETDEV_TX_OK;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100574 }
575
576 netif_stop_queue(dev);
577
578 if (!IS_FIR(si)) {
579 si->tx_buff.data = si->tx_buff.head;
580 si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize);
581
582 /* Disable STUART interrupts and switch to transmit mode. */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200583 stuart_writel(si, 0, STIER);
584 stuart_writel(si, IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6,
585 STISR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100586
587 /* enable STUART and transmit interrupts */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200588 stuart_writel(si, IER_UUE | IER_TIE, STIER);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100589 } else {
590 unsigned long mtt = irda_get_mtt(skb);
591
592 si->dma_tx_buff_len = skb->len;
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -0300593 skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100594
595 if (mtt)
Robert Jarzmikbe018912015-09-26 20:49:18 +0200596 while ((sched_clock() - si->last_clk) * 1000 < mtt)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100597 cpu_relax();
598
599 /* stop RX DMA, disable FICP */
600 DCSR(si->rxdma) &= ~DCSR_RUN;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200601 ficp_writel(si, 0, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100602
603 pxa_irda_fir_dma_tx_start(si);
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200604 ficp_writel(si, ICCR0_ITR | ICCR0_TXE, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100605 }
606
607 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000608 return NETDEV_TX_OK;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100609}
610
611static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
612{
613 struct if_irda_req *rq = (struct if_irda_req *)ifreq;
614 struct pxa_irda *si = netdev_priv(dev);
615 int ret;
616
617 switch (cmd) {
618 case SIOCSBANDWIDTH:
619 ret = -EPERM;
620 if (capable(CAP_NET_ADMIN)) {
621 /*
622 * We are unable to set the speed if the
623 * device is not running.
624 */
625 if (netif_running(dev)) {
626 ret = pxa_irda_set_speed(si,
627 rq->ifr_baudrate);
628 } else {
629 printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n");
630 ret = 0;
631 }
632 }
633 break;
634
635 case SIOCSMEDIABUSY:
636 ret = -EPERM;
637 if (capable(CAP_NET_ADMIN)) {
638 irda_device_set_media_busy(dev, TRUE);
639 ret = 0;
640 }
641 break;
642
643 case SIOCGRECEIVING:
644 ret = 0;
645 rq->ifr_receiving = IS_FIR(si) ? 0
646 : si->rx_buff.state != OUTSIDE_FRAME;
647 break;
648
649 default:
650 ret = -EOPNOTSUPP;
651 break;
652 }
653
654 return ret;
655}
656
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100657static void pxa_irda_startup(struct pxa_irda *si)
658{
659 /* Disable STUART interrupts */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200660 stuart_writel(si, 0, STIER);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100661 /* enable STUART interrupt to the processor */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200662 stuart_writel(si, MCR_OUT2, STMCR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100663 /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200664 stuart_writel(si, LCR_WLS0 | LCR_WLS1, STLCR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100665 /* enable FIFO, we use FIFO to improve performance */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200666 stuart_writel(si, FCR_TRFIFOE | FCR_ITL_32, STFCR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100667
668 /* disable FICP */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200669 ficp_writel(si, 0, ICCR0);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100670 /* configure FICP ICCR2 */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200671 ficp_writel(si, ICCR2_TXP | ICCR2_TRIG_32, ICCR2);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100672
673 /* configure DMAC */
Eric Miao87f3dd72008-09-08 15:26:43 +0800674 DRCMR(17) = si->rxdma | DRCMR_MAPVLD;
675 DRCMR(18) = si->txdma | DRCMR_MAPVLD;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100676
677 /* force SIR reinitialization */
678 si->speed = 4000000;
679 pxa_irda_set_speed(si, 9600);
680
681 printk(KERN_DEBUG "pxa_ir: irda startup\n");
682}
683
684static void pxa_irda_shutdown(struct pxa_irda *si)
685{
686 unsigned long flags;
687
688 local_irq_save(flags);
689
690 /* disable STUART and interrupt */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200691 stuart_writel(si, 0, STIER);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100692 /* disable STUART SIR mode */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200693 stuart_writel(si, 0, STISR);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100694
695 /* disable DMA */
696 DCSR(si->txdma) &= ~DCSR_RUN;
697 DCSR(si->rxdma) &= ~DCSR_RUN;
698 /* disable FICP */
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200699 ficp_writel(si, 0, ICCR0);
Russell King82d553c2007-09-02 17:09:23 +0100700
701 /* disable the STUART or FICP clocks */
702 pxa_irda_disable_clk(si);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100703
Eric Miao87f3dd72008-09-08 15:26:43 +0800704 DRCMR(17) = 0;
705 DRCMR(18) = 0;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100706
707 local_irq_restore(flags);
708
709 /* power off board transceiver */
Marek Vasutc4bd0172009-07-17 12:50:43 +0200710 pxa_irda_set_mode(si, IR_OFF);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100711
712 printk(KERN_DEBUG "pxa_ir: irda shutdown\n");
713}
714
715static int pxa_irda_start(struct net_device *dev)
716{
717 struct pxa_irda *si = netdev_priv(dev);
718 int err;
719
720 si->speed = 9600;
721
Rob Herring121f3f92012-08-29 10:31:14 -0500722 err = request_irq(si->uart_irq, pxa_irda_sir_irq, 0, dev->name, dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100723 if (err)
724 goto err_irq1;
725
Rob Herring121f3f92012-08-29 10:31:14 -0500726 err = request_irq(si->icp_irq, pxa_irda_fir_irq, 0, dev->name, dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100727 if (err)
728 goto err_irq2;
729
730 /*
731 * The interrupt must remain disabled for now.
732 */
Rob Herring121f3f92012-08-29 10:31:14 -0500733 disable_irq(si->uart_irq);
734 disable_irq(si->icp_irq);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100735
736 err = -EBUSY;
737 si->rxdma = pxa_request_dma("FICP_RX",DMA_PRIO_LOW, pxa_irda_fir_dma_rx_irq, dev);
738 if (si->rxdma < 0)
739 goto err_rx_dma;
740
741 si->txdma = pxa_request_dma("FICP_TX",DMA_PRIO_LOW, pxa_irda_fir_dma_tx_irq, dev);
742 if (si->txdma < 0)
743 goto err_tx_dma;
744
745 err = -ENOMEM;
746 si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
Joe Perches1f9061d22013-03-15 07:23:58 +0000747 &si->dma_rx_buff_phy, GFP_KERNEL);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100748 if (!si->dma_rx_buff)
749 goto err_dma_rx_buff;
750
751 si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
Joe Perches1f9061d22013-03-15 07:23:58 +0000752 &si->dma_tx_buff_phy, GFP_KERNEL);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100753 if (!si->dma_tx_buff)
754 goto err_dma_tx_buff;
755
756 /* Setup the serial port for the initial speed. */
757 pxa_irda_startup(si);
758
759 /*
760 * Open a new IrLAP layer instance.
761 */
762 si->irlap = irlap_open(dev, &si->qos, "pxa");
763 err = -ENOMEM;
764 if (!si->irlap)
765 goto err_irlap;
766
767 /*
768 * Now enable the interrupt and start the queue
769 */
Rob Herring121f3f92012-08-29 10:31:14 -0500770 enable_irq(si->uart_irq);
771 enable_irq(si->icp_irq);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100772 netif_start_queue(dev);
773
774 printk(KERN_DEBUG "pxa_ir: irda driver opened\n");
775
776 return 0;
777
778err_irlap:
779 pxa_irda_shutdown(si);
780 dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);
781err_dma_tx_buff:
782 dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);
783err_dma_rx_buff:
784 pxa_free_dma(si->txdma);
785err_tx_dma:
786 pxa_free_dma(si->rxdma);
787err_rx_dma:
Rob Herring121f3f92012-08-29 10:31:14 -0500788 free_irq(si->icp_irq, dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100789err_irq2:
Rob Herring121f3f92012-08-29 10:31:14 -0500790 free_irq(si->uart_irq, dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100791err_irq1:
792
793 return err;
794}
795
796static int pxa_irda_stop(struct net_device *dev)
797{
798 struct pxa_irda *si = netdev_priv(dev);
799
800 netif_stop_queue(dev);
801
802 pxa_irda_shutdown(si);
803
804 /* Stop IrLAP */
805 if (si->irlap) {
806 irlap_close(si->irlap);
807 si->irlap = NULL;
808 }
809
Rob Herring121f3f92012-08-29 10:31:14 -0500810 free_irq(si->uart_irq, dev);
811 free_irq(si->icp_irq, dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100812
813 pxa_free_dma(si->rxdma);
814 pxa_free_dma(si->txdma);
815
816 if (si->dma_rx_buff)
817 dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy);
818 if (si->dma_tx_buff)
819 dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy);
820
821 printk(KERN_DEBUG "pxa_ir: irda driver closed\n");
822 return 0;
823}
824
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800825static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100826{
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800827 struct net_device *dev = platform_get_drvdata(_dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100828 struct pxa_irda *si;
829
Richard Purdie91e1a512005-10-30 14:38:52 +0000830 if (dev && netif_running(dev)) {
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100831 si = netdev_priv(dev);
832 netif_device_detach(dev);
833 pxa_irda_shutdown(si);
834 }
835
836 return 0;
837}
838
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800839static int pxa_irda_resume(struct platform_device *_dev)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100840{
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800841 struct net_device *dev = platform_get_drvdata(_dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100842 struct pxa_irda *si;
843
Richard Purdie91e1a512005-10-30 14:38:52 +0000844 if (dev && netif_running(dev)) {
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100845 si = netdev_priv(dev);
846 pxa_irda_startup(si);
847 netif_device_attach(dev);
848 netif_wake_queue(dev);
849 }
850
851 return 0;
852}
853
854
855static int pxa_irda_init_iobuf(iobuff_t *io, int size)
856{
857 io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
858 if (io->head != NULL) {
859 io->truesize = size;
860 io->in_frame = FALSE;
861 io->state = OUTSIDE_FRAME;
862 io->data = io->head;
863 }
864 return io->head ? 0 : -ENOMEM;
865}
866
Alexander Beregalovc76ccd62009-04-15 12:52:41 +0000867static const struct net_device_ops pxa_irda_netdev_ops = {
868 .ndo_open = pxa_irda_start,
869 .ndo_stop = pxa_irda_stop,
870 .ndo_start_xmit = pxa_irda_hard_xmit,
871 .ndo_do_ioctl = pxa_irda_ioctl,
Alexander Beregalovc76ccd62009-04-15 12:52:41 +0000872};
873
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800874static int pxa_irda_probe(struct platform_device *pdev)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100875{
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100876 struct net_device *dev;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200877 struct resource *res;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100878 struct pxa_irda *si;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200879 void __iomem *ficp, *stuart;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100880 unsigned int baudrate_mask;
881 int err;
882
883 if (!pdev->dev.platform_data)
884 return -ENODEV;
885
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200886 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
887 ficp = devm_ioremap_resource(&pdev->dev, res);
888 if (IS_ERR(ficp)) {
889 dev_err(&pdev->dev, "resource ficp not defined\n");
890 return PTR_ERR(ficp);
891 }
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100892
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200893 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
894 stuart = devm_ioremap_resource(&pdev->dev, res);
895 if (IS_ERR(stuart)) {
896 dev_err(&pdev->dev, "resource stuart not defined\n");
897 return PTR_ERR(stuart);
898 }
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100899
900 dev = alloc_irdadev(sizeof(struct pxa_irda));
Peter Senna Tschudincbd841c2012-10-05 11:33:05 +0000901 if (!dev) {
902 err = -ENOMEM;
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200903 goto err_mem_1;
Peter Senna Tschudincbd841c2012-10-05 11:33:05 +0000904 }
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100905
Marek Vasutd2f3ad42009-08-23 22:57:30 -0700906 SET_NETDEV_DEV(dev, &pdev->dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100907 si = netdev_priv(dev);
908 si->dev = &pdev->dev;
909 si->pdata = pdev->dev.platform_data;
910
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200911 si->irda_base = ficp;
912 si->stuart_base = stuart;
Rob Herring121f3f92012-08-29 10:31:14 -0500913 si->uart_irq = platform_get_irq(pdev, 0);
914 si->icp_irq = platform_get_irq(pdev, 1);
915
Robert Jarzmik89fa5722015-09-26 20:49:19 +0200916 si->sir_clk = devm_clk_get(&pdev->dev, "UARTCLK");
917 si->fir_clk = devm_clk_get(&pdev->dev, "FICPCLK");
Russell King82d553c2007-09-02 17:09:23 +0100918 if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) {
919 err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk);
920 goto err_mem_4;
921 }
922
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100923 /*
924 * Initialise the SIR buffers
925 */
926 err = pxa_irda_init_iobuf(&si->rx_buff, 14384);
927 if (err)
928 goto err_mem_4;
929 err = pxa_irda_init_iobuf(&si->tx_buff, 4000);
930 if (err)
931 goto err_mem_5;
932
Marek Vasutc4bd0172009-07-17 12:50:43 +0200933 if (gpio_is_valid(si->pdata->gpio_pwdown)) {
934 err = gpio_request(si->pdata->gpio_pwdown, "IrDA switch");
935 if (err)
936 goto err_startup;
937 err = gpio_direction_output(si->pdata->gpio_pwdown,
938 !si->pdata->gpio_pwdown_inverted);
939 if (err) {
940 gpio_free(si->pdata->gpio_pwdown);
941 goto err_startup;
942 }
943 }
944
945 if (si->pdata->startup) {
Dmitry Baryshkovbaf1c5d2008-04-12 20:08:16 +0100946 err = si->pdata->startup(si->dev);
Marek Vasutc4bd0172009-07-17 12:50:43 +0200947 if (err)
948 goto err_startup;
949 }
950
951 if (gpio_is_valid(si->pdata->gpio_pwdown) && si->pdata->startup)
952 dev_warn(si->dev, "gpio_pwdown and startup() both defined!\n");
Dmitry Baryshkovbaf1c5d2008-04-12 20:08:16 +0100953
Alexander Beregalovc76ccd62009-04-15 12:52:41 +0000954 dev->netdev_ops = &pxa_irda_netdev_ops;
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100955
956 irda_init_max_qos_capabilies(&si->qos);
957
958 baudrate_mask = 0;
959 if (si->pdata->transceiver_cap & IR_SIRMODE)
960 baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
961 if (si->pdata->transceiver_cap & IR_FIRMODE)
962 baudrate_mask |= IR_4000000 << 8;
963
964 si->qos.baud_rate.bits &= baudrate_mask;
965 si->qos.min_turn_time.bits = 7; /* 1ms or more */
966
967 irda_qos_bits_to_value(&si->qos);
968
969 err = register_netdev(dev);
970
971 if (err == 0)
Libo Chen9bcadae2013-08-21 18:15:11 +0800972 platform_set_drvdata(pdev, dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100973
974 if (err) {
Dmitry Baryshkovbaf1c5d2008-04-12 20:08:16 +0100975 if (si->pdata->shutdown)
976 si->pdata->shutdown(si->dev);
977err_startup:
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100978 kfree(si->tx_buff.head);
979err_mem_5:
980 kfree(si->rx_buff.head);
981err_mem_4:
982 free_netdev(dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100983 }
984err_mem_1:
985 return err;
986}
987
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800988static int pxa_irda_remove(struct platform_device *_dev)
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100989{
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -0800990 struct net_device *dev = platform_get_drvdata(_dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100991
992 if (dev) {
993 struct pxa_irda *si = netdev_priv(dev);
994 unregister_netdev(dev);
Marek Vasutc4bd0172009-07-17 12:50:43 +0200995 if (gpio_is_valid(si->pdata->gpio_pwdown))
996 gpio_free(si->pdata->gpio_pwdown);
Dmitry Baryshkovbaf1c5d2008-04-12 20:08:16 +0100997 if (si->pdata->shutdown)
998 si->pdata->shutdown(si->dev);
Nicolas Pitre6f475c02005-10-28 16:39:33 +0100999 kfree(si->tx_buff.head);
1000 kfree(si->rx_buff.head);
1001 free_netdev(dev);
1002 }
1003
Nicolas Pitre6f475c02005-10-28 16:39:33 +01001004 return 0;
1005}
1006
Paul Sokolovskyb259e7d2006-12-06 20:07:59 -08001007static struct platform_driver pxa_ir_driver = {
1008 .driver = {
1009 .name = "pxa2xx-ir",
1010 },
Nicolas Pitre6f475c02005-10-28 16:39:33 +01001011 .probe = pxa_irda_probe,
1012 .remove = pxa_irda_remove,
1013 .suspend = pxa_irda_suspend,
1014 .resume = pxa_irda_resume,
1015};
1016
Axel Lin8b7ff202011-11-27 20:29:11 -05001017module_platform_driver(pxa_ir_driver);
Nicolas Pitre6f475c02005-10-28 16:39:33 +01001018
1019MODULE_LICENSE("GPL");
Kay Sievers72abb462008-04-18 13:50:44 -07001020MODULE_ALIAS("platform:pxa2xx-ir");