#define PCA9553_LED_ON(c) PCA9553_LED_STATE(PCA9553_ON, c) #define PCA9553_LED_OFF(c) PCA9553_LED_STATE(PCA9553_OFF, c) #define PCA9553_LED_SLOW(c) PCA9553_LED_STATE(PCA9553_SLOW, c) #define PCA9553_LED_FAST(c) PCA9553_LED_STATE(PCA9553_FAST, c) #define PCA9553_LED_MASK(c) PCA9553_LED_STATE(0x03, c)
struct peak_pciec_card { void __iomem *cfg_base; /* Common for all channels */ void __iomem *reg_base; /* first channel base address */
u8 led_cache; /* leds state cache */
/* PCIExpressCard i2c data */ struct i2c_algo_bit_data i2c_bit; struct i2c_adapter led_chip; struct delayed_work led_work; /* led delayed work */ int chan_count; struct peak_pciec_chan channel[PEAK_PCI_CHAN_MAX];
};
/* "normal" pci register write callback is overloaded for leds control */ staticvoid peak_pci_write_reg(conststruct sja1000_priv *priv, int port, u8 val);
/* write commands to the LED chip though the I2C-bus of the PCAN-PCIeC */ staticint peak_pciec_write_pca9553(struct peak_pciec_card *card,
u8 offset, u8 data)
{
u8 buffer[2] = {
offset,
data
}; struct i2c_msg msg = {
.addr = PCA9553_1_SLAVEADDR,
.len = 2,
.buf = buffer,
}; int ret;
/* cache led mask */ if (offset == 5 && data == card->led_cache) return 0;
ret = i2c_transfer(&card->led_chip, &msg, 1); if (ret < 0) return ret;
if (offset == 5)
card->led_cache = data;
return 0;
}
/* delayed work callback used to control the LEDs */ staticvoid peak_pciec_led_work(struct work_struct *work)
{ struct peak_pciec_card *card =
container_of(work, struct peak_pciec_card, led_work.work); struct net_device *netdev;
u8 new_led = card->led_cache; int i, up_count = 0;
/* first check what is to do */ for (i = 0; i < card->chan_count; i++) { /* default is: not configured */
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_ON(i);
netdev = card->channel[i].netdev; if (!netdev || !(netdev->flags & IFF_UP)) continue;
/* if bytes counters changed, set fast blinking led */ if (netdev->stats.rx_bytes != card->channel[i].prev_rx_bytes) {
card->channel[i].prev_rx_bytes = netdev->stats.rx_bytes;
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_FAST(i);
} if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_FAST(i);
}
}
/* check if LS0 settings changed, only update i2c if so */
peak_pciec_write_pca9553(card, 5, new_led);
/* restart timer (except if no more configured channels) */ if (up_count)
schedule_delayed_work(&card->led_work, HZ);
}
/* set LEDs blinking state */ staticvoid peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
{
u8 new_led = card->led_cache; int i;
/* first check what is to do */ for (i = 0; i < card->chan_count; i++) if (led_mask & PCA9553_LED(i)) {
new_led &= ~PCA9553_LED_MASK(i);
new_led |= PCA9553_LED_STATE(s, i);
}
/* check if LS0 settings changed, only update i2c if so */
peak_pciec_write_pca9553(card, 5, new_led);
}
/* start one second delayed work to control LEDs */ staticvoid peak_pciec_start_led_work(struct peak_pciec_card *card)
{
schedule_delayed_work(&card->led_work, HZ);
}
/* switch LEDs to initial state */ return peak_pciec_write_pca9553(card, 5, PCA9553_LS0_INIT);
}
/* restore LEDs state to off peak_pciec_leds_exit */ staticvoid peak_pciec_leds_exit(struct peak_pciec_card *card)
{ /* switch LEDs to off */
peak_pciec_write_pca9553(card, 5, PCA9553_LED_OFF_ALL);
}
/* normal write sja1000 register method overloaded to catch when controller * is started or stopped, to control leds
*/ staticvoid peak_pciec_write_reg(conststruct sja1000_priv *priv, int port, u8 val)
{ struct peak_pci_chan *chan = priv->priv; struct peak_pciec_card *card = chan->pciec_card; int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE;
/* sja1000 register changes control the leds state */ if (port == SJA1000_MOD) switch (val) { case MOD_RM: /* Reset Mode: set led on */
peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_ON); break; case 0x00: /* Normal Mode: led slow blinking and start led timer */
peak_pciec_set_leds(card, PCA9553_LED(c), PCA9553_SLOW);
peak_pciec_start_led_work(card); break; default: break;
}
/* call base function */
peak_pci_write_reg(priv, port, val);
}
card = prev_chan->pciec_card; if (!card) return -ENODEV;
/* channel is the first one: do the init part */
} else { /* create the bit banging I2C adapter structure */
card = kzalloc(sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM;
INIT_DELAYED_WORK(&card->led_work, peak_pciec_led_work); /* PCAN-ExpressCard needs its own callback for leds */
priv->write_reg = peak_pciec_write_reg;
}
/* Set GPIO control register */
writew(0x0005, cfg_base + PITA_GPIOICR + 2); /* Enable all channels of this card */
writeb(0x00, cfg_base + PITA_GPIOICR); /* Toggle reset */
writeb(0x05, cfg_base + PITA_MISC + 3);
usleep_range(5000, 6000); /* Leave parport mux mode */
writeb(0x04, cfg_base + PITA_MISC + 3);
/* FPGA equipped card if not 0 */ if (readl(cfg_base + PEAK_VER_REG1)) { /* FPGA card: display version of the running firmware */
u32 fw_ver = readl(cfg_base + PEAK_VER_REG2);
/* Display commercial name (and, eventually, FW version) of the card */
dev_info(&pdev->dev, "%ux CAN %s%s\n",
channels, (constchar *)ent->driver_data, fw_str);
icr = readw(cfg_base + PITA_ICR + 2);
for (i = 0; i < channels; i++) {
dev = alloc_sja1000dev(sizeof(struct peak_pci_chan)); if (!dev) {
err = -ENOMEM; goto failure_remove_channels;
}
priv = netdev_priv(dev);
chan = priv->priv;
chan->cfg_base = cfg_base;
priv->reg_base = reg_base + i * PEAK_PCI_CHAN_SIZE;
priv->can.clock.freq = PEAK_PCI_CAN_CLOCK;
priv->ocr = PEAK_PCI_OCR;
priv->cdr = PEAK_PCI_CDR; /* Neither a slave nor a single device distributes the clock */ if (channels == 1 || i > 0)
priv->cdr |= CDR_CLK_OFF;
/* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while * the probe() function must return a negative errno in case of failure * (err is unchanged if negative)
*/ return pcibios_err_to_errno(err);
}
/* Loop over all registered devices */ while (1) { struct net_device *prev_dev = chan->prev_dev;
dev_info(&pdev->dev, "removing device %s\n", dev->name); /* do that only for first channel */ if (!prev_dev && chan->pciec_card)
peak_pciec_remove(chan->pciec_card);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
dev = prev_dev;
if (!dev) break;
priv = netdev_priv(dev);
chan = priv->priv;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.