Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: cc770: add driver core for the Bosch CC770 and Intel AN82527

Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
Acked-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Wolfgang Grandegger and committed by
David S. Miller
2a367c3a d7d75960

+1130
+2
drivers/net/can/Kconfig
··· 116 116 117 117 source "drivers/net/can/c_can/Kconfig" 118 118 119 + source "drivers/net/can/cc770/Kconfig" 120 + 119 121 source "drivers/net/can/usb/Kconfig" 120 122 121 123 source "drivers/net/can/softing/Kconfig"
+1
drivers/net/can/Makefile
··· 14 14 obj-$(CONFIG_CAN_SJA1000) += sja1000/ 15 15 obj-$(CONFIG_CAN_MSCAN) += mscan/ 16 16 obj-$(CONFIG_CAN_C_CAN) += c_can/ 17 + obj-$(CONFIG_CAN_CC770) += cc770/ 17 18 obj-$(CONFIG_CAN_AT91) += at91_can.o 18 19 obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o 19 20 obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
+3
drivers/net/can/cc770/Kconfig
··· 1 + menuconfig CAN_CC770 2 + tristate "Bosch CC770 and Intel AN82527 devices" 3 + depends on CAN_DEV && HAS_IOMEM
+7
drivers/net/can/cc770/Makefile
··· 1 + # 2 + # Makefile for the Bosch CC770 CAN controller drivers. 3 + # 4 + 5 + obj-$(CONFIG_CAN_CC770) += cc770.o 6 + 7 + ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+881
drivers/net/can/cc770/cc770.c
··· 1 + /* 2 + * Core driver for the CC770 and AN82527 CAN controllers 3 + * 4 + * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the version 2 of the GNU General Public License 8 + * as published by the Free Software Foundation 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 + 18 + #include <linux/module.h> 19 + #include <linux/init.h> 20 + #include <linux/kernel.h> 21 + #include <linux/sched.h> 22 + #include <linux/types.h> 23 + #include <linux/fcntl.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/ptrace.h> 26 + #include <linux/string.h> 27 + #include <linux/errno.h> 28 + #include <linux/netdevice.h> 29 + #include <linux/if_arp.h> 30 + #include <linux/if_ether.h> 31 + #include <linux/skbuff.h> 32 + #include <linux/delay.h> 33 + 34 + #include <linux/can.h> 35 + #include <linux/can/dev.h> 36 + #include <linux/can/error.h> 37 + #include <linux/can/dev.h> 38 + #include <linux/can/platform/cc770.h> 39 + 40 + #include "cc770.h" 41 + 42 + MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); 43 + MODULE_LICENSE("GPL v2"); 44 + MODULE_DESCRIPTION(KBUILD_MODNAME "CAN netdevice driver"); 45 + 46 + /* 47 + * The CC770 is a CAN controller from Bosch, which is 100% compatible 48 + * with the AN82527 from Intel, but with "bugs" being fixed and some 49 + * additional functionality, mainly: 50 + * 51 + * 1. RX and TX error counters are readable. 52 + * 2. Support of silent (listen-only) mode. 53 + * 3. Message object 15 can receive all types of frames, also RTR and EFF. 54 + * 55 + * Details are available from Bosch's "CC770_Product_Info_2007-01.pdf", 56 + * which explains in detail the compatibility between the CC770 and the 57 + * 82527. This driver use the additional functionality 3. on real CC770 58 + * devices. Unfortunately, the CC770 does still not store the message 59 + * identifier of received remote transmission request frames and 60 + * therefore it's set to 0. 61 + * 62 + * The message objects 1..14 can be used for TX and RX while the message 63 + * objects 15 is optimized for RX. It has a shadow register for reliable 64 + * data receiption under heavy bus load. Therefore it makes sense to use 65 + * this message object for the needed use case. The frame type (EFF/SFF) 66 + * for the message object 15 can be defined via kernel module parameter 67 + * "msgobj15_eff". If not equal 0, it will receive 29-bit EFF frames, 68 + * otherwise 11 bit SFF messages. 69 + */ 70 + static int msgobj15_eff; 71 + module_param(msgobj15_eff, int, S_IRUGO); 72 + MODULE_PARM_DESC(msgobj15_eff, "Extended 29-bit frames for message object 15 " 73 + "(default: 11-bit standard frames)"); 74 + 75 + static int i82527_compat; 76 + module_param(i82527_compat, int, S_IRUGO); 77 + MODULE_PARM_DESC(i82527_compat, "Strict Intel 82527 comptibility mode " 78 + "without using additional functions"); 79 + 80 + /* 81 + * This driver uses the last 5 message objects 11..15. The definitions 82 + * and structure below allows to configure and assign them to the real 83 + * message object. 84 + */ 85 + static unsigned char cc770_obj_flags[CC770_OBJ_MAX] = { 86 + [CC770_OBJ_RX0] = CC770_OBJ_FLAG_RX, 87 + [CC770_OBJ_RX1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_EFF, 88 + [CC770_OBJ_RX_RTR0] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR, 89 + [CC770_OBJ_RX_RTR1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR | 90 + CC770_OBJ_FLAG_EFF, 91 + [CC770_OBJ_TX] = 0, 92 + }; 93 + 94 + static struct can_bittiming_const cc770_bittiming_const = { 95 + .name = KBUILD_MODNAME, 96 + .tseg1_min = 1, 97 + .tseg1_max = 16, 98 + .tseg2_min = 1, 99 + .tseg2_max = 8, 100 + .sjw_max = 4, 101 + .brp_min = 1, 102 + .brp_max = 64, 103 + .brp_inc = 1, 104 + }; 105 + 106 + static inline int intid2obj(unsigned int intid) 107 + { 108 + if (intid == 2) 109 + return 0; 110 + else 111 + return MSGOBJ_LAST + 2 - intid; 112 + } 113 + 114 + static void enable_all_objs(const struct net_device *dev) 115 + { 116 + struct cc770_priv *priv = netdev_priv(dev); 117 + u8 msgcfg; 118 + unsigned char obj_flags; 119 + unsigned int o, mo; 120 + 121 + for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) { 122 + obj_flags = priv->obj_flags[o]; 123 + mo = obj2msgobj(o); 124 + 125 + if (obj_flags & CC770_OBJ_FLAG_RX) { 126 + /* 127 + * We don't need extra objects for RTR and EFF if 128 + * the additional CC770 functions are enabled. 129 + */ 130 + if (priv->control_normal_mode & CTRL_EAF) { 131 + if (o > 0) 132 + continue; 133 + netdev_dbg(dev, "Message object %d for " 134 + "RX data, RTR, SFF and EFF\n", mo); 135 + } else { 136 + netdev_dbg(dev, 137 + "Message object %d for RX %s %s\n", 138 + mo, obj_flags & CC770_OBJ_FLAG_RTR ? 139 + "RTR" : "data", 140 + obj_flags & CC770_OBJ_FLAG_EFF ? 141 + "EFF" : "SFF"); 142 + } 143 + 144 + if (obj_flags & CC770_OBJ_FLAG_EFF) 145 + msgcfg = MSGCFG_XTD; 146 + else 147 + msgcfg = 0; 148 + if (obj_flags & CC770_OBJ_FLAG_RTR) 149 + msgcfg |= MSGCFG_DIR; 150 + 151 + cc770_write_reg(priv, msgobj[mo].config, msgcfg); 152 + cc770_write_reg(priv, msgobj[mo].ctrl0, 153 + MSGVAL_SET | TXIE_RES | 154 + RXIE_SET | INTPND_RES); 155 + 156 + if (obj_flags & CC770_OBJ_FLAG_RTR) 157 + cc770_write_reg(priv, msgobj[mo].ctrl1, 158 + NEWDAT_RES | CPUUPD_SET | 159 + TXRQST_RES | RMTPND_RES); 160 + else 161 + cc770_write_reg(priv, msgobj[mo].ctrl1, 162 + NEWDAT_RES | MSGLST_RES | 163 + TXRQST_RES | RMTPND_RES); 164 + } else { 165 + netdev_dbg(dev, "Message object %d for " 166 + "TX data, RTR, SFF and EFF\n", mo); 167 + 168 + cc770_write_reg(priv, msgobj[mo].ctrl1, 169 + RMTPND_RES | TXRQST_RES | 170 + CPUUPD_RES | NEWDAT_RES); 171 + cc770_write_reg(priv, msgobj[mo].ctrl0, 172 + MSGVAL_RES | TXIE_RES | 173 + RXIE_RES | INTPND_RES); 174 + } 175 + } 176 + } 177 + 178 + static void disable_all_objs(const struct cc770_priv *priv) 179 + { 180 + int o, mo; 181 + 182 + for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) { 183 + mo = obj2msgobj(o); 184 + 185 + if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) { 186 + if (o > 0 && priv->control_normal_mode & CTRL_EAF) 187 + continue; 188 + 189 + cc770_write_reg(priv, msgobj[mo].ctrl1, 190 + NEWDAT_RES | MSGLST_RES | 191 + TXRQST_RES | RMTPND_RES); 192 + cc770_write_reg(priv, msgobj[mo].ctrl0, 193 + MSGVAL_RES | TXIE_RES | 194 + RXIE_RES | INTPND_RES); 195 + } else { 196 + /* Clear message object for send */ 197 + cc770_write_reg(priv, msgobj[mo].ctrl1, 198 + RMTPND_RES | TXRQST_RES | 199 + CPUUPD_RES | NEWDAT_RES); 200 + cc770_write_reg(priv, msgobj[mo].ctrl0, 201 + MSGVAL_RES | TXIE_RES | 202 + RXIE_RES | INTPND_RES); 203 + } 204 + } 205 + } 206 + 207 + static void set_reset_mode(struct net_device *dev) 208 + { 209 + struct cc770_priv *priv = netdev_priv(dev); 210 + 211 + /* Enable configuration and puts chip in bus-off, disable interrupts */ 212 + cc770_write_reg(priv, control, CTRL_CCE | CTRL_INI); 213 + 214 + priv->can.state = CAN_STATE_STOPPED; 215 + 216 + /* Clear interrupts */ 217 + cc770_read_reg(priv, interrupt); 218 + 219 + /* Clear status register */ 220 + cc770_write_reg(priv, status, 0); 221 + 222 + /* Disable all used message objects */ 223 + disable_all_objs(priv); 224 + } 225 + 226 + static void set_normal_mode(struct net_device *dev) 227 + { 228 + struct cc770_priv *priv = netdev_priv(dev); 229 + 230 + /* Clear interrupts */ 231 + cc770_read_reg(priv, interrupt); 232 + 233 + /* Clear status register and pre-set last error code */ 234 + cc770_write_reg(priv, status, STAT_LEC_MASK); 235 + 236 + /* Enable all used message objects*/ 237 + enable_all_objs(dev); 238 + 239 + /* 240 + * Clear bus-off, interrupts only for errors, 241 + * not for status change 242 + */ 243 + cc770_write_reg(priv, control, priv->control_normal_mode); 244 + 245 + priv->can.state = CAN_STATE_ERROR_ACTIVE; 246 + } 247 + 248 + static void chipset_init(struct cc770_priv *priv) 249 + { 250 + int mo, id, data; 251 + 252 + /* Enable configuration and put chip in bus-off, disable interrupts */ 253 + cc770_write_reg(priv, control, (CTRL_CCE | CTRL_INI)); 254 + 255 + /* Set CLKOUT divider and slew rates */ 256 + cc770_write_reg(priv, clkout, priv->clkout); 257 + 258 + /* Configure CPU interface / CLKOUT enable */ 259 + cc770_write_reg(priv, cpu_interface, priv->cpu_interface); 260 + 261 + /* Set bus configuration */ 262 + cc770_write_reg(priv, bus_config, priv->bus_config); 263 + 264 + /* Clear interrupts */ 265 + cc770_read_reg(priv, interrupt); 266 + 267 + /* Clear status register */ 268 + cc770_write_reg(priv, status, 0); 269 + 270 + /* Clear and invalidate message objects */ 271 + for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++) { 272 + cc770_write_reg(priv, msgobj[mo].ctrl0, 273 + INTPND_UNC | RXIE_RES | 274 + TXIE_RES | MSGVAL_RES); 275 + cc770_write_reg(priv, msgobj[mo].ctrl0, 276 + INTPND_RES | RXIE_RES | 277 + TXIE_RES | MSGVAL_RES); 278 + cc770_write_reg(priv, msgobj[mo].ctrl1, 279 + NEWDAT_RES | MSGLST_RES | 280 + TXRQST_RES | RMTPND_RES); 281 + for (data = 0; data < 8; data++) 282 + cc770_write_reg(priv, msgobj[mo].data[data], 0); 283 + for (id = 0; id < 4; id++) 284 + cc770_write_reg(priv, msgobj[mo].id[id], 0); 285 + cc770_write_reg(priv, msgobj[mo].config, 0); 286 + } 287 + 288 + /* Set all global ID masks to "don't care" */ 289 + cc770_write_reg(priv, global_mask_std[0], 0); 290 + cc770_write_reg(priv, global_mask_std[1], 0); 291 + cc770_write_reg(priv, global_mask_ext[0], 0); 292 + cc770_write_reg(priv, global_mask_ext[1], 0); 293 + cc770_write_reg(priv, global_mask_ext[2], 0); 294 + cc770_write_reg(priv, global_mask_ext[3], 0); 295 + 296 + } 297 + 298 + static int cc770_probe_chip(struct net_device *dev) 299 + { 300 + struct cc770_priv *priv = netdev_priv(dev); 301 + 302 + /* Enable configuration, put chip in bus-off, disable ints */ 303 + cc770_write_reg(priv, control, CTRL_CCE | CTRL_EAF | CTRL_INI); 304 + /* Configure cpu interface / CLKOUT disable */ 305 + cc770_write_reg(priv, cpu_interface, priv->cpu_interface); 306 + 307 + /* 308 + * Check if hardware reset is still inactive or maybe there 309 + * is no chip in this address space 310 + */ 311 + if (cc770_read_reg(priv, cpu_interface) & CPUIF_RST) { 312 + netdev_info(dev, "probing @0x%p failed (reset)\n", 313 + priv->reg_base); 314 + return -ENODEV; 315 + } 316 + 317 + /* Write and read back test pattern (some arbitrary values) */ 318 + cc770_write_reg(priv, msgobj[1].data[1], 0x25); 319 + cc770_write_reg(priv, msgobj[2].data[3], 0x52); 320 + cc770_write_reg(priv, msgobj[10].data[6], 0xc3); 321 + if ((cc770_read_reg(priv, msgobj[1].data[1]) != 0x25) || 322 + (cc770_read_reg(priv, msgobj[2].data[3]) != 0x52) || 323 + (cc770_read_reg(priv, msgobj[10].data[6]) != 0xc3)) { 324 + netdev_info(dev, "probing @0x%p failed (pattern)\n", 325 + priv->reg_base); 326 + return -ENODEV; 327 + } 328 + 329 + /* Check if this chip is a CC770 supporting additional functions */ 330 + if (cc770_read_reg(priv, control) & CTRL_EAF) 331 + priv->control_normal_mode |= CTRL_EAF; 332 + 333 + return 0; 334 + } 335 + 336 + static void cc770_start(struct net_device *dev) 337 + { 338 + struct cc770_priv *priv = netdev_priv(dev); 339 + 340 + /* leave reset mode */ 341 + if (priv->can.state != CAN_STATE_STOPPED) 342 + set_reset_mode(dev); 343 + 344 + /* leave reset mode */ 345 + set_normal_mode(dev); 346 + } 347 + 348 + static int cc770_set_mode(struct net_device *dev, enum can_mode mode) 349 + { 350 + switch (mode) { 351 + case CAN_MODE_START: 352 + cc770_start(dev); 353 + netif_wake_queue(dev); 354 + break; 355 + 356 + default: 357 + return -EOPNOTSUPP; 358 + } 359 + 360 + return 0; 361 + } 362 + 363 + static int cc770_set_bittiming(struct net_device *dev) 364 + { 365 + struct cc770_priv *priv = netdev_priv(dev); 366 + struct can_bittiming *bt = &priv->can.bittiming; 367 + u8 btr0, btr1; 368 + 369 + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); 370 + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | 371 + (((bt->phase_seg2 - 1) & 0x7) << 4); 372 + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) 373 + btr1 |= 0x80; 374 + 375 + netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); 376 + 377 + cc770_write_reg(priv, bit_timing_0, btr0); 378 + cc770_write_reg(priv, bit_timing_1, btr1); 379 + 380 + return 0; 381 + } 382 + 383 + static int cc770_get_berr_counter(const struct net_device *dev, 384 + struct can_berr_counter *bec) 385 + { 386 + struct cc770_priv *priv = netdev_priv(dev); 387 + 388 + bec->txerr = cc770_read_reg(priv, tx_error_counter); 389 + bec->rxerr = cc770_read_reg(priv, rx_error_counter); 390 + 391 + return 0; 392 + } 393 + 394 + static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) 395 + { 396 + struct cc770_priv *priv = netdev_priv(dev); 397 + struct net_device_stats *stats = &dev->stats; 398 + struct can_frame *cf = (struct can_frame *)skb->data; 399 + unsigned int mo = obj2msgobj(CC770_OBJ_TX); 400 + u8 dlc, rtr; 401 + u32 id; 402 + int i; 403 + 404 + if (can_dropped_invalid_skb(dev, skb)) 405 + return NETDEV_TX_OK; 406 + 407 + if ((cc770_read_reg(priv, 408 + msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { 409 + netdev_err(dev, "TX register is still occupied!\n"); 410 + return NETDEV_TX_BUSY; 411 + } 412 + 413 + netif_stop_queue(dev); 414 + 415 + dlc = cf->can_dlc; 416 + id = cf->can_id; 417 + if (cf->can_id & CAN_RTR_FLAG) 418 + rtr = 0; 419 + else 420 + rtr = MSGCFG_DIR; 421 + cc770_write_reg(priv, msgobj[mo].ctrl1, 422 + RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); 423 + cc770_write_reg(priv, msgobj[mo].ctrl0, 424 + MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES); 425 + if (id & CAN_EFF_FLAG) { 426 + id &= CAN_EFF_MASK; 427 + cc770_write_reg(priv, msgobj[mo].config, 428 + (dlc << 4) | rtr | MSGCFG_XTD); 429 + cc770_write_reg(priv, msgobj[mo].id[3], id << 3); 430 + cc770_write_reg(priv, msgobj[mo].id[2], id >> 5); 431 + cc770_write_reg(priv, msgobj[mo].id[1], id >> 13); 432 + cc770_write_reg(priv, msgobj[mo].id[0], id >> 21); 433 + } else { 434 + id &= CAN_SFF_MASK; 435 + cc770_write_reg(priv, msgobj[mo].config, (dlc << 4) | rtr); 436 + cc770_write_reg(priv, msgobj[mo].id[0], id >> 3); 437 + cc770_write_reg(priv, msgobj[mo].id[1], id << 5); 438 + } 439 + 440 + for (i = 0; i < dlc; i++) 441 + cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]); 442 + 443 + cc770_write_reg(priv, msgobj[mo].ctrl1, 444 + RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); 445 + 446 + stats->tx_bytes += dlc; 447 + 448 + can_put_echo_skb(skb, dev, 0); 449 + 450 + /* 451 + * HM: We had some cases of repeated IRQs so make sure the 452 + * INT is acknowledged I know it's already further up, but 453 + * doing again fixed the issue 454 + */ 455 + cc770_write_reg(priv, msgobj[mo].ctrl0, 456 + MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); 457 + 458 + return NETDEV_TX_OK; 459 + } 460 + 461 + static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1) 462 + { 463 + struct cc770_priv *priv = netdev_priv(dev); 464 + struct net_device_stats *stats = &dev->stats; 465 + struct can_frame *cf; 466 + struct sk_buff *skb; 467 + u8 config; 468 + u32 id; 469 + int i; 470 + 471 + skb = alloc_can_skb(dev, &cf); 472 + if (!skb) 473 + return; 474 + 475 + config = cc770_read_reg(priv, msgobj[mo].config); 476 + 477 + if (ctrl1 & RMTPND_SET) { 478 + /* 479 + * Unfortunately, the chip does not store the real message 480 + * identifier of the received remote transmission request 481 + * frame. Therefore we set it to 0. 482 + */ 483 + cf->can_id = CAN_RTR_FLAG; 484 + if (config & MSGCFG_XTD) 485 + cf->can_id |= CAN_EFF_FLAG; 486 + cf->can_dlc = 0; 487 + } else { 488 + if (config & MSGCFG_XTD) { 489 + id = cc770_read_reg(priv, msgobj[mo].id[3]); 490 + id |= cc770_read_reg(priv, msgobj[mo].id[2]) << 8; 491 + id |= cc770_read_reg(priv, msgobj[mo].id[1]) << 16; 492 + id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 24; 493 + id >>= 3; 494 + id |= CAN_EFF_FLAG; 495 + } else { 496 + id = cc770_read_reg(priv, msgobj[mo].id[1]); 497 + id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 8; 498 + id >>= 5; 499 + } 500 + 501 + cf->can_id = id; 502 + cf->can_dlc = get_can_dlc((config & 0xf0) >> 4); 503 + for (i = 0; i < cf->can_dlc; i++) 504 + cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]); 505 + } 506 + netif_rx(skb); 507 + 508 + stats->rx_packets++; 509 + stats->rx_bytes += cf->can_dlc; 510 + } 511 + 512 + static int cc770_err(struct net_device *dev, u8 status) 513 + { 514 + struct cc770_priv *priv = netdev_priv(dev); 515 + struct net_device_stats *stats = &dev->stats; 516 + struct can_frame *cf; 517 + struct sk_buff *skb; 518 + u8 lec; 519 + 520 + netdev_dbg(dev, "status interrupt (%#x)\n", status); 521 + 522 + skb = alloc_can_err_skb(dev, &cf); 523 + if (!skb) 524 + return -ENOMEM; 525 + 526 + /* Use extended functions of the CC770 */ 527 + if (priv->control_normal_mode & CTRL_EAF) { 528 + cf->data[6] = cc770_read_reg(priv, tx_error_counter); 529 + cf->data[7] = cc770_read_reg(priv, rx_error_counter); 530 + } 531 + 532 + if (status & STAT_BOFF) { 533 + /* Disable interrupts */ 534 + cc770_write_reg(priv, control, CTRL_INI); 535 + cf->can_id |= CAN_ERR_BUSOFF; 536 + priv->can.state = CAN_STATE_BUS_OFF; 537 + can_bus_off(dev); 538 + } else if (status & STAT_WARN) { 539 + cf->can_id |= CAN_ERR_CRTL; 540 + /* Only the CC770 does show error passive */ 541 + if (cf->data[7] > 127) { 542 + cf->data[1] = CAN_ERR_CRTL_RX_PASSIVE | 543 + CAN_ERR_CRTL_TX_PASSIVE; 544 + priv->can.state = CAN_STATE_ERROR_PASSIVE; 545 + priv->can.can_stats.error_passive++; 546 + } else { 547 + cf->data[1] = CAN_ERR_CRTL_RX_WARNING | 548 + CAN_ERR_CRTL_TX_WARNING; 549 + priv->can.state = CAN_STATE_ERROR_WARNING; 550 + priv->can.can_stats.error_warning++; 551 + } 552 + } else { 553 + /* Back to error avtive */ 554 + cf->can_id |= CAN_ERR_PROT; 555 + cf->data[2] = CAN_ERR_PROT_ACTIVE; 556 + priv->can.state = CAN_STATE_ERROR_ACTIVE; 557 + } 558 + 559 + lec = status & STAT_LEC_MASK; 560 + if (lec < 7 && lec > 0) { 561 + if (lec == STAT_LEC_ACK) { 562 + cf->can_id |= CAN_ERR_ACK; 563 + } else { 564 + cf->can_id |= CAN_ERR_PROT; 565 + switch (lec) { 566 + case STAT_LEC_STUFF: 567 + cf->data[2] |= CAN_ERR_PROT_STUFF; 568 + break; 569 + case STAT_LEC_FORM: 570 + cf->data[2] |= CAN_ERR_PROT_FORM; 571 + break; 572 + case STAT_LEC_BIT1: 573 + cf->data[2] |= CAN_ERR_PROT_BIT1; 574 + break; 575 + case STAT_LEC_BIT0: 576 + cf->data[2] |= CAN_ERR_PROT_BIT0; 577 + break; 578 + case STAT_LEC_CRC: 579 + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; 580 + break; 581 + } 582 + } 583 + } 584 + 585 + netif_rx(skb); 586 + 587 + stats->rx_packets++; 588 + stats->rx_bytes += cf->can_dlc; 589 + 590 + return 0; 591 + } 592 + 593 + static int cc770_status_interrupt(struct net_device *dev) 594 + { 595 + struct cc770_priv *priv = netdev_priv(dev); 596 + u8 status; 597 + 598 + status = cc770_read_reg(priv, status); 599 + /* Reset the status register including RXOK and TXOK */ 600 + cc770_write_reg(priv, status, STAT_LEC_MASK); 601 + 602 + if (status & (STAT_WARN | STAT_BOFF) || 603 + (status & STAT_LEC_MASK) != STAT_LEC_MASK) { 604 + cc770_err(dev, status); 605 + return status & STAT_BOFF; 606 + } 607 + 608 + return 0; 609 + } 610 + 611 + static void cc770_rx_interrupt(struct net_device *dev, unsigned int o) 612 + { 613 + struct cc770_priv *priv = netdev_priv(dev); 614 + struct net_device_stats *stats = &dev->stats; 615 + unsigned int mo = obj2msgobj(o); 616 + u8 ctrl1; 617 + int n = CC770_MAX_MSG; 618 + 619 + while (n--) { 620 + ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); 621 + 622 + if (!(ctrl1 & NEWDAT_SET)) { 623 + /* Check for RTR if additional functions are enabled */ 624 + if (priv->control_normal_mode & CTRL_EAF) { 625 + if (!(cc770_read_reg(priv, msgobj[mo].ctrl0) & 626 + INTPND_SET)) 627 + break; 628 + } else { 629 + break; 630 + } 631 + } 632 + 633 + if (ctrl1 & MSGLST_SET) { 634 + stats->rx_over_errors++; 635 + stats->rx_errors++; 636 + } 637 + if (mo < MSGOBJ_LAST) 638 + cc770_write_reg(priv, msgobj[mo].ctrl1, 639 + NEWDAT_RES | MSGLST_RES | 640 + TXRQST_UNC | RMTPND_UNC); 641 + cc770_rx(dev, mo, ctrl1); 642 + 643 + cc770_write_reg(priv, msgobj[mo].ctrl0, 644 + MSGVAL_SET | TXIE_RES | 645 + RXIE_SET | INTPND_RES); 646 + cc770_write_reg(priv, msgobj[mo].ctrl1, 647 + NEWDAT_RES | MSGLST_RES | 648 + TXRQST_RES | RMTPND_RES); 649 + } 650 + } 651 + 652 + static void cc770_rtr_interrupt(struct net_device *dev, unsigned int o) 653 + { 654 + struct cc770_priv *priv = netdev_priv(dev); 655 + unsigned int mo = obj2msgobj(o); 656 + u8 ctrl0, ctrl1; 657 + int n = CC770_MAX_MSG; 658 + 659 + while (n--) { 660 + ctrl0 = cc770_read_reg(priv, msgobj[mo].ctrl0); 661 + if (!(ctrl0 & INTPND_SET)) 662 + break; 663 + 664 + ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); 665 + cc770_rx(dev, mo, ctrl1); 666 + 667 + cc770_write_reg(priv, msgobj[mo].ctrl0, 668 + MSGVAL_SET | TXIE_RES | 669 + RXIE_SET | INTPND_RES); 670 + cc770_write_reg(priv, msgobj[mo].ctrl1, 671 + NEWDAT_RES | CPUUPD_SET | 672 + TXRQST_RES | RMTPND_RES); 673 + } 674 + } 675 + 676 + static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) 677 + { 678 + struct cc770_priv *priv = netdev_priv(dev); 679 + struct net_device_stats *stats = &dev->stats; 680 + unsigned int mo = obj2msgobj(o); 681 + 682 + /* Nothing more to send, switch off interrupts */ 683 + cc770_write_reg(priv, msgobj[mo].ctrl0, 684 + MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); 685 + /* 686 + * We had some cases of repeated IRQ so make sure the 687 + * INT is acknowledged 688 + */ 689 + cc770_write_reg(priv, msgobj[mo].ctrl0, 690 + MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); 691 + 692 + stats->tx_packets++; 693 + can_get_echo_skb(dev, 0); 694 + netif_wake_queue(dev); 695 + } 696 + 697 + irqreturn_t cc770_interrupt(int irq, void *dev_id) 698 + { 699 + struct net_device *dev = (struct net_device *)dev_id; 700 + struct cc770_priv *priv = netdev_priv(dev); 701 + u8 intid; 702 + int o, n = 0; 703 + 704 + /* Shared interrupts and IRQ off? */ 705 + if (priv->can.state == CAN_STATE_STOPPED) 706 + return IRQ_NONE; 707 + 708 + if (priv->pre_irq) 709 + priv->pre_irq(priv); 710 + 711 + while (n < CC770_MAX_IRQ) { 712 + /* Read the highest pending interrupt request */ 713 + intid = cc770_read_reg(priv, interrupt); 714 + if (!intid) 715 + break; 716 + n++; 717 + 718 + if (intid == 1) { 719 + /* Exit in case of bus-off */ 720 + if (cc770_status_interrupt(dev)) 721 + break; 722 + } else { 723 + o = intid2obj(intid); 724 + 725 + if (o >= CC770_OBJ_MAX) { 726 + netdev_err(dev, "Unexpected interrupt id %d\n", 727 + intid); 728 + continue; 729 + } 730 + 731 + if (priv->obj_flags[o] & CC770_OBJ_FLAG_RTR) 732 + cc770_rtr_interrupt(dev, o); 733 + else if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) 734 + cc770_rx_interrupt(dev, o); 735 + else 736 + cc770_tx_interrupt(dev, o); 737 + } 738 + } 739 + 740 + if (priv->post_irq) 741 + priv->post_irq(priv); 742 + 743 + if (n >= CC770_MAX_IRQ) 744 + netdev_dbg(dev, "%d messages handled in ISR", n); 745 + 746 + return (n) ? IRQ_HANDLED : IRQ_NONE; 747 + } 748 + 749 + static int cc770_open(struct net_device *dev) 750 + { 751 + struct cc770_priv *priv = netdev_priv(dev); 752 + int err; 753 + 754 + /* set chip into reset mode */ 755 + set_reset_mode(dev); 756 + 757 + /* common open */ 758 + err = open_candev(dev); 759 + if (err) 760 + return err; 761 + 762 + err = request_irq(dev->irq, &cc770_interrupt, priv->irq_flags, 763 + dev->name, dev); 764 + if (err) { 765 + close_candev(dev); 766 + return -EAGAIN; 767 + } 768 + 769 + /* init and start chip */ 770 + cc770_start(dev); 771 + 772 + netif_start_queue(dev); 773 + 774 + return 0; 775 + } 776 + 777 + static int cc770_close(struct net_device *dev) 778 + { 779 + netif_stop_queue(dev); 780 + set_reset_mode(dev); 781 + 782 + free_irq(dev->irq, dev); 783 + close_candev(dev); 784 + 785 + return 0; 786 + } 787 + 788 + struct net_device *alloc_cc770dev(int sizeof_priv) 789 + { 790 + struct net_device *dev; 791 + struct cc770_priv *priv; 792 + 793 + dev = alloc_candev(sizeof(struct cc770_priv) + sizeof_priv, 794 + CC770_ECHO_SKB_MAX); 795 + if (!dev) 796 + return NULL; 797 + 798 + priv = netdev_priv(dev); 799 + 800 + priv->dev = dev; 801 + priv->can.bittiming_const = &cc770_bittiming_const; 802 + priv->can.do_set_bittiming = cc770_set_bittiming; 803 + priv->can.do_set_mode = cc770_set_mode; 804 + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; 805 + 806 + memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); 807 + 808 + if (sizeof_priv) 809 + priv->priv = (void *)priv + sizeof(struct cc770_priv); 810 + 811 + return dev; 812 + } 813 + EXPORT_SYMBOL_GPL(alloc_cc770dev); 814 + 815 + void free_cc770dev(struct net_device *dev) 816 + { 817 + free_candev(dev); 818 + } 819 + EXPORT_SYMBOL_GPL(free_cc770dev); 820 + 821 + static const struct net_device_ops cc770_netdev_ops = { 822 + .ndo_open = cc770_open, 823 + .ndo_stop = cc770_close, 824 + .ndo_start_xmit = cc770_start_xmit, 825 + }; 826 + 827 + int register_cc770dev(struct net_device *dev) 828 + { 829 + struct cc770_priv *priv = netdev_priv(dev); 830 + int err; 831 + 832 + err = cc770_probe_chip(dev); 833 + if (err) 834 + return err; 835 + 836 + dev->netdev_ops = &cc770_netdev_ops; 837 + 838 + dev->flags |= IFF_ECHO; /* we support local echo */ 839 + 840 + /* Should we use additional functions? */ 841 + if (!i82527_compat && priv->control_normal_mode & CTRL_EAF) { 842 + priv->can.do_get_berr_counter = cc770_get_berr_counter; 843 + priv->control_normal_mode = CTRL_IE | CTRL_EAF | CTRL_EIE; 844 + netdev_dbg(dev, "i82527 mode with additional functions\n"); 845 + } else { 846 + priv->control_normal_mode = CTRL_IE | CTRL_EIE; 847 + netdev_dbg(dev, "strict i82527 compatibility mode\n"); 848 + } 849 + 850 + chipset_init(priv); 851 + set_reset_mode(dev); 852 + 853 + return register_candev(dev); 854 + } 855 + EXPORT_SYMBOL_GPL(register_cc770dev); 856 + 857 + void unregister_cc770dev(struct net_device *dev) 858 + { 859 + set_reset_mode(dev); 860 + unregister_candev(dev); 861 + } 862 + EXPORT_SYMBOL_GPL(unregister_cc770dev); 863 + 864 + static __init int cc770_init(void) 865 + { 866 + if (msgobj15_eff) { 867 + cc770_obj_flags[CC770_OBJ_RX0] |= CC770_OBJ_FLAG_EFF; 868 + cc770_obj_flags[CC770_OBJ_RX1] &= ~CC770_OBJ_FLAG_EFF; 869 + } 870 + 871 + pr_info("CAN netdevice driver\n"); 872 + 873 + return 0; 874 + } 875 + module_init(cc770_init); 876 + 877 + static __exit void cc770_exit(void) 878 + { 879 + pr_info("driver removed\n"); 880 + } 881 + module_exit(cc770_exit);
+203
drivers/net/can/cc770/cc770.h
··· 1 + /* 2 + * Core driver for the CC770 and AN82527 CAN controllers 3 + * 4 + * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the version 2 of the GNU General Public License 8 + * as published by the Free Software Foundation 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #ifndef CC770_DEV_H 17 + #define CC770_DEV_H 18 + 19 + #include <linux/can/dev.h> 20 + 21 + struct cc770_msgobj { 22 + u8 ctrl0; 23 + u8 ctrl1; 24 + u8 id[4]; 25 + u8 config; 26 + u8 data[8]; 27 + u8 dontuse; /* padding */ 28 + } __packed; 29 + 30 + struct cc770_regs { 31 + union { 32 + struct cc770_msgobj msgobj[16]; /* Message object 1..15 */ 33 + struct { 34 + u8 control; /* Control Register */ 35 + u8 status; /* Status Register */ 36 + u8 cpu_interface; /* CPU Interface Register */ 37 + u8 dontuse1; 38 + u8 high_speed_read[2]; /* High Speed Read */ 39 + u8 global_mask_std[2]; /* Standard Global Mask */ 40 + u8 global_mask_ext[4]; /* Extended Global Mask */ 41 + u8 msg15_mask[4]; /* Message 15 Mask */ 42 + u8 dontuse2[15]; 43 + u8 clkout; /* Clock Out Register */ 44 + u8 dontuse3[15]; 45 + u8 bus_config; /* Bus Configuration Register */ 46 + u8 dontuse4[15]; 47 + u8 bit_timing_0; /* Bit Timing Register byte 0 */ 48 + u8 dontuse5[15]; 49 + u8 bit_timing_1; /* Bit Timing Register byte 1 */ 50 + u8 dontuse6[15]; 51 + u8 interrupt; /* Interrupt Register */ 52 + u8 dontuse7[15]; 53 + u8 rx_error_counter; /* Receive Error Counter */ 54 + u8 dontuse8[15]; 55 + u8 tx_error_counter; /* Transmit Error Counter */ 56 + u8 dontuse9[31]; 57 + u8 p1_conf; 58 + u8 dontuse10[15]; 59 + u8 p2_conf; 60 + u8 dontuse11[15]; 61 + u8 p1_in; 62 + u8 dontuse12[15]; 63 + u8 p2_in; 64 + u8 dontuse13[15]; 65 + u8 p1_out; 66 + u8 dontuse14[15]; 67 + u8 p2_out; 68 + u8 dontuse15[15]; 69 + u8 serial_reset_addr; 70 + }; 71 + }; 72 + } __packed; 73 + 74 + /* Control Register (0x00) */ 75 + #define CTRL_INI 0x01 /* Initialization */ 76 + #define CTRL_IE 0x02 /* Interrupt Enable */ 77 + #define CTRL_SIE 0x04 /* Status Interrupt Enable */ 78 + #define CTRL_EIE 0x08 /* Error Interrupt Enable */ 79 + #define CTRL_EAF 0x20 /* Enable additional functions */ 80 + #define CTRL_CCE 0x40 /* Change Configuration Enable */ 81 + 82 + /* Status Register (0x01) */ 83 + #define STAT_LEC_STUFF 0x01 /* Stuff error */ 84 + #define STAT_LEC_FORM 0x02 /* Form error */ 85 + #define STAT_LEC_ACK 0x03 /* Acknowledgement error */ 86 + #define STAT_LEC_BIT1 0x04 /* Bit1 error */ 87 + #define STAT_LEC_BIT0 0x05 /* Bit0 error */ 88 + #define STAT_LEC_CRC 0x06 /* CRC error */ 89 + #define STAT_LEC_MASK 0x07 /* Last Error Code mask */ 90 + #define STAT_TXOK 0x08 /* Transmit Message Successfully */ 91 + #define STAT_RXOK 0x10 /* Receive Message Successfully */ 92 + #define STAT_WAKE 0x20 /* Wake Up Status */ 93 + #define STAT_WARN 0x40 /* Warning Status */ 94 + #define STAT_BOFF 0x80 /* Bus Off Status */ 95 + 96 + /* 97 + * CPU Interface Register (0x02) 98 + * Clock Out Register (0x1f) 99 + * Bus Configuration Register (0x2f) 100 + * 101 + * see include/linux/can/platform/cc770.h 102 + */ 103 + 104 + /* Message Control Register 0 (Base Address + 0x0) */ 105 + #define INTPND_RES 0x01 /* No Interrupt pending */ 106 + #define INTPND_SET 0x02 /* Interrupt pending */ 107 + #define INTPND_UNC 0x03 108 + #define RXIE_RES 0x04 /* Receive Interrupt Disable */ 109 + #define RXIE_SET 0x08 /* Receive Interrupt Enable */ 110 + #define RXIE_UNC 0x0c 111 + #define TXIE_RES 0x10 /* Transmit Interrupt Disable */ 112 + #define TXIE_SET 0x20 /* Transmit Interrupt Enable */ 113 + #define TXIE_UNC 0x30 114 + #define MSGVAL_RES 0x40 /* Message Invalid */ 115 + #define MSGVAL_SET 0x80 /* Message Valid */ 116 + #define MSGVAL_UNC 0xc0 117 + 118 + /* Message Control Register 1 (Base Address + 0x01) */ 119 + #define NEWDAT_RES 0x01 /* No New Data */ 120 + #define NEWDAT_SET 0x02 /* New Data */ 121 + #define NEWDAT_UNC 0x03 122 + #define MSGLST_RES 0x04 /* No Message Lost */ 123 + #define MSGLST_SET 0x08 /* Message Lost */ 124 + #define MSGLST_UNC 0x0c 125 + #define CPUUPD_RES 0x04 /* No CPU Updating */ 126 + #define CPUUPD_SET 0x08 /* CPU Updating */ 127 + #define CPUUPD_UNC 0x0c 128 + #define TXRQST_RES 0x10 /* No Transmission Request */ 129 + #define TXRQST_SET 0x20 /* Transmission Request */ 130 + #define TXRQST_UNC 0x30 131 + #define RMTPND_RES 0x40 /* No Remote Request Pending */ 132 + #define RMTPND_SET 0x80 /* Remote Request Pending */ 133 + #define RMTPND_UNC 0xc0 134 + 135 + /* Message Configuration Register (Base Address + 0x06) */ 136 + #define MSGCFG_XTD 0x04 /* Extended Identifier */ 137 + #define MSGCFG_DIR 0x08 /* Direction is Transmit */ 138 + 139 + #define MSGOBJ_FIRST 1 140 + #define MSGOBJ_LAST 15 141 + 142 + #define CC770_IO_SIZE 0x100 143 + #define CC770_MAX_IRQ 20 /* max. number of interrupts handled in ISR */ 144 + #define CC770_MAX_MSG 4 /* max. number of messages handled in ISR */ 145 + 146 + #define CC770_ECHO_SKB_MAX 1 147 + 148 + #define cc770_read_reg(priv, member) \ 149 + priv->read_reg(priv, offsetof(struct cc770_regs, member)) 150 + 151 + #define cc770_write_reg(priv, member, value) \ 152 + priv->write_reg(priv, offsetof(struct cc770_regs, member), value) 153 + 154 + /* 155 + * Message objects and flags used by this driver 156 + */ 157 + #define CC770_OBJ_FLAG_RX 0x01 158 + #define CC770_OBJ_FLAG_RTR 0x02 159 + #define CC770_OBJ_FLAG_EFF 0x04 160 + 161 + enum { 162 + CC770_OBJ_RX0 = 0, /* for receiving normal messages */ 163 + CC770_OBJ_RX1, /* for receiving normal messages */ 164 + CC770_OBJ_RX_RTR0, /* for receiving remote transmission requests */ 165 + CC770_OBJ_RX_RTR1, /* for receiving remote transmission requests */ 166 + CC770_OBJ_TX, /* for sending messages */ 167 + CC770_OBJ_MAX 168 + }; 169 + 170 + #define obj2msgobj(o) (MSGOBJ_LAST - (o)) /* message object 11..15 */ 171 + 172 + /* 173 + * CC770 private data structure 174 + */ 175 + struct cc770_priv { 176 + struct can_priv can; /* must be the first member */ 177 + struct sk_buff *echo_skb; 178 + 179 + /* the lower-layer is responsible for appropriate locking */ 180 + u8 (*read_reg)(const struct cc770_priv *priv, int reg); 181 + void (*write_reg)(const struct cc770_priv *priv, int reg, u8 val); 182 + void (*pre_irq)(const struct cc770_priv *priv); 183 + void (*post_irq)(const struct cc770_priv *priv); 184 + 185 + void *priv; /* for board-specific data */ 186 + struct net_device *dev; 187 + 188 + void __iomem *reg_base; /* ioremap'ed address to registers */ 189 + unsigned long irq_flags; /* for request_irq() */ 190 + 191 + unsigned char obj_flags[CC770_OBJ_MAX]; 192 + u8 control_normal_mode; /* Control register for normal mode */ 193 + u8 cpu_interface; /* CPU interface register */ 194 + u8 clkout; /* Clock out register */ 195 + u8 bus_config; /* Bus conffiguration register */ 196 + }; 197 + 198 + struct net_device *alloc_cc770dev(int sizeof_priv); 199 + void free_cc770dev(struct net_device *dev); 200 + int register_cc770dev(struct net_device *dev); 201 + void unregister_cc770dev(struct net_device *dev); 202 + 203 + #endif /* CC770_DEV_H */
+33
include/linux/can/platform/cc770.h
··· 1 + #ifndef _CAN_PLATFORM_CC770_H_ 2 + #define _CAN_PLATFORM_CC770_H_ 3 + 4 + /* CPU Interface Register (0x02) */ 5 + #define CPUIF_CEN 0x01 /* Clock Out Enable */ 6 + #define CPUIF_MUX 0x04 /* Multiplex */ 7 + #define CPUIF_SLP 0x08 /* Sleep */ 8 + #define CPUIF_PWD 0x10 /* Power Down Mode */ 9 + #define CPUIF_DMC 0x20 /* Divide Memory Clock */ 10 + #define CPUIF_DSC 0x40 /* Divide System Clock */ 11 + #define CPUIF_RST 0x80 /* Hardware Reset Status */ 12 + 13 + /* Clock Out Register (0x1f) */ 14 + #define CLKOUT_CD_MASK 0x0f /* Clock Divider mask */ 15 + #define CLKOUT_SL_MASK 0x30 /* Slew Rate mask */ 16 + #define CLKOUT_SL_SHIFT 4 17 + 18 + /* Bus Configuration Register (0x2f) */ 19 + #define BUSCFG_DR0 0x01 /* Disconnect RX0 Input / Select RX input */ 20 + #define BUSCFG_DR1 0x02 /* Disconnect RX1 Input / Silent mode */ 21 + #define BUSCFG_DT1 0x08 /* Disconnect TX1 Output */ 22 + #define BUSCFG_POL 0x20 /* Polarity dominant or recessive */ 23 + #define BUSCFG_CBY 0x40 /* Input Comparator Bypass */ 24 + 25 + struct cc770_platform_data { 26 + u32 osc_freq; /* CAN bus oscillator frequency in Hz */ 27 + 28 + u8 cir; /* CPU Interface Register */ 29 + u8 cor; /* Clock Out Register */ 30 + u8 bcr; /* Bus Configuration Register */ 31 + }; 32 + 33 + #endif /* !_CAN_PLATFORM_CC770_H_ */