Commit | Line | Data |
---|---|---|
6f475c01 NP |
1 | /* |
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 | */ | |
b7f080cf | 15 | #include <linux/dma-mapping.h> |
a6b7a407 | 16 | #include <linux/interrupt.h> |
6f475c01 | 17 | #include <linux/module.h> |
6f475c01 | 18 | #include <linux/netdevice.h> |
f6a26293 | 19 | #include <linux/etherdevice.h> |
d052d1be | 20 | #include <linux/platform_device.h> |
82d553c6 | 21 | #include <linux/clk.h> |
1273bc57 RJ |
22 | #include <linux/dmaengine.h> |
23 | #include <linux/dma-mapping.h> | |
24 | #include <linux/dma/pxa-dma.h> | |
c4bd0172 | 25 | #include <linux/gpio.h> |
5a0e3ad6 | 26 | #include <linux/slab.h> |
6f475c01 NP |
27 | |
28 | #include <net/irda/irda.h> | |
29 | #include <net/irda/irmod.h> | |
30 | #include <net/irda/wrapper.h> | |
31 | #include <net/irda/irda_device.h> | |
32 | ||
293b2da1 | 33 | #include <linux/platform_data/irda-pxaficp.h> |
89fa5724 RJ |
34 | #undef __REG |
35 | #define __REG(x) ((x) & 0xffff) | |
121f3f9b | 36 | #include <mach/regs-uart.h> |
6f475c01 | 37 | |
89fa5724 RJ |
38 | #define ICCR0 0x0000 /* ICP Control Register 0 */ |
39 | #define ICCR1 0x0004 /* ICP Control Register 1 */ | |
40 | #define ICCR2 0x0008 /* ICP Control Register 2 */ | |
41 | #define ICDR 0x000c /* ICP Data Register */ | |
42 | #define ICSR0 0x0014 /* ICP Status Register 0 */ | |
43 | #define ICSR1 0x0018 /* ICP Status Register 1 */ | |
b40ddf57 EM |
44 | |
45 | #define ICCR0_AME (1 << 7) /* Address match enable */ | |
46 | #define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */ | |
25985edc | 47 | #define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */ |
b40ddf57 EM |
48 | #define ICCR0_RXE (1 << 4) /* Receive enable */ |
49 | #define ICCR0_TXE (1 << 3) /* Transmit enable */ | |
50 | #define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */ | |
51 | #define ICCR0_LBM (1 << 1) /* Loopback mode */ | |
52 | #define ICCR0_ITR (1 << 0) /* IrDA transmission */ | |
53 | ||
54 | #define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */ | |
55 | #define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */ | |
56 | #define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */ | |
57 | #define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */ | |
58 | #define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */ | |
59 | #define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */ | |
60 | ||
b40ddf57 | 61 | #define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */ |
b40ddf57 EM |
62 | #define ICSR0_FRE (1 << 5) /* Framing error */ |
63 | #define ICSR0_RFS (1 << 4) /* Receive FIFO service request */ | |
64 | #define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */ | |
65 | #define ICSR0_RAB (1 << 2) /* Receiver abort */ | |
66 | #define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */ | |
67 | #define ICSR0_EIF (1 << 0) /* End/Error in FIFO */ | |
68 | ||
69 | #define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */ | |
70 | #define ICSR1_CRE (1 << 5) /* CRC error */ | |
71 | #define ICSR1_EOF (1 << 4) /* End of frame */ | |
72 | #define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */ | |
73 | #define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */ | |
74 | #define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */ | |
75 | #define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */ | |
6f475c01 | 76 | |
6f475c01 NP |
77 | #define IrSR_RXPL_NEG_IS_ZERO (1<<4) |
78 | #define IrSR_RXPL_POS_IS_ZERO 0x0 | |
79 | #define IrSR_TXPL_NEG_IS_ZERO (1<<3) | |
80 | #define IrSR_TXPL_POS_IS_ZERO 0x0 | |
81 | #define IrSR_XMODE_PULSE_1_6 (1<<2) | |
82 | #define IrSR_XMODE_PULSE_3_16 0x0 | |
83 | #define IrSR_RCVEIR_IR_MODE (1<<1) | |
84 | #define IrSR_RCVEIR_UART_MODE 0x0 | |
85 | #define IrSR_XMITIR_IR_MODE (1<<0) | |
86 | #define IrSR_XMITIR_UART_MODE 0x0 | |
87 | ||
88 | #define IrSR_IR_RECEIVE_ON (\ | |
89 | IrSR_RXPL_NEG_IS_ZERO | \ | |
90 | IrSR_TXPL_POS_IS_ZERO | \ | |
91 | IrSR_XMODE_PULSE_3_16 | \ | |
92 | IrSR_RCVEIR_IR_MODE | \ | |
93 | IrSR_XMITIR_UART_MODE) | |
94 | ||
95 | #define IrSR_IR_TRANSMIT_ON (\ | |
96 | IrSR_RXPL_NEG_IS_ZERO | \ | |
97 | IrSR_TXPL_POS_IS_ZERO | \ | |
98 | IrSR_XMODE_PULSE_3_16 | \ | |
99 | IrSR_RCVEIR_UART_MODE | \ | |
100 | IrSR_XMITIR_IR_MODE) | |
101 | ||
89fa5724 RJ |
102 | /* macros for registers read/write */ |
103 | #define ficp_writel(irda, val, off) \ | |
104 | do { \ | |
105 | dev_vdbg(irda->dev, \ | |
106 | "%s():%d ficp_writel(0x%x, %s)\n", \ | |
107 | __func__, __LINE__, (val), #off); \ | |
108 | writel_relaxed((val), (irda)->irda_base + (off)); \ | |
109 | } while (0) | |
110 | ||
111 | #define ficp_readl(irda, off) \ | |
112 | ({ \ | |
113 | unsigned int _v; \ | |
114 | _v = readl_relaxed((irda)->irda_base + (off)); \ | |
115 | dev_vdbg(irda->dev, \ | |
116 | "%s():%d ficp_readl(%s): 0x%x\n", \ | |
117 | __func__, __LINE__, #off, _v); \ | |
118 | _v; \ | |
119 | }) | |
120 | ||
121 | #define stuart_writel(irda, val, off) \ | |
122 | do { \ | |
123 | dev_vdbg(irda->dev, \ | |
124 | "%s():%d stuart_writel(0x%x, %s)\n", \ | |
125 | __func__, __LINE__, (val), #off); \ | |
126 | writel_relaxed((val), (irda)->stuart_base + (off)); \ | |
127 | } while (0) | |
128 | ||
129 | #define stuart_readl(irda, off) \ | |
130 | ({ \ | |
131 | unsigned int _v; \ | |
132 | _v = readl_relaxed((irda)->stuart_base + (off)); \ | |
133 | dev_vdbg(irda->dev, \ | |
134 | "%s():%d stuart_readl(%s): 0x%x\n", \ | |
135 | __func__, __LINE__, #off, _v); \ | |
136 | _v; \ | |
137 | }) | |
138 | ||
6f475c01 NP |
139 | struct pxa_irda { |
140 | int speed; | |
141 | int newspeed; | |
be01891e | 142 | unsigned long long last_clk; |
6f475c01 | 143 | |
89fa5724 RJ |
144 | void __iomem *stuart_base; |
145 | void __iomem *irda_base; | |
6f475c01 NP |
146 | unsigned char *dma_rx_buff; |
147 | unsigned char *dma_tx_buff; | |
148 | dma_addr_t dma_rx_buff_phy; | |
149 | dma_addr_t dma_tx_buff_phy; | |
150 | unsigned int dma_tx_buff_len; | |
1273bc57 RJ |
151 | struct dma_chan *txdma; |
152 | struct dma_chan *rxdma; | |
153 | dma_cookie_t rx_cookie; | |
154 | dma_cookie_t tx_cookie; | |
155 | int drcmr_rx; | |
156 | int drcmr_tx; | |
6f475c01 | 157 | |
121f3f9b RH |
158 | int uart_irq; |
159 | int icp_irq; | |
160 | ||
6f475c01 NP |
161 | struct irlap_cb *irlap; |
162 | struct qos_info qos; | |
163 | ||
164 | iobuff_t tx_buff; | |
165 | iobuff_t rx_buff; | |
166 | ||
167 | struct device *dev; | |
168 | struct pxaficp_platform_data *pdata; | |
82d553c6 RK |
169 | struct clk *fir_clk; |
170 | struct clk *sir_clk; | |
171 | struct clk *cur_clk; | |
6f475c01 NP |
172 | }; |
173 | ||
1273bc57 RJ |
174 | static int pxa_irda_set_speed(struct pxa_irda *si, int speed); |
175 | ||
82d553c6 RK |
176 | static inline void pxa_irda_disable_clk(struct pxa_irda *si) |
177 | { | |
178 | if (si->cur_clk) | |
4823cd38 | 179 | clk_disable_unprepare(si->cur_clk); |
82d553c6 RK |
180 | si->cur_clk = NULL; |
181 | } | |
182 | ||
183 | static inline void pxa_irda_enable_firclk(struct pxa_irda *si) | |
184 | { | |
185 | si->cur_clk = si->fir_clk; | |
4823cd38 | 186 | clk_prepare_enable(si->fir_clk); |
82d553c6 RK |
187 | } |
188 | ||
189 | static inline void pxa_irda_enable_sirclk(struct pxa_irda *si) | |
190 | { | |
191 | si->cur_clk = si->sir_clk; | |
4823cd38 | 192 | clk_prepare_enable(si->sir_clk); |
82d553c6 RK |
193 | } |
194 | ||
6f475c01 NP |
195 | |
196 | #define IS_FIR(si) ((si)->speed >= 4000000) | |
197 | #define IRDA_FRAME_SIZE_LIMIT 2047 | |
198 | ||
1273bc57 RJ |
199 | static void pxa_irda_fir_dma_rx_irq(void *data); |
200 | static void pxa_irda_fir_dma_tx_irq(void *data); | |
201 | ||
6f475c01 NP |
202 | inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si) |
203 | { | |
1273bc57 RJ |
204 | struct dma_async_tx_descriptor *tx; |
205 | ||
206 | tx = dmaengine_prep_slave_single(si->rxdma, si->dma_rx_buff_phy, | |
207 | IRDA_FRAME_SIZE_LIMIT, DMA_FROM_DEVICE, | |
208 | DMA_PREP_INTERRUPT); | |
209 | if (!tx) { | |
210 | dev_err(si->dev, "prep_slave_sg() failed\n"); | |
211 | return; | |
212 | } | |
213 | tx->callback = pxa_irda_fir_dma_rx_irq; | |
214 | tx->callback_param = si; | |
215 | si->rx_cookie = dmaengine_submit(tx); | |
216 | dma_async_issue_pending(si->rxdma); | |
6f475c01 NP |
217 | } |
218 | ||
219 | inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si) | |
220 | { | |
1273bc57 RJ |
221 | struct dma_async_tx_descriptor *tx; |
222 | ||
223 | tx = dmaengine_prep_slave_single(si->txdma, si->dma_tx_buff_phy, | |
224 | si->dma_tx_buff_len, DMA_TO_DEVICE, | |
225 | DMA_PREP_INTERRUPT); | |
226 | if (!tx) { | |
227 | dev_err(si->dev, "prep_slave_sg() failed\n"); | |
228 | return; | |
229 | } | |
230 | tx->callback = pxa_irda_fir_dma_tx_irq; | |
231 | tx->callback_param = si; | |
232 | si->tx_cookie = dmaengine_submit(tx); | |
233 | dma_async_issue_pending(si->rxdma); | |
6f475c01 NP |
234 | } |
235 | ||
c4bd0172 MV |
236 | /* |
237 | * Set the IrDA communications mode. | |
238 | */ | |
239 | static void pxa_irda_set_mode(struct pxa_irda *si, int mode) | |
240 | { | |
241 | if (si->pdata->transceiver_mode) | |
242 | si->pdata->transceiver_mode(si->dev, mode); | |
243 | else { | |
244 | if (gpio_is_valid(si->pdata->gpio_pwdown)) | |
245 | gpio_set_value(si->pdata->gpio_pwdown, | |
246 | !(mode & IR_OFF) ^ | |
247 | !si->pdata->gpio_pwdown_inverted); | |
248 | pxa2xx_transceiver_mode(si->dev, mode); | |
249 | } | |
250 | } | |
251 | ||
6f475c01 NP |
252 | /* |
253 | * Set the IrDA communications speed. | |
254 | */ | |
255 | static int pxa_irda_set_speed(struct pxa_irda *si, int speed) | |
256 | { | |
257 | unsigned long flags; | |
258 | unsigned int divisor; | |
259 | ||
260 | switch (speed) { | |
261 | case 9600: case 19200: case 38400: | |
262 | case 57600: case 115200: | |
263 | ||
264 | /* refer to PXA250/210 Developer's Manual 10-7 */ | |
265 | /* BaudRate = 14.7456 MHz / (16*Divisor) */ | |
266 | divisor = 14745600 / (16 * speed); | |
267 | ||
268 | local_irq_save(flags); | |
269 | ||
270 | if (IS_FIR(si)) { | |
271 | /* stop RX DMA */ | |
1273bc57 | 272 | dmaengine_terminate_all(si->rxdma); |
6f475c01 | 273 | /* disable FICP */ |
89fa5724 | 274 | ficp_writel(si, 0, ICCR0); |
82d553c6 | 275 | pxa_irda_disable_clk(si); |
6f475c01 NP |
276 | |
277 | /* set board transceiver to SIR mode */ | |
c4bd0172 | 278 | pxa_irda_set_mode(si, IR_SIRMODE); |
6f475c01 | 279 | |
6f475c01 | 280 | /* enable the STUART clock */ |
82d553c6 | 281 | pxa_irda_enable_sirclk(si); |
6f475c01 NP |
282 | } |
283 | ||
284 | /* disable STUART first */ | |
89fa5724 | 285 | stuart_writel(si, 0, STIER); |
6f475c01 NP |
286 | |
287 | /* access DLL & DLH */ | |
89fa5724 RJ |
288 | stuart_writel(si, stuart_readl(si, STLCR) | LCR_DLAB, STLCR); |
289 | stuart_writel(si, divisor & 0xff, STDLL); | |
290 | stuart_writel(si, divisor >> 8, STDLH); | |
291 | stuart_writel(si, stuart_readl(si, STLCR) & ~LCR_DLAB, STLCR); | |
6f475c01 NP |
292 | |
293 | si->speed = speed; | |
89fa5724 RJ |
294 | stuart_writel(si, IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6, |
295 | STISR); | |
296 | stuart_writel(si, IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE, | |
297 | STIER); | |
6f475c01 NP |
298 | |
299 | local_irq_restore(flags); | |
300 | break; | |
301 | ||
302 | case 4000000: | |
303 | local_irq_save(flags); | |
304 | ||
305 | /* disable STUART */ | |
89fa5724 RJ |
306 | stuart_writel(si, 0, STIER); |
307 | stuart_writel(si, 0, STISR); | |
82d553c6 | 308 | pxa_irda_disable_clk(si); |
6f475c01 NP |
309 | |
310 | /* disable FICP first */ | |
89fa5724 | 311 | ficp_writel(si, 0, ICCR0); |
6f475c01 NP |
312 | |
313 | /* set board transceiver to FIR mode */ | |
c4bd0172 | 314 | pxa_irda_set_mode(si, IR_FIRMODE); |
6f475c01 | 315 | |
6f475c01 | 316 | /* enable the FICP clock */ |
82d553c6 | 317 | pxa_irda_enable_firclk(si); |
6f475c01 NP |
318 | |
319 | si->speed = speed; | |
320 | pxa_irda_fir_dma_rx_start(si); | |
89fa5724 | 321 | ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); |
6f475c01 NP |
322 | |
323 | local_irq_restore(flags); | |
324 | break; | |
325 | ||
326 | default: | |
327 | return -EINVAL; | |
328 | } | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | /* SIR interrupt service routine. */ | |
7d12e780 | 334 | static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) |
6f475c01 NP |
335 | { |
336 | struct net_device *dev = dev_id; | |
337 | struct pxa_irda *si = netdev_priv(dev); | |
338 | int iir, lsr, data; | |
339 | ||
89fa5724 | 340 | iir = stuart_readl(si, STIIR); |
6f475c01 NP |
341 | |
342 | switch (iir & 0x0F) { | |
343 | case 0x06: /* Receiver Line Status */ | |
89fa5724 | 344 | lsr = stuart_readl(si, STLSR); |
6f475c01 | 345 | while (lsr & LSR_FIFOE) { |
89fa5724 | 346 | data = stuart_readl(si, STRBR); |
6f475c01 NP |
347 | if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { |
348 | printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); | |
af049081 | 349 | dev->stats.rx_errors++; |
6f475c01 | 350 | if (lsr & LSR_FE) |
af049081 | 351 | dev->stats.rx_frame_errors++; |
6f475c01 | 352 | if (lsr & LSR_OE) |
af049081 | 353 | dev->stats.rx_fifo_errors++; |
6f475c01 | 354 | } else { |
af049081 SH |
355 | dev->stats.rx_bytes++; |
356 | async_unwrap_char(dev, &dev->stats, | |
357 | &si->rx_buff, data); | |
6f475c01 | 358 | } |
89fa5724 | 359 | lsr = stuart_readl(si, STLSR); |
6f475c01 | 360 | } |
be01891e | 361 | si->last_clk = sched_clock(); |
6f475c01 NP |
362 | break; |
363 | ||
364 | case 0x04: /* Received Data Available */ | |
365 | /* forth through */ | |
366 | ||
367 | case 0x0C: /* Character Timeout Indication */ | |
368 | do { | |
af049081 | 369 | dev->stats.rx_bytes++; |
89fa5724 RJ |
370 | async_unwrap_char(dev, &dev->stats, &si->rx_buff, |
371 | stuart_readl(si, STRBR)); | |
372 | } while (stuart_readl(si, STLSR) & LSR_DR); | |
be01891e | 373 | si->last_clk = sched_clock(); |
6f475c01 NP |
374 | break; |
375 | ||
376 | case 0x02: /* Transmit FIFO Data Request */ | |
89fa5724 RJ |
377 | while ((si->tx_buff.len) && |
378 | (stuart_readl(si, STLSR) & LSR_TDRQ)) { | |
379 | stuart_writel(si, *si->tx_buff.data++, STTHR); | |
6f475c01 NP |
380 | si->tx_buff.len -= 1; |
381 | } | |
382 | ||
383 | if (si->tx_buff.len == 0) { | |
af049081 SH |
384 | dev->stats.tx_packets++; |
385 | dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; | |
6f475c01 NP |
386 | |
387 | /* We need to ensure that the transmitter has finished. */ | |
89fa5724 | 388 | while ((stuart_readl(si, STLSR) & LSR_TEMT) == 0) |
6f475c01 | 389 | cpu_relax(); |
be01891e | 390 | si->last_clk = sched_clock(); |
6f475c01 NP |
391 | |
392 | /* | |
393 | * Ok, we've finished transmitting. Now enable | |
394 | * the receiver. Sometimes we get a receive IRQ | |
395 | * immediately after a transmit... | |
396 | */ | |
397 | if (si->newspeed) { | |
398 | pxa_irda_set_speed(si, si->newspeed); | |
399 | si->newspeed = 0; | |
400 | } else { | |
401 | /* enable IR Receiver, disable IR Transmitter */ | |
89fa5724 RJ |
402 | stuart_writel(si, IrSR_IR_RECEIVE_ON | |
403 | IrSR_XMODE_PULSE_1_6, STISR); | |
6f475c01 | 404 | /* enable STUART and receive interrupts */ |
89fa5724 RJ |
405 | stuart_writel(si, IER_UUE | IER_RLSE | |
406 | IER_RAVIE | IER_RTIOE, STIER); | |
6f475c01 NP |
407 | } |
408 | /* I'm hungry! */ | |
409 | netif_wake_queue(dev); | |
410 | } | |
411 | break; | |
412 | } | |
413 | ||
414 | return IRQ_HANDLED; | |
415 | } | |
416 | ||
417 | /* FIR Receive DMA interrupt handler */ | |
1273bc57 | 418 | static void pxa_irda_fir_dma_rx_irq(void *data) |
6f475c01 | 419 | { |
1273bc57 RJ |
420 | struct net_device *dev = data; |
421 | struct pxa_irda *si = netdev_priv(dev); | |
6f475c01 | 422 | |
1273bc57 RJ |
423 | dmaengine_terminate_all(si->rxdma); |
424 | netdev_dbg(dev, "pxa_ir: fir rx dma bus error\n"); | |
6f475c01 NP |
425 | } |
426 | ||
427 | /* FIR Transmit DMA interrupt handler */ | |
1273bc57 | 428 | static void pxa_irda_fir_dma_tx_irq(void *data) |
6f475c01 NP |
429 | { |
430 | struct net_device *dev = data; | |
431 | struct pxa_irda *si = netdev_priv(dev); | |
6f475c01 | 432 | |
1273bc57 RJ |
433 | dmaengine_terminate_all(si->txdma); |
434 | if (dmaengine_tx_status(si->txdma, si->tx_cookie, NULL) == DMA_ERROR) { | |
435 | dev->stats.tx_errors++; | |
436 | } else { | |
af049081 SH |
437 | dev->stats.tx_packets++; |
438 | dev->stats.tx_bytes += si->dma_tx_buff_len; | |
6f475c01 NP |
439 | } |
440 | ||
89fa5724 | 441 | while (ficp_readl(si, ICSR1) & ICSR1_TBY) |
6f475c01 | 442 | cpu_relax(); |
be01891e | 443 | si->last_clk = sched_clock(); |
6f475c01 NP |
444 | |
445 | /* | |
446 | * HACK: It looks like the TBY bit is dropped too soon. | |
447 | * Without this delay things break. | |
448 | */ | |
449 | udelay(120); | |
450 | ||
451 | if (si->newspeed) { | |
452 | pxa_irda_set_speed(si, si->newspeed); | |
453 | si->newspeed = 0; | |
454 | } else { | |
9a4d93d4 GL |
455 | int i = 64; |
456 | ||
89fa5724 | 457 | ficp_writel(si, 0, ICCR0); |
6f475c01 | 458 | pxa_irda_fir_dma_rx_start(si); |
89fa5724 RJ |
459 | while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--) |
460 | ficp_readl(si, ICDR); | |
461 | ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); | |
9a4d93d4 GL |
462 | |
463 | if (i < 0) | |
464 | printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); | |
6f475c01 NP |
465 | } |
466 | netif_wake_queue(dev); | |
467 | } | |
468 | ||
469 | /* EIF(Error in FIFO/End in Frame) handler for FIR */ | |
9a4d93d4 | 470 | static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0) |
6f475c01 NP |
471 | { |
472 | unsigned int len, stat, data; | |
1273bc57 | 473 | struct dma_tx_state state; |
6f475c01 NP |
474 | |
475 | /* Get the current data position. */ | |
1273bc57 RJ |
476 | |
477 | dmaengine_tx_status(si->rxdma, si->rx_cookie, &state); | |
478 | len = IRDA_FRAME_SIZE_LIMIT - state.residue; | |
6f475c01 NP |
479 | |
480 | do { | |
481 | /* Read Status, and then Data. */ | |
89fa5724 | 482 | stat = ficp_readl(si, ICSR1); |
6f475c01 | 483 | rmb(); |
89fa5724 | 484 | data = ficp_readl(si, ICDR); |
6f475c01 NP |
485 | |
486 | if (stat & (ICSR1_CRE | ICSR1_ROR)) { | |
af049081 | 487 | dev->stats.rx_errors++; |
6f475c01 NP |
488 | if (stat & ICSR1_CRE) { |
489 | printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); | |
af049081 | 490 | dev->stats.rx_crc_errors++; |
6f475c01 NP |
491 | } |
492 | if (stat & ICSR1_ROR) { | |
493 | printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); | |
af049081 | 494 | dev->stats.rx_over_errors++; |
6f475c01 NP |
495 | } |
496 | } else { | |
497 | si->dma_rx_buff[len++] = data; | |
498 | } | |
499 | /* If we hit the end of frame, there's no point in continuing. */ | |
500 | if (stat & ICSR1_EOF) | |
501 | break; | |
89fa5724 | 502 | } while (ficp_readl(si, ICSR0) & ICSR0_EIF); |
6f475c01 NP |
503 | |
504 | if (stat & ICSR1_EOF) { | |
505 | /* end of frame. */ | |
9a4d93d4 GL |
506 | struct sk_buff *skb; |
507 | ||
508 | if (icsr0 & ICSR0_FRE) { | |
509 | printk(KERN_ERR "pxa_ir: dropping erroneous frame\n"); | |
af049081 | 510 | dev->stats.rx_dropped++; |
9a4d93d4 GL |
511 | return; |
512 | } | |
513 | ||
514 | skb = alloc_skb(len+1,GFP_ATOMIC); | |
6f475c01 NP |
515 | if (!skb) { |
516 | printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); | |
af049081 | 517 | dev->stats.rx_dropped++; |
6f475c01 NP |
518 | return; |
519 | } | |
520 | ||
521 | /* Align IP header to 20 bytes */ | |
522 | skb_reserve(skb, 1); | |
27d7ff46 | 523 | skb_copy_to_linear_data(skb, si->dma_rx_buff, len); |
6f475c01 NP |
524 | skb_put(skb, len); |
525 | ||
526 | /* Feed it to IrLAP */ | |
527 | skb->dev = dev; | |
459a98ed | 528 | skb_reset_mac_header(skb); |
6f475c01 NP |
529 | skb->protocol = htons(ETH_P_IRDA); |
530 | netif_rx(skb); | |
531 | ||
af049081 SH |
532 | dev->stats.rx_packets++; |
533 | dev->stats.rx_bytes += len; | |
6f475c01 NP |
534 | } |
535 | } | |
536 | ||
537 | /* FIR interrupt handler */ | |
7d12e780 | 538 | static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) |
6f475c01 NP |
539 | { |
540 | struct net_device *dev = dev_id; | |
541 | struct pxa_irda *si = netdev_priv(dev); | |
9a4d93d4 | 542 | int icsr0, i = 64; |
6f475c01 NP |
543 | |
544 | /* stop RX DMA */ | |
1273bc57 | 545 | dmaengine_terminate_all(si->rxdma); |
be01891e | 546 | si->last_clk = sched_clock(); |
89fa5724 | 547 | icsr0 = ficp_readl(si, ICSR0); |
6f475c01 NP |
548 | |
549 | if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { | |
550 | if (icsr0 & ICSR0_FRE) { | |
551 | printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); | |
af049081 | 552 | dev->stats.rx_frame_errors++; |
6f475c01 NP |
553 | } else { |
554 | printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); | |
af049081 | 555 | dev->stats.rx_errors++; |
6f475c01 | 556 | } |
89fa5724 | 557 | ficp_writel(si, icsr0 & (ICSR0_FRE | ICSR0_RAB), ICSR0); |
6f475c01 NP |
558 | } |
559 | ||
560 | if (icsr0 & ICSR0_EIF) { | |
25985edc | 561 | /* An error in FIFO occurred, or there is a end of frame */ |
9a4d93d4 | 562 | pxa_irda_fir_irq_eif(si, dev, icsr0); |
6f475c01 NP |
563 | } |
564 | ||
89fa5724 | 565 | ficp_writel(si, 0, ICCR0); |
6f475c01 | 566 | pxa_irda_fir_dma_rx_start(si); |
89fa5724 RJ |
567 | while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--) |
568 | ficp_readl(si, ICDR); | |
569 | ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); | |
6f475c01 | 570 | |
9a4d93d4 GL |
571 | if (i < 0) |
572 | printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); | |
573 | ||
6f475c01 NP |
574 | return IRQ_HANDLED; |
575 | } | |
576 | ||
577 | /* hard_xmit interface of irda device */ | |
578 | static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) | |
579 | { | |
580 | struct pxa_irda *si = netdev_priv(dev); | |
581 | int speed = irda_get_next_speed(skb); | |
582 | ||
583 | /* | |
584 | * Does this packet contain a request to change the interface | |
585 | * speed? If so, remember it until we complete the transmission | |
586 | * of this frame. | |
587 | */ | |
588 | if (speed != si->speed && speed != -1) | |
589 | si->newspeed = speed; | |
590 | ||
591 | /* | |
592 | * If this is an empty frame, we can bypass a lot. | |
593 | */ | |
594 | if (skb->len == 0) { | |
595 | if (si->newspeed) { | |
596 | si->newspeed = 0; | |
597 | pxa_irda_set_speed(si, speed); | |
598 | } | |
599 | dev_kfree_skb(skb); | |
6ed10654 | 600 | return NETDEV_TX_OK; |
6f475c01 NP |
601 | } |
602 | ||
603 | netif_stop_queue(dev); | |
604 | ||
605 | if (!IS_FIR(si)) { | |
606 | si->tx_buff.data = si->tx_buff.head; | |
607 | si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); | |
608 | ||
609 | /* Disable STUART interrupts and switch to transmit mode. */ | |
89fa5724 RJ |
610 | stuart_writel(si, 0, STIER); |
611 | stuart_writel(si, IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6, | |
612 | STISR); | |
6f475c01 NP |
613 | |
614 | /* enable STUART and transmit interrupts */ | |
89fa5724 | 615 | stuart_writel(si, IER_UUE | IER_TIE, STIER); |
6f475c01 NP |
616 | } else { |
617 | unsigned long mtt = irda_get_mtt(skb); | |
618 | ||
619 | si->dma_tx_buff_len = skb->len; | |
d626f62b | 620 | skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len); |
6f475c01 NP |
621 | |
622 | if (mtt) | |
be01891e | 623 | while ((sched_clock() - si->last_clk) * 1000 < mtt) |
6f475c01 NP |
624 | cpu_relax(); |
625 | ||
626 | /* stop RX DMA, disable FICP */ | |
1273bc57 | 627 | dmaengine_terminate_all(si->rxdma); |
89fa5724 | 628 | ficp_writel(si, 0, ICCR0); |
6f475c01 NP |
629 | |
630 | pxa_irda_fir_dma_tx_start(si); | |
89fa5724 | 631 | ficp_writel(si, ICCR0_ITR | ICCR0_TXE, ICCR0); |
6f475c01 NP |
632 | } |
633 | ||
634 | dev_kfree_skb(skb); | |
6ed10654 | 635 | return NETDEV_TX_OK; |
6f475c01 NP |
636 | } |
637 | ||
638 | static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) | |
639 | { | |
640 | struct if_irda_req *rq = (struct if_irda_req *)ifreq; | |
641 | struct pxa_irda *si = netdev_priv(dev); | |
642 | int ret; | |
643 | ||
644 | switch (cmd) { | |
645 | case SIOCSBANDWIDTH: | |
646 | ret = -EPERM; | |
647 | if (capable(CAP_NET_ADMIN)) { | |
648 | /* | |
649 | * We are unable to set the speed if the | |
650 | * device is not running. | |
651 | */ | |
652 | if (netif_running(dev)) { | |
653 | ret = pxa_irda_set_speed(si, | |
654 | rq->ifr_baudrate); | |
655 | } else { | |
656 | printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); | |
657 | ret = 0; | |
658 | } | |
659 | } | |
660 | break; | |
661 | ||
662 | case SIOCSMEDIABUSY: | |
663 | ret = -EPERM; | |
664 | if (capable(CAP_NET_ADMIN)) { | |
665 | irda_device_set_media_busy(dev, TRUE); | |
666 | ret = 0; | |
667 | } | |
668 | break; | |
669 | ||
670 | case SIOCGRECEIVING: | |
671 | ret = 0; | |
672 | rq->ifr_receiving = IS_FIR(si) ? 0 | |
673 | : si->rx_buff.state != OUTSIDE_FRAME; | |
674 | break; | |
675 | ||
676 | default: | |
677 | ret = -EOPNOTSUPP; | |
678 | break; | |
679 | } | |
680 | ||
681 | return ret; | |
682 | } | |
683 | ||
6f475c01 NP |
684 | static void pxa_irda_startup(struct pxa_irda *si) |
685 | { | |
686 | /* Disable STUART interrupts */ | |
89fa5724 | 687 | stuart_writel(si, 0, STIER); |
6f475c01 | 688 | /* enable STUART interrupt to the processor */ |
89fa5724 | 689 | stuart_writel(si, MCR_OUT2, STMCR); |
6f475c01 | 690 | /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */ |
89fa5724 | 691 | stuart_writel(si, LCR_WLS0 | LCR_WLS1, STLCR); |
6f475c01 | 692 | /* enable FIFO, we use FIFO to improve performance */ |
89fa5724 | 693 | stuart_writel(si, FCR_TRFIFOE | FCR_ITL_32, STFCR); |
6f475c01 NP |
694 | |
695 | /* disable FICP */ | |
89fa5724 | 696 | ficp_writel(si, 0, ICCR0); |
6f475c01 | 697 | /* configure FICP ICCR2 */ |
89fa5724 | 698 | ficp_writel(si, ICCR2_TXP | ICCR2_TRIG_32, ICCR2); |
6f475c01 | 699 | |
6f475c01 NP |
700 | /* force SIR reinitialization */ |
701 | si->speed = 4000000; | |
702 | pxa_irda_set_speed(si, 9600); | |
703 | ||
704 | printk(KERN_DEBUG "pxa_ir: irda startup\n"); | |
705 | } | |
706 | ||
707 | static void pxa_irda_shutdown(struct pxa_irda *si) | |
708 | { | |
709 | unsigned long flags; | |
710 | ||
711 | local_irq_save(flags); | |
712 | ||
713 | /* disable STUART and interrupt */ | |
89fa5724 | 714 | stuart_writel(si, 0, STIER); |
6f475c01 | 715 | /* disable STUART SIR mode */ |
89fa5724 | 716 | stuart_writel(si, 0, STISR); |
6f475c01 NP |
717 | |
718 | /* disable DMA */ | |
1273bc57 RJ |
719 | dmaengine_terminate_all(si->rxdma); |
720 | dmaengine_terminate_all(si->txdma); | |
6f475c01 | 721 | /* disable FICP */ |
89fa5724 | 722 | ficp_writel(si, 0, ICCR0); |
82d553c6 RK |
723 | |
724 | /* disable the STUART or FICP clocks */ | |
725 | pxa_irda_disable_clk(si); | |
6f475c01 | 726 | |
6f475c01 NP |
727 | local_irq_restore(flags); |
728 | ||
729 | /* power off board transceiver */ | |
c4bd0172 | 730 | pxa_irda_set_mode(si, IR_OFF); |
6f475c01 NP |
731 | |
732 | printk(KERN_DEBUG "pxa_ir: irda shutdown\n"); | |
733 | } | |
734 | ||
735 | static int pxa_irda_start(struct net_device *dev) | |
736 | { | |
737 | struct pxa_irda *si = netdev_priv(dev); | |
1273bc57 RJ |
738 | dma_cap_mask_t mask; |
739 | struct dma_slave_config config; | |
740 | struct pxad_param param; | |
6f475c01 NP |
741 | int err; |
742 | ||
743 | si->speed = 9600; | |
744 | ||
121f3f9b | 745 | err = request_irq(si->uart_irq, pxa_irda_sir_irq, 0, dev->name, dev); |
6f475c01 NP |
746 | if (err) |
747 | goto err_irq1; | |
748 | ||
121f3f9b | 749 | err = request_irq(si->icp_irq, pxa_irda_fir_irq, 0, dev->name, dev); |
6f475c01 NP |
750 | if (err) |
751 | goto err_irq2; | |
752 | ||
753 | /* | |
754 | * The interrupt must remain disabled for now. | |
755 | */ | |
121f3f9b RH |
756 | disable_irq(si->uart_irq); |
757 | disable_irq(si->icp_irq); | |
6f475c01 NP |
758 | |
759 | err = -EBUSY; | |
1273bc57 RJ |
760 | dma_cap_zero(mask); |
761 | dma_cap_set(DMA_SLAVE, mask); | |
762 | param.prio = PXAD_PRIO_LOWEST; | |
763 | ||
764 | memset(&config, 0, sizeof(config)); | |
765 | config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | |
766 | config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | |
767 | config.src_addr = (dma_addr_t)si->irda_base + ICDR; | |
768 | config.dst_addr = (dma_addr_t)si->irda_base + ICDR; | |
769 | config.src_maxburst = 32; | |
770 | config.dst_maxburst = 32; | |
771 | ||
772 | param.drcmr = si->drcmr_rx; | |
773 | si->rxdma = dma_request_slave_channel_compat(mask, pxad_filter_fn, | |
774 | ¶m, &dev->dev, "rx"); | |
775 | if (!si->rxdma) | |
6f475c01 NP |
776 | goto err_rx_dma; |
777 | ||
1273bc57 RJ |
778 | param.drcmr = si->drcmr_tx; |
779 | si->txdma = dma_request_slave_channel_compat(mask, pxad_filter_fn, | |
780 | ¶m, &dev->dev, "tx"); | |
781 | if (!si->txdma) | |
6f475c01 NP |
782 | goto err_tx_dma; |
783 | ||
1273bc57 RJ |
784 | err = dmaengine_slave_config(si->rxdma, &config); |
785 | if (err) | |
786 | goto err_dma_rx_buff; | |
787 | err = dmaengine_slave_config(si->txdma, &config); | |
788 | if (err) | |
789 | goto err_dma_rx_buff; | |
790 | ||
6f475c01 NP |
791 | err = -ENOMEM; |
792 | si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, | |
1f9061d2 | 793 | &si->dma_rx_buff_phy, GFP_KERNEL); |
6f475c01 NP |
794 | if (!si->dma_rx_buff) |
795 | goto err_dma_rx_buff; | |
796 | ||
797 | si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, | |
1f9061d2 | 798 | &si->dma_tx_buff_phy, GFP_KERNEL); |
6f475c01 NP |
799 | if (!si->dma_tx_buff) |
800 | goto err_dma_tx_buff; | |
801 | ||
802 | /* Setup the serial port for the initial speed. */ | |
803 | pxa_irda_startup(si); | |
804 | ||
805 | /* | |
806 | * Open a new IrLAP layer instance. | |
807 | */ | |
808 | si->irlap = irlap_open(dev, &si->qos, "pxa"); | |
809 | err = -ENOMEM; | |
810 | if (!si->irlap) | |
811 | goto err_irlap; | |
812 | ||
813 | /* | |
814 | * Now enable the interrupt and start the queue | |
815 | */ | |
121f3f9b RH |
816 | enable_irq(si->uart_irq); |
817 | enable_irq(si->icp_irq); | |
6f475c01 NP |
818 | netif_start_queue(dev); |
819 | ||
820 | printk(KERN_DEBUG "pxa_ir: irda driver opened\n"); | |
821 | ||
822 | return 0; | |
823 | ||
824 | err_irlap: | |
825 | pxa_irda_shutdown(si); | |
826 | dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); | |
827 | err_dma_tx_buff: | |
828 | dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); | |
829 | err_dma_rx_buff: | |
1273bc57 | 830 | dma_release_channel(si->txdma); |
6f475c01 | 831 | err_tx_dma: |
1273bc57 | 832 | dma_release_channel(si->rxdma); |
6f475c01 | 833 | err_rx_dma: |
121f3f9b | 834 | free_irq(si->icp_irq, dev); |
6f475c01 | 835 | err_irq2: |
121f3f9b | 836 | free_irq(si->uart_irq, dev); |
6f475c01 NP |
837 | err_irq1: |
838 | ||
839 | return err; | |
840 | } | |
841 | ||
842 | static int pxa_irda_stop(struct net_device *dev) | |
843 | { | |
844 | struct pxa_irda *si = netdev_priv(dev); | |
845 | ||
846 | netif_stop_queue(dev); | |
847 | ||
848 | pxa_irda_shutdown(si); | |
849 | ||
850 | /* Stop IrLAP */ | |
851 | if (si->irlap) { | |
852 | irlap_close(si->irlap); | |
853 | si->irlap = NULL; | |
854 | } | |
855 | ||
121f3f9b RH |
856 | free_irq(si->uart_irq, dev); |
857 | free_irq(si->icp_irq, dev); | |
6f475c01 | 858 | |
1273bc57 RJ |
859 | dmaengine_terminate_all(si->rxdma); |
860 | dmaengine_terminate_all(si->txdma); | |
861 | dma_release_channel(si->rxdma); | |
862 | dma_release_channel(si->txdma); | |
6f475c01 NP |
863 | |
864 | if (si->dma_rx_buff) | |
865 | dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); | |
866 | if (si->dma_tx_buff) | |
867 | dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); | |
868 | ||
869 | printk(KERN_DEBUG "pxa_ir: irda driver closed\n"); | |
870 | return 0; | |
871 | } | |
872 | ||
b259e7d2 | 873 | static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state) |
6f475c01 | 874 | { |
b259e7d2 | 875 | struct net_device *dev = platform_get_drvdata(_dev); |
6f475c01 NP |
876 | struct pxa_irda *si; |
877 | ||
91e1a512 | 878 | if (dev && netif_running(dev)) { |
6f475c01 NP |
879 | si = netdev_priv(dev); |
880 | netif_device_detach(dev); | |
881 | pxa_irda_shutdown(si); | |
882 | } | |
883 | ||
884 | return 0; | |
885 | } | |
886 | ||
b259e7d2 | 887 | static int pxa_irda_resume(struct platform_device *_dev) |
6f475c01 | 888 | { |
b259e7d2 | 889 | struct net_device *dev = platform_get_drvdata(_dev); |
6f475c01 NP |
890 | struct pxa_irda *si; |
891 | ||
91e1a512 | 892 | if (dev && netif_running(dev)) { |
6f475c01 NP |
893 | si = netdev_priv(dev); |
894 | pxa_irda_startup(si); | |
895 | netif_device_attach(dev); | |
896 | netif_wake_queue(dev); | |
897 | } | |
898 | ||
899 | return 0; | |
900 | } | |
901 | ||
902 | ||
903 | static int pxa_irda_init_iobuf(iobuff_t *io, int size) | |
904 | { | |
905 | io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); | |
906 | if (io->head != NULL) { | |
907 | io->truesize = size; | |
908 | io->in_frame = FALSE; | |
909 | io->state = OUTSIDE_FRAME; | |
910 | io->data = io->head; | |
911 | } | |
912 | return io->head ? 0 : -ENOMEM; | |
913 | } | |
914 | ||
c76ccd6a AB |
915 | static const struct net_device_ops pxa_irda_netdev_ops = { |
916 | .ndo_open = pxa_irda_start, | |
917 | .ndo_stop = pxa_irda_stop, | |
918 | .ndo_start_xmit = pxa_irda_hard_xmit, | |
919 | .ndo_do_ioctl = pxa_irda_ioctl, | |
c76ccd6a AB |
920 | }; |
921 | ||
b259e7d2 | 922 | static int pxa_irda_probe(struct platform_device *pdev) |
6f475c01 | 923 | { |
6f475c01 | 924 | struct net_device *dev; |
89fa5724 | 925 | struct resource *res; |
6f475c01 | 926 | struct pxa_irda *si; |
89fa5724 | 927 | void __iomem *ficp, *stuart; |
6f475c01 NP |
928 | unsigned int baudrate_mask; |
929 | int err; | |
930 | ||
931 | if (!pdev->dev.platform_data) | |
932 | return -ENODEV; | |
933 | ||
89fa5724 RJ |
934 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
935 | ficp = devm_ioremap_resource(&pdev->dev, res); | |
936 | if (IS_ERR(ficp)) { | |
937 | dev_err(&pdev->dev, "resource ficp not defined\n"); | |
938 | return PTR_ERR(ficp); | |
939 | } | |
6f475c01 | 940 | |
89fa5724 RJ |
941 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
942 | stuart = devm_ioremap_resource(&pdev->dev, res); | |
943 | if (IS_ERR(stuart)) { | |
944 | dev_err(&pdev->dev, "resource stuart not defined\n"); | |
945 | return PTR_ERR(stuart); | |
946 | } | |
6f475c01 NP |
947 | |
948 | dev = alloc_irdadev(sizeof(struct pxa_irda)); | |
cbd841ca PST |
949 | if (!dev) { |
950 | err = -ENOMEM; | |
89fa5724 | 951 | goto err_mem_1; |
cbd841ca | 952 | } |
6f475c01 | 953 | |
d2f3ad4c | 954 | SET_NETDEV_DEV(dev, &pdev->dev); |
6f475c01 NP |
955 | si = netdev_priv(dev); |
956 | si->dev = &pdev->dev; | |
957 | si->pdata = pdev->dev.platform_data; | |
958 | ||
89fa5724 RJ |
959 | si->irda_base = ficp; |
960 | si->stuart_base = stuart; | |
121f3f9b RH |
961 | si->uart_irq = platform_get_irq(pdev, 0); |
962 | si->icp_irq = platform_get_irq(pdev, 1); | |
963 | ||
89fa5724 RJ |
964 | si->sir_clk = devm_clk_get(&pdev->dev, "UARTCLK"); |
965 | si->fir_clk = devm_clk_get(&pdev->dev, "FICPCLK"); | |
82d553c6 RK |
966 | if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) { |
967 | err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk); | |
968 | goto err_mem_4; | |
969 | } | |
970 | ||
1273bc57 RJ |
971 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
972 | if (res) | |
973 | si->drcmr_rx = res->start; | |
974 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | |
975 | if (res) | |
976 | si->drcmr_tx = res->start; | |
977 | ||
6f475c01 NP |
978 | /* |
979 | * Initialise the SIR buffers | |
980 | */ | |
981 | err = pxa_irda_init_iobuf(&si->rx_buff, 14384); | |
982 | if (err) | |
983 | goto err_mem_4; | |
984 | err = pxa_irda_init_iobuf(&si->tx_buff, 4000); | |
985 | if (err) | |
986 | goto err_mem_5; | |
987 | ||
c4bd0172 MV |
988 | if (gpio_is_valid(si->pdata->gpio_pwdown)) { |
989 | err = gpio_request(si->pdata->gpio_pwdown, "IrDA switch"); | |
990 | if (err) | |
991 | goto err_startup; | |
992 | err = gpio_direction_output(si->pdata->gpio_pwdown, | |
993 | !si->pdata->gpio_pwdown_inverted); | |
994 | if (err) { | |
995 | gpio_free(si->pdata->gpio_pwdown); | |
996 | goto err_startup; | |
997 | } | |
998 | } | |
999 | ||
1000 | if (si->pdata->startup) { | |
baf1c5d2 | 1001 | err = si->pdata->startup(si->dev); |
c4bd0172 MV |
1002 | if (err) |
1003 | goto err_startup; | |
1004 | } | |
1005 | ||
1006 | if (gpio_is_valid(si->pdata->gpio_pwdown) && si->pdata->startup) | |
1007 | dev_warn(si->dev, "gpio_pwdown and startup() both defined!\n"); | |
baf1c5d2 | 1008 | |
c76ccd6a | 1009 | dev->netdev_ops = &pxa_irda_netdev_ops; |
6f475c01 NP |
1010 | |
1011 | irda_init_max_qos_capabilies(&si->qos); | |
1012 | ||
1013 | baudrate_mask = 0; | |
1014 | if (si->pdata->transceiver_cap & IR_SIRMODE) | |
1015 | baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; | |
1016 | if (si->pdata->transceiver_cap & IR_FIRMODE) | |
1017 | baudrate_mask |= IR_4000000 << 8; | |
1018 | ||
1019 | si->qos.baud_rate.bits &= baudrate_mask; | |
1020 | si->qos.min_turn_time.bits = 7; /* 1ms or more */ | |
1021 | ||
1022 | irda_qos_bits_to_value(&si->qos); | |
1023 | ||
1024 | err = register_netdev(dev); | |
1025 | ||
1026 | if (err == 0) | |
9bcadaef | 1027 | platform_set_drvdata(pdev, dev); |
6f475c01 NP |
1028 | |
1029 | if (err) { | |
baf1c5d2 DB |
1030 | if (si->pdata->shutdown) |
1031 | si->pdata->shutdown(si->dev); | |
1032 | err_startup: | |
6f475c01 NP |
1033 | kfree(si->tx_buff.head); |
1034 | err_mem_5: | |
1035 | kfree(si->rx_buff.head); | |
1036 | err_mem_4: | |
1037 | free_netdev(dev); | |
6f475c01 NP |
1038 | } |
1039 | err_mem_1: | |
1040 | return err; | |
1041 | } | |
1042 | ||
b259e7d2 | 1043 | static int pxa_irda_remove(struct platform_device *_dev) |
6f475c01 | 1044 | { |
b259e7d2 | 1045 | struct net_device *dev = platform_get_drvdata(_dev); |
6f475c01 NP |
1046 | |
1047 | if (dev) { | |
1048 | struct pxa_irda *si = netdev_priv(dev); | |
1049 | unregister_netdev(dev); | |
c4bd0172 MV |
1050 | if (gpio_is_valid(si->pdata->gpio_pwdown)) |
1051 | gpio_free(si->pdata->gpio_pwdown); | |
baf1c5d2 DB |
1052 | if (si->pdata->shutdown) |
1053 | si->pdata->shutdown(si->dev); | |
6f475c01 NP |
1054 | kfree(si->tx_buff.head); |
1055 | kfree(si->rx_buff.head); | |
1056 | free_netdev(dev); | |
1057 | } | |
1058 | ||
6f475c01 NP |
1059 | return 0; |
1060 | } | |
1061 | ||
b259e7d2 PS |
1062 | static struct platform_driver pxa_ir_driver = { |
1063 | .driver = { | |
1064 | .name = "pxa2xx-ir", | |
1065 | }, | |
6f475c01 NP |
1066 | .probe = pxa_irda_probe, |
1067 | .remove = pxa_irda_remove, | |
1068 | .suspend = pxa_irda_suspend, | |
1069 | .resume = pxa_irda_resume, | |
1070 | }; | |
1071 | ||
8b7ff200 | 1072 | module_platform_driver(pxa_ir_driver); |
6f475c01 NP |
1073 | |
1074 | MODULE_LICENSE("GPL"); | |
72abb461 | 1075 | MODULE_ALIAS("platform:pxa2xx-ir"); |