]>
Commit | Line | Data |
---|---|---|
bbb84619 BS |
1 | /* |
2 | * Blackfin On-Chip CAN Driver | |
3 | * | |
4 | * Copyright 2004-2009 Analog Devices Inc. | |
5 | * | |
6 | * Enter bugs at http://blackfin.uclinux.org/ | |
7 | * | |
8 | * Licensed under the GPL-2 or later. | |
9 | */ | |
10 | ||
11 | #include <linux/module.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/bitops.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/errno.h> | |
17 | #include <linux/netdevice.h> | |
18 | #include <linux/skbuff.h> | |
19 | #include <linux/platform_device.h> | |
20 | ||
21 | #include <linux/can.h> | |
22 | #include <linux/can/dev.h> | |
23 | #include <linux/can/error.h> | |
24 | ||
25 | #include <asm/portmux.h> | |
26 | ||
27 | #define DRV_NAME "bfin_can" | |
28 | #define BFIN_CAN_TIMEOUT 100 | |
29 | ||
30 | /* | |
31 | * transmit and receive channels | |
32 | */ | |
33 | #define TRANSMIT_CHL 24 | |
34 | #define RECEIVE_STD_CHL 0 | |
35 | #define RECEIVE_EXT_CHL 4 | |
36 | #define RECEIVE_RTR_CHL 8 | |
37 | #define RECEIVE_EXT_RTR_CHL 12 | |
38 | #define MAX_CHL_NUMBER 32 | |
39 | ||
40 | /* | |
41 | * bfin can registers layout | |
42 | */ | |
43 | struct bfin_can_mask_regs { | |
44 | u16 aml; | |
45 | u16 dummy1; | |
46 | u16 amh; | |
47 | u16 dummy2; | |
48 | }; | |
49 | ||
50 | struct bfin_can_channel_regs { | |
51 | u16 data[8]; | |
52 | u16 dlc; | |
53 | u16 dummy1; | |
54 | u16 tsv; | |
55 | u16 dummy2; | |
56 | u16 id0; | |
57 | u16 dummy3; | |
58 | u16 id1; | |
59 | u16 dummy4; | |
60 | }; | |
61 | ||
62 | struct bfin_can_regs { | |
63 | /* | |
64 | * global control and status registers | |
65 | */ | |
66 | u16 mc1; /* offset 0 */ | |
67 | u16 dummy1; | |
68 | u16 md1; /* offset 4 */ | |
69 | u16 rsv1[13]; | |
70 | u16 mbtif1; /* offset 0x20 */ | |
71 | u16 dummy2; | |
72 | u16 mbrif1; /* offset 0x24 */ | |
73 | u16 dummy3; | |
74 | u16 mbim1; /* offset 0x28 */ | |
75 | u16 rsv2[11]; | |
76 | u16 mc2; /* offset 0x40 */ | |
77 | u16 dummy4; | |
78 | u16 md2; /* offset 0x44 */ | |
79 | u16 dummy5; | |
80 | u16 trs2; /* offset 0x48 */ | |
81 | u16 rsv3[11]; | |
82 | u16 mbtif2; /* offset 0x60 */ | |
83 | u16 dummy6; | |
84 | u16 mbrif2; /* offset 0x64 */ | |
85 | u16 dummy7; | |
86 | u16 mbim2; /* offset 0x68 */ | |
87 | u16 rsv4[11]; | |
88 | u16 clk; /* offset 0x80 */ | |
89 | u16 dummy8; | |
90 | u16 timing; /* offset 0x84 */ | |
91 | u16 rsv5[3]; | |
92 | u16 status; /* offset 0x8c */ | |
93 | u16 dummy9; | |
94 | u16 cec; /* offset 0x90 */ | |
95 | u16 dummy10; | |
96 | u16 gis; /* offset 0x94 */ | |
97 | u16 dummy11; | |
98 | u16 gim; /* offset 0x98 */ | |
99 | u16 rsv6[3]; | |
100 | u16 ctrl; /* offset 0xa0 */ | |
101 | u16 dummy12; | |
102 | u16 intr; /* offset 0xa4 */ | |
103 | u16 rsv7[7]; | |
104 | u16 esr; /* offset 0xb4 */ | |
105 | u16 rsv8[37]; | |
106 | ||
107 | /* | |
108 | * channel(mailbox) mask and message registers | |
109 | */ | |
110 | struct bfin_can_mask_regs msk[MAX_CHL_NUMBER]; /* offset 0x100 */ | |
111 | struct bfin_can_channel_regs chl[MAX_CHL_NUMBER]; /* offset 0x200 */ | |
112 | }; | |
113 | ||
114 | /* | |
115 | * bfin can private data | |
116 | */ | |
117 | struct bfin_can_priv { | |
118 | struct can_priv can; /* must be the first member */ | |
119 | struct net_device *dev; | |
120 | void __iomem *membase; | |
121 | int rx_irq; | |
122 | int tx_irq; | |
123 | int err_irq; | |
124 | unsigned short *pin_list; | |
125 | }; | |
126 | ||
127 | /* | |
128 | * bfin can timing parameters | |
129 | */ | |
130 | static struct can_bittiming_const bfin_can_bittiming_const = { | |
131 | .name = DRV_NAME, | |
132 | .tseg1_min = 1, | |
133 | .tseg1_max = 16, | |
134 | .tseg2_min = 1, | |
135 | .tseg2_max = 8, | |
136 | .sjw_max = 4, | |
137 | /* | |
138 | * Although the BRP field can be set to any value, it is recommended | |
139 | * that the value be greater than or equal to 4, as restrictions | |
140 | * apply to the bit timing configuration when BRP is less than 4. | |
141 | */ | |
142 | .brp_min = 4, | |
143 | .brp_max = 1024, | |
144 | .brp_inc = 1, | |
145 | }; | |
146 | ||
147 | static int bfin_can_set_bittiming(struct net_device *dev) | |
148 | { | |
149 | struct bfin_can_priv *priv = netdev_priv(dev); | |
150 | struct bfin_can_regs __iomem *reg = priv->membase; | |
151 | struct can_bittiming *bt = &priv->can.bittiming; | |
152 | u16 clk, timing; | |
153 | ||
154 | clk = bt->brp - 1; | |
155 | timing = ((bt->sjw - 1) << 8) | (bt->prop_seg + bt->phase_seg1 - 1) | | |
156 | ((bt->phase_seg2 - 1) << 4); | |
157 | ||
158 | /* | |
159 | * If the SAM bit is set, the input signal is oversampled three times | |
160 | * at the SCLK rate. | |
161 | */ | |
162 | if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) | |
163 | timing |= SAM; | |
164 | ||
165 | bfin_write16(®->clk, clk); | |
166 | bfin_write16(®->timing, timing); | |
167 | ||
168 | dev_info(dev->dev.parent, "setting CLOCK=0x%04x TIMING=0x%04x\n", | |
169 | clk, timing); | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | static void bfin_can_set_reset_mode(struct net_device *dev) | |
175 | { | |
176 | struct bfin_can_priv *priv = netdev_priv(dev); | |
177 | struct bfin_can_regs __iomem *reg = priv->membase; | |
178 | int timeout = BFIN_CAN_TIMEOUT; | |
179 | int i; | |
180 | ||
181 | /* disable interrupts */ | |
182 | bfin_write16(®->mbim1, 0); | |
183 | bfin_write16(®->mbim2, 0); | |
184 | bfin_write16(®->gim, 0); | |
185 | ||
186 | /* reset can and enter configuration mode */ | |
187 | bfin_write16(®->ctrl, SRS | CCR); | |
188 | SSYNC(); | |
189 | bfin_write16(®->ctrl, CCR); | |
190 | SSYNC(); | |
191 | while (!(bfin_read16(®->ctrl) & CCA)) { | |
192 | udelay(10); | |
193 | if (--timeout == 0) { | |
194 | dev_err(dev->dev.parent, | |
195 | "fail to enter configuration mode\n"); | |
196 | BUG(); | |
197 | } | |
198 | } | |
199 | ||
200 | /* | |
201 | * All mailbox configurations are marked as inactive | |
202 | * by writing to CAN Mailbox Configuration Registers 1 and 2 | |
203 | * For all bits: 0 - Mailbox disabled, 1 - Mailbox enabled | |
204 | */ | |
205 | bfin_write16(®->mc1, 0); | |
206 | bfin_write16(®->mc2, 0); | |
207 | ||
208 | /* Set Mailbox Direction */ | |
209 | bfin_write16(®->md1, 0xFFFF); /* mailbox 1-16 are RX */ | |
210 | bfin_write16(®->md2, 0); /* mailbox 17-32 are TX */ | |
211 | ||
212 | /* RECEIVE_STD_CHL */ | |
213 | for (i = 0; i < 2; i++) { | |
214 | bfin_write16(®->chl[RECEIVE_STD_CHL + i].id0, 0); | |
215 | bfin_write16(®->chl[RECEIVE_STD_CHL + i].id1, AME); | |
216 | bfin_write16(®->chl[RECEIVE_STD_CHL + i].dlc, 0); | |
217 | bfin_write16(®->msk[RECEIVE_STD_CHL + i].amh, 0x1FFF); | |
218 | bfin_write16(®->msk[RECEIVE_STD_CHL + i].aml, 0xFFFF); | |
219 | } | |
220 | ||
221 | /* RECEIVE_EXT_CHL */ | |
222 | for (i = 0; i < 2; i++) { | |
223 | bfin_write16(®->chl[RECEIVE_EXT_CHL + i].id0, 0); | |
224 | bfin_write16(®->chl[RECEIVE_EXT_CHL + i].id1, AME | IDE); | |
225 | bfin_write16(®->chl[RECEIVE_EXT_CHL + i].dlc, 0); | |
226 | bfin_write16(®->msk[RECEIVE_EXT_CHL + i].amh, 0x1FFF); | |
227 | bfin_write16(®->msk[RECEIVE_EXT_CHL + i].aml, 0xFFFF); | |
228 | } | |
229 | ||
230 | bfin_write16(®->mc2, BIT(TRANSMIT_CHL - 16)); | |
231 | bfin_write16(®->mc1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL)); | |
232 | SSYNC(); | |
233 | ||
234 | priv->can.state = CAN_STATE_STOPPED; | |
235 | } | |
236 | ||
237 | static void bfin_can_set_normal_mode(struct net_device *dev) | |
238 | { | |
239 | struct bfin_can_priv *priv = netdev_priv(dev); | |
240 | struct bfin_can_regs __iomem *reg = priv->membase; | |
241 | int timeout = BFIN_CAN_TIMEOUT; | |
242 | ||
243 | /* | |
244 | * leave configuration mode | |
245 | */ | |
246 | bfin_write16(®->ctrl, bfin_read16(®->ctrl) & ~CCR); | |
247 | ||
248 | while (bfin_read16(®->status) & CCA) { | |
249 | udelay(10); | |
250 | if (--timeout == 0) { | |
251 | dev_err(dev->dev.parent, | |
252 | "fail to leave configuration mode\n"); | |
253 | BUG(); | |
254 | } | |
255 | } | |
256 | ||
257 | /* | |
258 | * clear _All_ tx and rx interrupts | |
259 | */ | |
260 | bfin_write16(®->mbtif1, 0xFFFF); | |
261 | bfin_write16(®->mbtif2, 0xFFFF); | |
262 | bfin_write16(®->mbrif1, 0xFFFF); | |
263 | bfin_write16(®->mbrif2, 0xFFFF); | |
264 | ||
265 | /* | |
266 | * clear global interrupt status register | |
267 | */ | |
268 | bfin_write16(®->gis, 0x7FF); /* overwrites with '1' */ | |
269 | ||
270 | /* | |
271 | * Initialize Interrupts | |
272 | * - set bits in the mailbox interrupt mask register | |
273 | * - global interrupt mask | |
274 | */ | |
275 | bfin_write16(®->mbim1, BIT(RECEIVE_STD_CHL) + BIT(RECEIVE_EXT_CHL)); | |
276 | bfin_write16(®->mbim2, BIT(TRANSMIT_CHL - 16)); | |
277 | ||
278 | bfin_write16(®->gim, EPIM | BOIM | RMLIM); | |
279 | SSYNC(); | |
280 | } | |
281 | ||
282 | static void bfin_can_start(struct net_device *dev) | |
283 | { | |
284 | struct bfin_can_priv *priv = netdev_priv(dev); | |
285 | ||
286 | /* enter reset mode */ | |
287 | if (priv->can.state != CAN_STATE_STOPPED) | |
288 | bfin_can_set_reset_mode(dev); | |
289 | ||
290 | /* leave reset mode */ | |
291 | bfin_can_set_normal_mode(dev); | |
292 | } | |
293 | ||
294 | static int bfin_can_set_mode(struct net_device *dev, enum can_mode mode) | |
295 | { | |
296 | switch (mode) { | |
297 | case CAN_MODE_START: | |
298 | bfin_can_start(dev); | |
299 | if (netif_queue_stopped(dev)) | |
300 | netif_wake_queue(dev); | |
301 | break; | |
302 | ||
303 | default: | |
304 | return -EOPNOTSUPP; | |
305 | } | |
306 | ||
307 | return 0; | |
308 | } | |
309 | ||
310 | static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev) | |
311 | { | |
312 | struct bfin_can_priv *priv = netdev_priv(dev); | |
313 | struct bfin_can_regs __iomem *reg = priv->membase; | |
314 | struct can_frame *cf = (struct can_frame *)skb->data; | |
315 | u8 dlc = cf->can_dlc; | |
316 | canid_t id = cf->can_id; | |
317 | u8 *data = cf->data; | |
318 | u16 val; | |
319 | int i; | |
320 | ||
3ccd4c61 OH |
321 | if (can_dropped_invalid_skb(dev, skb)) |
322 | return NETDEV_TX_OK; | |
323 | ||
bbb84619 BS |
324 | netif_stop_queue(dev); |
325 | ||
326 | /* fill id */ | |
327 | if (id & CAN_EFF_FLAG) { | |
328 | bfin_write16(®->chl[TRANSMIT_CHL].id0, id); | |
329 | if (id & CAN_RTR_FLAG) | |
330 | writew(((id & 0x1FFF0000) >> 16) | IDE | AME | RTR, | |
331 | ®->chl[TRANSMIT_CHL].id1); | |
332 | else | |
333 | writew(((id & 0x1FFF0000) >> 16) | IDE | AME, | |
334 | ®->chl[TRANSMIT_CHL].id1); | |
335 | ||
336 | } else { | |
337 | if (id & CAN_RTR_FLAG) | |
338 | writew((id << 2) | AME | RTR, | |
339 | ®->chl[TRANSMIT_CHL].id1); | |
340 | else | |
341 | bfin_write16(®->chl[TRANSMIT_CHL].id1, | |
342 | (id << 2) | AME); | |
343 | } | |
344 | ||
345 | /* fill payload */ | |
346 | for (i = 0; i < 8; i += 2) { | |
347 | val = ((7 - i) < dlc ? (data[7 - i]) : 0) + | |
348 | ((6 - i) < dlc ? (data[6 - i] << 8) : 0); | |
349 | bfin_write16(®->chl[TRANSMIT_CHL].data[i], val); | |
350 | } | |
351 | ||
352 | /* fill data length code */ | |
353 | bfin_write16(®->chl[TRANSMIT_CHL].dlc, dlc); | |
354 | ||
355 | dev->trans_start = jiffies; | |
356 | ||
357 | can_put_echo_skb(skb, dev, 0); | |
358 | ||
359 | /* set transmit request */ | |
360 | bfin_write16(®->trs2, BIT(TRANSMIT_CHL - 16)); | |
361 | ||
362 | return 0; | |
363 | } | |
364 | ||
365 | static void bfin_can_rx(struct net_device *dev, u16 isrc) | |
366 | { | |
367 | struct bfin_can_priv *priv = netdev_priv(dev); | |
368 | struct net_device_stats *stats = &dev->stats; | |
369 | struct bfin_can_regs __iomem *reg = priv->membase; | |
370 | struct can_frame *cf; | |
371 | struct sk_buff *skb; | |
372 | int obj; | |
373 | int i; | |
374 | u16 val; | |
375 | ||
376 | skb = alloc_can_skb(dev, &cf); | |
377 | if (skb == NULL) | |
378 | return; | |
379 | ||
380 | /* get id */ | |
381 | if (isrc & BIT(RECEIVE_EXT_CHL)) { | |
382 | /* extended frame format (EFF) */ | |
383 | cf->can_id = ((bfin_read16(®->chl[RECEIVE_EXT_CHL].id1) | |
384 | & 0x1FFF) << 16) | |
385 | + bfin_read16(®->chl[RECEIVE_EXT_CHL].id0); | |
386 | cf->can_id |= CAN_EFF_FLAG; | |
387 | obj = RECEIVE_EXT_CHL; | |
388 | } else { | |
389 | /* standard frame format (SFF) */ | |
390 | cf->can_id = (bfin_read16(®->chl[RECEIVE_STD_CHL].id1) | |
391 | & 0x1ffc) >> 2; | |
392 | obj = RECEIVE_STD_CHL; | |
393 | } | |
394 | if (bfin_read16(®->chl[obj].id1) & RTR) | |
395 | cf->can_id |= CAN_RTR_FLAG; | |
396 | ||
397 | /* get data length code */ | |
c7cd606f | 398 | cf->can_dlc = get_can_dlc(bfin_read16(®->chl[obj].dlc) & 0xF); |
bbb84619 BS |
399 | |
400 | /* get payload */ | |
401 | for (i = 0; i < 8; i += 2) { | |
402 | val = bfin_read16(®->chl[obj].data[i]); | |
403 | cf->data[7 - i] = (7 - i) < cf->can_dlc ? val : 0; | |
404 | cf->data[6 - i] = (6 - i) < cf->can_dlc ? (val >> 8) : 0; | |
405 | } | |
406 | ||
407 | netif_rx(skb); | |
408 | ||
409 | stats->rx_packets++; | |
410 | stats->rx_bytes += cf->can_dlc; | |
411 | } | |
412 | ||
413 | static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status) | |
414 | { | |
415 | struct bfin_can_priv *priv = netdev_priv(dev); | |
416 | struct bfin_can_regs __iomem *reg = priv->membase; | |
417 | struct net_device_stats *stats = &dev->stats; | |
418 | struct can_frame *cf; | |
419 | struct sk_buff *skb; | |
420 | enum can_state state = priv->can.state; | |
421 | ||
422 | skb = alloc_can_err_skb(dev, &cf); | |
423 | if (skb == NULL) | |
424 | return -ENOMEM; | |
425 | ||
426 | if (isrc & RMLIS) { | |
427 | /* data overrun interrupt */ | |
428 | dev_dbg(dev->dev.parent, "data overrun interrupt\n"); | |
429 | cf->can_id |= CAN_ERR_CRTL; | |
430 | cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; | |
431 | stats->rx_over_errors++; | |
432 | stats->rx_errors++; | |
433 | } | |
434 | ||
435 | if (isrc & BOIS) { | |
436 | dev_dbg(dev->dev.parent, "bus-off mode interrupt\n"); | |
437 | state = CAN_STATE_BUS_OFF; | |
438 | cf->can_id |= CAN_ERR_BUSOFF; | |
439 | can_bus_off(dev); | |
440 | } | |
441 | ||
442 | if (isrc & EPIS) { | |
443 | /* error passive interrupt */ | |
444 | dev_dbg(dev->dev.parent, "error passive interrupt\n"); | |
445 | state = CAN_STATE_ERROR_PASSIVE; | |
446 | } | |
447 | ||
448 | if ((isrc & EWTIS) || (isrc & EWRIS)) { | |
449 | dev_dbg(dev->dev.parent, | |
450 | "Error Warning Transmit/Receive Interrupt\n"); | |
451 | state = CAN_STATE_ERROR_WARNING; | |
452 | } | |
453 | ||
454 | if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING || | |
455 | state == CAN_STATE_ERROR_PASSIVE)) { | |
456 | u16 cec = bfin_read16(®->cec); | |
457 | u8 rxerr = cec; | |
458 | u8 txerr = cec >> 8; | |
459 | ||
460 | cf->can_id |= CAN_ERR_CRTL; | |
461 | if (state == CAN_STATE_ERROR_WARNING) { | |
462 | priv->can.can_stats.error_warning++; | |
463 | cf->data[1] = (txerr > rxerr) ? | |
464 | CAN_ERR_CRTL_TX_WARNING : | |
465 | CAN_ERR_CRTL_RX_WARNING; | |
466 | } else { | |
467 | priv->can.can_stats.error_passive++; | |
468 | cf->data[1] = (txerr > rxerr) ? | |
469 | CAN_ERR_CRTL_TX_PASSIVE : | |
470 | CAN_ERR_CRTL_RX_PASSIVE; | |
471 | } | |
472 | } | |
473 | ||
474 | if (status) { | |
475 | priv->can.can_stats.bus_error++; | |
476 | ||
477 | cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; | |
478 | ||
479 | if (status & BEF) | |
480 | cf->data[2] |= CAN_ERR_PROT_BIT; | |
481 | else if (status & FER) | |
482 | cf->data[2] |= CAN_ERR_PROT_FORM; | |
483 | else if (status & SER) | |
484 | cf->data[2] |= CAN_ERR_PROT_STUFF; | |
485 | else | |
486 | cf->data[2] |= CAN_ERR_PROT_UNSPEC; | |
487 | } | |
488 | ||
489 | priv->can.state = state; | |
490 | ||
491 | netif_rx(skb); | |
492 | ||
493 | stats->rx_packets++; | |
494 | stats->rx_bytes += cf->can_dlc; | |
495 | ||
496 | return 0; | |
497 | } | |
498 | ||
499 | irqreturn_t bfin_can_interrupt(int irq, void *dev_id) | |
500 | { | |
501 | struct net_device *dev = dev_id; | |
502 | struct bfin_can_priv *priv = netdev_priv(dev); | |
503 | struct bfin_can_regs __iomem *reg = priv->membase; | |
504 | struct net_device_stats *stats = &dev->stats; | |
505 | u16 status, isrc; | |
506 | ||
507 | if ((irq == priv->tx_irq) && bfin_read16(®->mbtif2)) { | |
508 | /* transmission complete interrupt */ | |
509 | bfin_write16(®->mbtif2, 0xFFFF); | |
510 | stats->tx_packets++; | |
511 | stats->tx_bytes += bfin_read16(®->chl[TRANSMIT_CHL].dlc); | |
512 | can_get_echo_skb(dev, 0); | |
513 | netif_wake_queue(dev); | |
514 | } else if ((irq == priv->rx_irq) && bfin_read16(®->mbrif1)) { | |
515 | /* receive interrupt */ | |
516 | isrc = bfin_read16(®->mbrif1); | |
517 | bfin_write16(®->mbrif1, 0xFFFF); | |
518 | bfin_can_rx(dev, isrc); | |
519 | } else if ((irq == priv->err_irq) && bfin_read16(®->gis)) { | |
520 | /* error interrupt */ | |
521 | isrc = bfin_read16(®->gis); | |
522 | status = bfin_read16(®->esr); | |
523 | bfin_write16(®->gis, 0x7FF); | |
524 | bfin_can_err(dev, isrc, status); | |
525 | } else { | |
526 | return IRQ_NONE; | |
527 | } | |
528 | ||
529 | return IRQ_HANDLED; | |
530 | } | |
531 | ||
532 | static int bfin_can_open(struct net_device *dev) | |
533 | { | |
534 | struct bfin_can_priv *priv = netdev_priv(dev); | |
535 | int err; | |
536 | ||
537 | /* set chip into reset mode */ | |
538 | bfin_can_set_reset_mode(dev); | |
539 | ||
540 | /* common open */ | |
541 | err = open_candev(dev); | |
542 | if (err) | |
543 | goto exit_open; | |
544 | ||
545 | /* register interrupt handler */ | |
546 | err = request_irq(priv->rx_irq, &bfin_can_interrupt, 0, | |
547 | "bfin-can-rx", dev); | |
548 | if (err) | |
549 | goto exit_rx_irq; | |
550 | err = request_irq(priv->tx_irq, &bfin_can_interrupt, 0, | |
551 | "bfin-can-tx", dev); | |
552 | if (err) | |
553 | goto exit_tx_irq; | |
554 | err = request_irq(priv->err_irq, &bfin_can_interrupt, 0, | |
555 | "bfin-can-err", dev); | |
556 | if (err) | |
557 | goto exit_err_irq; | |
558 | ||
559 | bfin_can_start(dev); | |
560 | ||
561 | netif_start_queue(dev); | |
562 | ||
563 | return 0; | |
564 | ||
565 | exit_err_irq: | |
566 | free_irq(priv->tx_irq, dev); | |
567 | exit_tx_irq: | |
568 | free_irq(priv->rx_irq, dev); | |
569 | exit_rx_irq: | |
570 | close_candev(dev); | |
571 | exit_open: | |
572 | return err; | |
573 | } | |
574 | ||
575 | static int bfin_can_close(struct net_device *dev) | |
576 | { | |
577 | struct bfin_can_priv *priv = netdev_priv(dev); | |
578 | ||
579 | netif_stop_queue(dev); | |
580 | bfin_can_set_reset_mode(dev); | |
581 | ||
582 | close_candev(dev); | |
583 | ||
584 | free_irq(priv->rx_irq, dev); | |
585 | free_irq(priv->tx_irq, dev); | |
586 | free_irq(priv->err_irq, dev); | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
591 | struct net_device *alloc_bfin_candev(void) | |
592 | { | |
593 | struct net_device *dev; | |
594 | struct bfin_can_priv *priv; | |
595 | ||
596 | dev = alloc_candev(sizeof(*priv)); | |
597 | if (!dev) | |
598 | return NULL; | |
599 | ||
600 | priv = netdev_priv(dev); | |
601 | ||
602 | priv->dev = dev; | |
603 | priv->can.bittiming_const = &bfin_can_bittiming_const; | |
604 | priv->can.do_set_bittiming = bfin_can_set_bittiming; | |
605 | priv->can.do_set_mode = bfin_can_set_mode; | |
ad72c347 | 606 | priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; |
bbb84619 BS |
607 | |
608 | return dev; | |
609 | } | |
610 | ||
611 | static const struct net_device_ops bfin_can_netdev_ops = { | |
612 | .ndo_open = bfin_can_open, | |
613 | .ndo_stop = bfin_can_close, | |
614 | .ndo_start_xmit = bfin_can_start_xmit, | |
615 | }; | |
616 | ||
617 | static int __devinit bfin_can_probe(struct platform_device *pdev) | |
618 | { | |
619 | int err; | |
620 | struct net_device *dev; | |
621 | struct bfin_can_priv *priv; | |
622 | struct resource *res_mem, *rx_irq, *tx_irq, *err_irq; | |
623 | unsigned short *pdata; | |
624 | ||
625 | pdata = pdev->dev.platform_data; | |
626 | if (!pdata) { | |
627 | dev_err(&pdev->dev, "No platform data provided!\n"); | |
628 | err = -EINVAL; | |
629 | goto exit; | |
630 | } | |
631 | ||
632 | res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
633 | rx_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | |
634 | tx_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1); | |
635 | err_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 2); | |
636 | if (!res_mem || !rx_irq || !tx_irq || !err_irq) { | |
637 | err = -EINVAL; | |
638 | goto exit; | |
639 | } | |
640 | ||
641 | if (!request_mem_region(res_mem->start, resource_size(res_mem), | |
642 | dev_name(&pdev->dev))) { | |
643 | err = -EBUSY; | |
644 | goto exit; | |
645 | } | |
646 | ||
647 | /* request peripheral pins */ | |
648 | err = peripheral_request_list(pdata, dev_name(&pdev->dev)); | |
649 | if (err) | |
650 | goto exit_mem_release; | |
651 | ||
652 | dev = alloc_bfin_candev(); | |
653 | if (!dev) { | |
654 | err = -ENOMEM; | |
655 | goto exit_peri_pin_free; | |
656 | } | |
657 | ||
658 | priv = netdev_priv(dev); | |
659 | priv->membase = (void __iomem *)res_mem->start; | |
660 | priv->rx_irq = rx_irq->start; | |
661 | priv->tx_irq = tx_irq->start; | |
662 | priv->err_irq = err_irq->start; | |
663 | priv->pin_list = pdata; | |
664 | priv->can.clock.freq = get_sclk(); | |
665 | ||
666 | dev_set_drvdata(&pdev->dev, dev); | |
667 | SET_NETDEV_DEV(dev, &pdev->dev); | |
668 | ||
669 | dev->flags |= IFF_ECHO; /* we support local echo */ | |
670 | dev->netdev_ops = &bfin_can_netdev_ops; | |
671 | ||
672 | bfin_can_set_reset_mode(dev); | |
673 | ||
674 | err = register_candev(dev); | |
675 | if (err) { | |
676 | dev_err(&pdev->dev, "registering failed (err=%d)\n", err); | |
677 | goto exit_candev_free; | |
678 | } | |
679 | ||
680 | dev_info(&pdev->dev, | |
681 | "%s device registered" | |
682 | "(®_base=%p, rx_irq=%d, tx_irq=%d, err_irq=%d, sclk=%d)\n", | |
683 | DRV_NAME, (void *)priv->membase, priv->rx_irq, | |
684 | priv->tx_irq, priv->err_irq, priv->can.clock.freq); | |
685 | return 0; | |
686 | ||
687 | exit_candev_free: | |
688 | free_candev(dev); | |
689 | exit_peri_pin_free: | |
690 | peripheral_free_list(pdata); | |
691 | exit_mem_release: | |
692 | release_mem_region(res_mem->start, resource_size(res_mem)); | |
693 | exit: | |
694 | return err; | |
695 | } | |
696 | ||
697 | static int __devexit bfin_can_remove(struct platform_device *pdev) | |
698 | { | |
699 | struct net_device *dev = dev_get_drvdata(&pdev->dev); | |
700 | struct bfin_can_priv *priv = netdev_priv(dev); | |
701 | struct resource *res; | |
702 | ||
703 | bfin_can_set_reset_mode(dev); | |
704 | ||
705 | unregister_candev(dev); | |
706 | ||
707 | dev_set_drvdata(&pdev->dev, NULL); | |
708 | ||
709 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
710 | release_mem_region(res->start, resource_size(res)); | |
711 | ||
712 | peripheral_free_list(priv->pin_list); | |
713 | ||
714 | free_candev(dev); | |
715 | return 0; | |
716 | } | |
717 | ||
718 | #ifdef CONFIG_PM | |
719 | static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg) | |
720 | { | |
721 | struct net_device *dev = dev_get_drvdata(&pdev->dev); | |
722 | struct bfin_can_priv *priv = netdev_priv(dev); | |
723 | struct bfin_can_regs __iomem *reg = priv->membase; | |
724 | int timeout = BFIN_CAN_TIMEOUT; | |
725 | ||
726 | if (netif_running(dev)) { | |
727 | /* enter sleep mode */ | |
728 | bfin_write16(®->ctrl, bfin_read16(®->ctrl) | SMR); | |
729 | SSYNC(); | |
730 | while (!(bfin_read16(®->intr) & SMACK)) { | |
731 | udelay(10); | |
732 | if (--timeout == 0) { | |
733 | dev_err(dev->dev.parent, | |
734 | "fail to enter sleep mode\n"); | |
735 | BUG(); | |
736 | } | |
737 | } | |
738 | } | |
739 | ||
740 | return 0; | |
741 | } | |
742 | ||
743 | static int bfin_can_resume(struct platform_device *pdev) | |
744 | { | |
745 | struct net_device *dev = dev_get_drvdata(&pdev->dev); | |
746 | struct bfin_can_priv *priv = netdev_priv(dev); | |
747 | struct bfin_can_regs __iomem *reg = priv->membase; | |
748 | ||
749 | if (netif_running(dev)) { | |
750 | /* leave sleep mode */ | |
751 | bfin_write16(®->intr, 0); | |
752 | SSYNC(); | |
753 | } | |
754 | ||
755 | return 0; | |
756 | } | |
757 | #else | |
758 | #define bfin_can_suspend NULL | |
759 | #define bfin_can_resume NULL | |
760 | #endif /* CONFIG_PM */ | |
761 | ||
762 | static struct platform_driver bfin_can_driver = { | |
763 | .probe = bfin_can_probe, | |
764 | .remove = __devexit_p(bfin_can_remove), | |
765 | .suspend = bfin_can_suspend, | |
766 | .resume = bfin_can_resume, | |
767 | .driver = { | |
768 | .name = DRV_NAME, | |
769 | .owner = THIS_MODULE, | |
770 | }, | |
771 | }; | |
772 | ||
773 | static int __init bfin_can_init(void) | |
774 | { | |
775 | return platform_driver_register(&bfin_can_driver); | |
776 | } | |
777 | module_init(bfin_can_init); | |
778 | ||
779 | static void __exit bfin_can_exit(void) | |
780 | { | |
781 | platform_driver_unregister(&bfin_can_driver); | |
782 | } | |
783 | module_exit(bfin_can_exit); | |
784 | ||
785 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | |
786 | MODULE_LICENSE("GPL"); | |
787 | MODULE_DESCRIPTION("Blackfin on-chip CAN netdevice driver"); |