static void disable_all_objs(const struct cc770_priv *priv) { int o, mo; for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) { mo = obj2msgobj(o); if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) { if (o > 0 && priv->control_normal_mode & CTRL_EAF) continue; cc770_write_reg(priv, msgobj[mo].ctrl1, NEWDAT_RES | MSGLST_RES | TXRQST_RES | RMTPND_RES); cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); } else { /* Clear message object for send */ cc770_write_reg(priv, msgobj[mo].ctrl1, RMTPND_RES | TXRQST_RES | CPUUPD_RES | NEWDAT_RES); cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); } } }
static void set_reset_mode(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); /* Enable configuration and puts chip in bus-off, disable interrupts */ cc770_write_reg(priv, control, CTRL_CCE | CTRL_INI); priv->can.state = CAN_STATE_STOPPED; /* Clear interrupts */ cc770_read_reg(priv, interrupt); /* Clear status register */ cc770_write_reg(priv, status, 0); /* Disable all used message objects */ disable_all_objs(priv); }
static void set_reset_mode(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); /* */ cc770_write_reg(priv, control, CTRL_CCE | CTRL_INI); priv->can.state = CAN_STATE_STOPPED; /* */ cc770_read_reg(priv, interrupt); /* */ cc770_write_reg(priv, status, 0); /* */ disable_all_objs(priv); }
static int cc770_set_bittiming(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); struct can_bittiming *bt = &priv->can.bittiming; u8 btr0, btr1; btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | (((bt->phase_seg2 - 1) & 0x7) << 4); if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) btr1 |= 0x80; netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); cc770_write_reg(priv, bit_timing_0, btr0); cc770_write_reg(priv, bit_timing_1, btr1); return 0; }
static void set_normal_mode(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); /* Clear interrupts */ cc770_read_reg(priv, interrupt); /* Clear status register and pre-set last error code */ cc770_write_reg(priv, status, STAT_LEC_MASK); /* Enable all used message objects*/ enable_all_objs(dev); /* * Clear bus-off, interrupts only for errors, * not for status change */ cc770_write_reg(priv, control, priv->control_normal_mode); priv->can.state = CAN_STATE_ERROR_ACTIVE; }
static void set_normal_mode(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); /* */ cc770_read_reg(priv, interrupt); /* */ cc770_write_reg(priv, status, STAT_LEC_MASK); /* */ enable_all_objs(dev); /* */ cc770_write_reg(priv, control, priv->control_normal_mode); priv->can.state = CAN_STATE_ERROR_ACTIVE; }
static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; struct can_frame *cf = (struct can_frame *)skb->data; unsigned int mo = obj2msgobj(CC770_OBJ_TX); u8 dlc, rtr; u32 id; int i; if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; if ((cc770_read_reg(priv, msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { netdev_err(dev, "TX register is still occupied!\n"); return NETDEV_TX_BUSY; } netif_stop_queue(dev); dlc = cf->can_dlc; id = cf->can_id; if (cf->can_id & CAN_RTR_FLAG) rtr = 0; else rtr = MSGCFG_DIR; cc770_write_reg(priv, msgobj[mo].ctrl1, RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES); if (id & CAN_EFF_FLAG) { id &= CAN_EFF_MASK; cc770_write_reg(priv, msgobj[mo].config, (dlc << 4) | rtr | MSGCFG_XTD); cc770_write_reg(priv, msgobj[mo].id[3], id << 3); cc770_write_reg(priv, msgobj[mo].id[2], id >> 5); cc770_write_reg(priv, msgobj[mo].id[1], id >> 13); cc770_write_reg(priv, msgobj[mo].id[0], id >> 21); } else {
static int cc770_probe_chip(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); /* Enable configuration, put chip in bus-off, disable ints */ cc770_write_reg(priv, control, CTRL_CCE | CTRL_EAF | CTRL_INI); /* Configure cpu interface / CLKOUT disable */ cc770_write_reg(priv, cpu_interface, priv->cpu_interface); /* * Check if hardware reset is still inactive or maybe there * is no chip in this address space */ if (cc770_read_reg(priv, cpu_interface) & CPUIF_RST) { netdev_info(dev, "probing @0x%p failed (reset)\n", priv->reg_base); return -ENODEV; } /* Write and read back test pattern (some arbitrary values) */ cc770_write_reg(priv, msgobj[1].data[1], 0x25); cc770_write_reg(priv, msgobj[2].data[3], 0x52); cc770_write_reg(priv, msgobj[10].data[6], 0xc3); if ((cc770_read_reg(priv, msgobj[1].data[1]) != 0x25) || (cc770_read_reg(priv, msgobj[2].data[3]) != 0x52) || (cc770_read_reg(priv, msgobj[10].data[6]) != 0xc3)) { netdev_info(dev, "probing @0x%p failed (pattern)\n", priv->reg_base); return -ENODEV; } /* Check if this chip is a CC770 supporting additional functions */ if (cc770_read_reg(priv, control) & CTRL_EAF) priv->control_normal_mode |= CTRL_EAF; return 0; }
static int cc770_probe_chip(struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); /* */ cc770_write_reg(priv, control, CTRL_CCE | CTRL_EAF | CTRL_INI); /* */ cc770_write_reg(priv, cpu_interface, priv->cpu_interface); /* */ if (cc770_read_reg(priv, cpu_interface) & CPUIF_RST) { netdev_info(dev, "probing @0x%p failed (reset)\n", priv->reg_base); return -ENODEV; } /* */ cc770_write_reg(priv, msgobj[1].data[1], 0x25); cc770_write_reg(priv, msgobj[2].data[3], 0x52); cc770_write_reg(priv, msgobj[10].data[6], 0xc3); if ((cc770_read_reg(priv, msgobj[1].data[1]) != 0x25) || (cc770_read_reg(priv, msgobj[2].data[3]) != 0x52) || (cc770_read_reg(priv, msgobj[10].data[6]) != 0xc3)) { netdev_info(dev, "probing @0x%p failed (pattern)\n", priv->reg_base); return -ENODEV; } /* */ if (cc770_read_reg(priv, control) & CTRL_EAF) priv->control_normal_mode |= CTRL_EAF; return 0; }
static void chipset_init(struct cc770_priv *priv) { int mo, id, data; /* Enable configuration and put chip in bus-off, disable interrupts */ cc770_write_reg(priv, control, (CTRL_CCE | CTRL_INI)); /* Set CLKOUT divider and slew rates */ cc770_write_reg(priv, clkout, priv->clkout); /* Configure CPU interface / CLKOUT enable */ cc770_write_reg(priv, cpu_interface, priv->cpu_interface); /* Set bus configuration */ cc770_write_reg(priv, bus_config, priv->bus_config); /* Clear interrupts */ cc770_read_reg(priv, interrupt); /* Clear status register */ cc770_write_reg(priv, status, 0); /* Clear and invalidate message objects */ for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++) { cc770_write_reg(priv, msgobj[mo].ctrl0, INTPND_UNC | RXIE_RES | TXIE_RES | MSGVAL_RES); cc770_write_reg(priv, msgobj[mo].ctrl0, INTPND_RES | RXIE_RES | TXIE_RES | MSGVAL_RES); cc770_write_reg(priv, msgobj[mo].ctrl1, NEWDAT_RES | MSGLST_RES | TXRQST_RES | RMTPND_RES); for (data = 0; data < 8; data++) cc770_write_reg(priv, msgobj[mo].data[data], 0); for (id = 0; id < 4; id++) cc770_write_reg(priv, msgobj[mo].id[id], 0); cc770_write_reg(priv, msgobj[mo].config, 0); } /* Set all global ID masks to "don't care" */ cc770_write_reg(priv, global_mask_std[0], 0); cc770_write_reg(priv, global_mask_std[1], 0); cc770_write_reg(priv, global_mask_ext[0], 0); cc770_write_reg(priv, global_mask_ext[1], 0); cc770_write_reg(priv, global_mask_ext[2], 0); cc770_write_reg(priv, global_mask_ext[3], 0); }
static void enable_all_objs(const struct net_device *dev) { struct cc770_priv *priv = netdev_priv(dev); u8 msgcfg; unsigned char obj_flags; unsigned int o, mo; for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) { obj_flags = priv->obj_flags[o]; mo = obj2msgobj(o); if (obj_flags & CC770_OBJ_FLAG_RX) { /* * We don't need extra objects for RTR and EFF if * the additional CC770 functions are enabled. */ if (priv->control_normal_mode & CTRL_EAF) { if (o > 0) continue; netdev_dbg(dev, "Message object %d for " "RX data, RTR, SFF and EFF\n", mo); } else { netdev_dbg(dev, "Message object %d for RX %s %s\n", mo, obj_flags & CC770_OBJ_FLAG_RTR ? "RTR" : "data", obj_flags & CC770_OBJ_FLAG_EFF ? "EFF" : "SFF"); } if (obj_flags & CC770_OBJ_FLAG_EFF) msgcfg = MSGCFG_XTD; else msgcfg = 0; if (obj_flags & CC770_OBJ_FLAG_RTR) msgcfg |= MSGCFG_DIR; cc770_write_reg(priv, msgobj[mo].config, msgcfg); cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_SET | TXIE_RES | RXIE_SET | INTPND_RES); if (obj_flags & CC770_OBJ_FLAG_RTR) cc770_write_reg(priv, msgobj[mo].ctrl1, NEWDAT_RES | CPUUPD_SET | TXRQST_RES | RMTPND_RES); else cc770_write_reg(priv, msgobj[mo].ctrl1, NEWDAT_RES | MSGLST_RES | TXRQST_RES | RMTPND_RES); } else { netdev_dbg(dev, "Message object %d for " "TX data, RTR, SFF and EFF\n", mo); cc770_write_reg(priv, msgobj[mo].ctrl1, RMTPND_RES | TXRQST_RES | CPUUPD_RES | NEWDAT_RES); cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); } } }
static void chipset_init(struct cc770_priv *priv) { int mo, id, data; /* */ cc770_write_reg(priv, control, (CTRL_CCE | CTRL_INI)); /* */ cc770_write_reg(priv, clkout, priv->clkout); /* */ cc770_write_reg(priv, cpu_interface, priv->cpu_interface); /* */ cc770_write_reg(priv, bus_config, priv->bus_config); /* */ cc770_read_reg(priv, interrupt); /* */ cc770_write_reg(priv, status, 0); /* */ for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++) { cc770_write_reg(priv, msgobj[mo].ctrl0, INTPND_UNC | RXIE_RES | TXIE_RES | MSGVAL_RES); cc770_write_reg(priv, msgobj[mo].ctrl0, INTPND_RES | RXIE_RES | TXIE_RES | MSGVAL_RES); cc770_write_reg(priv, msgobj[mo].ctrl1, NEWDAT_RES | MSGLST_RES | TXRQST_RES | RMTPND_RES); for (data = 0; data < 8; data++) cc770_write_reg(priv, msgobj[mo].data[data], 0); for (id = 0; id < 4; id++) cc770_write_reg(priv, msgobj[mo].id[id], 0); cc770_write_reg(priv, msgobj[mo].config, 0); } /* */ cc770_write_reg(priv, global_mask_std[0], 0); cc770_write_reg(priv, global_mask_std[1], 0); cc770_write_reg(priv, global_mask_ext[0], 0); cc770_write_reg(priv, global_mask_ext[1], 0); cc770_write_reg(priv, global_mask_ext[2], 0); cc770_write_reg(priv, global_mask_ext[3], 0); }