/* EEPROM Status Register bits */ #define PCC_EEP_SR_WEN 0x02 /* EEPROM SR Write Enable bit */ #define PCC_EEP_SR_WIP 0x01 /* EEPROM SR Write In Progress bit */
/* * The board configuration is probably following: * RX1 is connected to ground. * TX1 is not connected. * CLKO is not connected. * Setting the OCR register to 0xDA is a good idea. * This means normal output mode, push-pull and the correct polarity.
*/ #define PCC_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
/* * In the CDR register, you should set CBP to 1. * You will probably also want to set the clock divider value to 7 * (meaning direct oscillator output) because the second SJA1000 chip * is driven by the first one CLKOUT output.
*/ #define PCC_CDR (CDR_CBP | CDR_CLKOUT_MASK)
/* * start timer which controls leds state
*/ staticvoid pcan_start_led_timer(struct pcan_pccard *card)
{ if (!timer_pending(&card->led_timer))
mod_timer(&card->led_timer, jiffies + HZ);
}
/* * stop the timer which controls leds state
*/ staticvoid pcan_stop_led_timer(struct pcan_pccard *card)
{
timer_delete_sync(&card->led_timer);
}
/* * read a sja1000 register
*/ static u8 pcan_read_canreg(conststruct sja1000_priv *priv, int port)
{ return ioread8(priv->reg_base + port);
}
/* * write a sja1000 register
*/ staticvoid pcan_write_canreg(conststruct sja1000_priv *priv, int port, u8 v)
{ struct pcan_pccard *card = priv->priv; int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;
/* sja1000 register changes control the leds state */ if (port == SJA1000_MOD) switch (v) { case MOD_RM: /* Reset Mode: set led on */
pcan_set_leds(card, PCC_LED(c), PCC_LED_ON); break; case 0x00: /* Normal Mode: led slow blinking and start led timer */
pcan_set_leds(card, PCC_LED(c), PCC_LED_SLOW);
pcan_start_led_timer(card); break; default: break;
}
iowrite8(v, priv->reg_base + port);
}
/* * read a register from the common area
*/ static u8 pcan_read_reg(struct pcan_pccard *card, int port)
{ return ioread8(card->ioport_addr + PCC_COMN_OFF + port);
}
/* * write a register into the common area
*/ staticvoid pcan_write_reg(struct pcan_pccard *card, int port, u8 v)
{ /* cache ccr value */ if (port == PCC_CCR) { if (card->ccr == v) return;
card->ccr = v;
}
/* * check whether the card is present by checking its fw version numbers * against values read at probing time.
*/ staticinlineint pcan_pccard_present(struct pcan_pccard *card)
{ return ((pcan_read_reg(card, PCC_FW_MAJOR) == card->fw_major) &&
(pcan_read_reg(card, PCC_FW_MINOR) == card->fw_minor));
}
/* * wait for SPI engine while it is busy
*/ staticint pcan_wait_spi_busy(struct pcan_pccard *card)
{ unsignedlong timeout = jiffies +
msecs_to_jiffies(PCC_SPI_MAX_BUSY_WAIT_MS) + 1;
/* be sure to read status at least once after sleeping */ while (pcan_read_reg(card, PCC_CSR) & PCC_CSR_SPI_BUSY) { if (time_after(jiffies, timeout)) return -EBUSY;
schedule();
}
return 0;
}
/* * write data in device eeprom
*/ staticint pcan_write_eeprom(struct pcan_pccard *card, u16 addr, u8 v)
{
u8 status; int err, i;
/* wait until write enabled */ for (i = 0; i < PCC_WRITE_MAX_LOOP; i++) { /* write instruction reading the status register */
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_RDSR);
err = pcan_wait_spi_busy(card); if (err) goto we_spi_err;
/* get status register value and check write enable bit */
status = pcan_read_reg(card, PCC_SPI_DIR); if (status & PCC_EEP_SR_WEN) break;
}
if (i >= PCC_WRITE_MAX_LOOP) {
dev_err(&card->pdev->dev, "stop waiting to be allowed to write in eeprom\n"); return -EIO;
}
/* set address and data */
pcan_write_reg(card, PCC_SPI_ADR, addr & 0xff);
pcan_write_reg(card, PCC_SPI_DOR, v);
/* * write instruction with bit[3] set according to address value: * if addr refers to upper half of the memory array: bit[3] = 1
*/
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_WRITE(addr));
err = pcan_wait_spi_busy(card); if (err) goto we_spi_err;
/* wait while write in progress */ for (i = 0; i < PCC_WRITE_MAX_LOOP; i++) { /* write instruction reading the status register */
pcan_write_reg(card, PCC_SPI_IR, PCC_EEP_RDSR);
err = pcan_wait_spi_busy(card); if (err) goto we_spi_err;
/* get status register value and check write in progress bit */
status = pcan_read_reg(card, PCC_SPI_DIR); if (!(status & PCC_EEP_SR_WIP)) break;
}
if (i >= PCC_WRITE_MAX_LOOP) {
dev_err(&card->pdev->dev, "stop waiting for write in eeprom to complete\n"); return -EIO;
}
for (i = 0; i < card->chan_count; i++) if (led_mask & PCC_LED(i)) { /* clear corresponding led bits in ccr */
ccr &= ~PCC_CCR_LED_MASK_CHAN(i); /* then set new bits */
ccr |= PCC_CCR_LED_CHAN(state, i);
}
/* real write only if something has changed in ccr */
pcan_write_reg(card, PCC_CCR, ccr);
}
/* * enable/disable CAN connectors power
*/ staticinlinevoid pcan_set_can_power(struct pcan_pccard *card, int onoff)
{ int err;
err = pcan_write_eeprom(card, 0, !!onoff); if (err)
dev_err(&card->pdev->dev, "failed setting power %s to can connectors (err %d)\n",
(onoff) ? "on" : "off", err);
}
/* * set leds state according to channel activity
*/ staticvoid pcan_led_timer(struct timer_list *t)
{ struct pcan_pccard *card = timer_container_of(card, t, led_timer); struct net_device *netdev; int i, up_count = 0;
u8 ccr;
ccr = card->ccr; for (i = 0; i < card->chan_count; i++) { /* default is: not configured */
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_ON_CHAN(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;
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_FAST_CHAN(i);
} if (netdev->stats.tx_bytes != card->channel[i].prev_tx_bytes) {
card->channel[i].prev_tx_bytes = netdev->stats.tx_bytes;
ccr &= ~PCC_CCR_LED_MASK_CHAN(i);
ccr |= PCC_CCR_LED_FAST_CHAN(i);
}
}
/* write the new leds state */
pcan_write_reg(card, PCC_CCR, ccr);
/* restart timer (except if no more configured channels) */ if (up_count)
mod_timer(&card->led_timer, jiffies + HZ);
}
/* * interrupt service routine
*/ static irqreturn_t pcan_isr(int irq, void *dev_id)
{ struct pcan_pccard *card = dev_id; int irq_handled;
/* prevent from infinite loop */ for (irq_handled = 0; irq_handled < PCC_ISR_MAX_LOOP; irq_handled++) { /* handle shared interrupt and next loop */ int nothing_to_handle = 1; int i;
/* check interrupt for each channel */ for (i = 0; i < card->chan_count; i++) { struct net_device *netdev;
/* * check whether the card is present before calling * sja1000_interrupt() to speed up hotplug detection
*/ if (!pcan_pccard_present(card)) { /* card unplugged during isr */ return IRQ_NONE;
}
/* * should check whether all or SJA1000_MAX_IRQ * interrupts have been handled: loop again to be sure.
*/
netdev = card->channel[i].netdev; if (netdev &&
sja1000_interrupt(irq, netdev) == IRQ_HANDLED)
nothing_to_handle = 0;
}
if (nothing_to_handle) break;
}
return (irq_handled) ? IRQ_HANDLED : IRQ_NONE;
}
/* * free all resources used by the channels and switch off leds and can power
*/ staticvoid pcan_free_channels(struct pcan_pccard *card)
{ int i;
u8 led_mask = 0;
for (i = 0; i < card->chan_count; i++) { struct net_device *netdev; char name[IFNAMSIZ];
led_mask |= PCC_LED(i);
netdev = card->channel[i].netdev; if (!netdev) continue;
/* do it only if device not removed */ if (pcan_pccard_present(card)) {
pcan_set_leds(card, led_mask, PCC_LED_OFF);
pcan_set_can_power(card, 0);
}
}
/* * check if a CAN controller is present at the specified location
*/ staticinlineint pcan_channel_present(struct sja1000_priv *priv)
{ /* make sure SJA1000 is in reset mode */
pcan_write_canreg(priv, SJA1000_MOD, 1);
pcan_write_canreg(priv, SJA1000_CDR, CDR_PELICAN);
/* create one network device per channel detected */ for (i = 0; i < ARRAY_SIZE(card->channel); i++) { struct net_device *netdev; struct sja1000_priv *priv;
/* check if channel is present */ if (!pcan_channel_present(priv)) {
dev_err(&pdev->dev, "channel %d not present\n", i);
free_sja1000dev(netdev); continue;
}
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.