X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/7440c5c6ece06cdf6ea19270047cca22b324d73a..04ac67cc3cac14cd601daacd0592121ec0b84012:/lincan/src/hcan2.c diff --git a/lincan/src/hcan2.c b/lincan/src/hcan2.c index a31490f..f06fdd1 100644 --- a/lincan/src/hcan2.c +++ b/lincan/src/hcan2.c @@ -1,7 +1,37 @@ -/* hcan2.c - * Linux CAN-bus device driver. - * This software is released under the GPL-License. - */ +/**************************************************************************/ +/* File: hcan2.c - Renesas SH7760 HCAN2 controller support */ +/* */ +/* LinCAN - (Not only) Linux CAN bus driver */ +/* Copyright (C) 2002-2009 DCE FEE CTU Prague */ +/* Copyright (C) 2002-2009 Pavel Pisa */ +/* Copyright (C) 2007-2008 Martin Petera */ +/* Funded by OCERA and FRESCOR IST projects */ +/* Based on CAN driver code by Arnaud Westenberg */ +/* */ +/* LinCAN is free software; you can redistribute it and/or modify it */ +/* under terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2, or (at your option) any */ +/* later version. LinCAN is distributed in the hope that it will be */ +/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */ +/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* General Public License for more details. You should have received a */ +/* copy of the GNU General Public License along with LinCAN; see file */ +/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */ +/* Cambridge, MA 02139, USA. */ +/* */ +/* To allow use of LinCAN in the compact embedded systems firmware */ +/* and RT-executives (RTEMS for example), main authors agree with next */ +/* special exception: */ +/* */ +/* Including LinCAN header files in a file, instantiating LinCAN generics */ +/* or templates, or linking other files with LinCAN objects to produce */ +/* an application image/executable, does not by itself cause the */ +/* resulting application image/executable to be covered by */ +/* the GNU General Public License. */ +/* This exception does not however invalidate any other reasons */ +/* why the executable file might be covered by the GNU Public License. */ +/* Publication of enhanced or derived LinCAN files is required although. */ +/**************************************************************************/ #include "../include/can.h" #include "../include/can_sysdep.h" @@ -46,7 +76,7 @@ uint16_t IRQs = ~(HCAN2_IRR_DFRI + HCAN2_IRR_MBEI + HCAN2_IRR_BOI + HCAN2_IRR_EP int hcan2_chip_config(struct canchip_t *chip) { DEBUGMSG("Configuring chip...\n"); - + if (hcan2_enable_configuration(chip)) return -ENODEV; @@ -206,7 +236,7 @@ int hcan2_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, int sa bcr1 = (((tseg1 - 1) & 0x000f) << 12) + (((tseg2 - 1) & 0x0007) << 8) + ((sjw & 0x0003) << 4); bcr0 = (best_brp - 1) & 0x00ff; - hcan2_set_btregs(chip, bcr0, bcr1); + hcan2_set_btregs(chip, bcr0, bcr1); hcan2_disable_configuration(chip); @@ -224,7 +254,7 @@ int hcan2_set_btregs(struct canchip_t *chip, unsigned short bcr0, unsigned short can_write_reg_w(chip, bcr1, HCAN2_BCR1); can_write_reg_w(chip, bcr0, HCAN2_BCR0); - + /* DEBUGMSG("BCR0 and BCR1 successfully set.\n"); */ return 0; } @@ -259,8 +289,8 @@ int hcan2_stop_chip(struct canchip_t *chip) int hcan2_attach_to_chip(struct canchip_t *chip) { /* DEBUGMSG("Attaching to chip %d.\n", chip->chip_idx); */ - - /* initialize chip */ + + /* initialize chip */ if (hcan2_enable_configuration(chip)) return -ENODEV; @@ -288,9 +318,9 @@ int hcan2_release_chip(struct canchip_t *chip) { hcan2_stop_chip(chip); can_disable_irq(chip->chip_irq); - + hcan2_clear_objects(chip); - + DEBUGMSG("Chip released [%02d]\n", chip->chip_idx); return 0; } @@ -302,27 +332,28 @@ int hcan2_standard_mask(struct canchip_t *chip, unsigned short code, unsigned sh struct msgobj_t * obj; int obj_idx = (int) (chip->chip_data); - if (code & 0x1ffff800) + if (code & 0x1ffff800) return hcan2_extended_mask(chip, code, mask); - + if (obj_idx > 0 && obj_idx <= 32) obj = chip->msgobj[obj_idx - 1]; else return -ENODEV; - chip->chip_data = (void*)0; /* reset mbox number */ + chip->chip_data = (void*)0; /* reset mbox number */ ctrl0 = ((code & 0x07ff) << 4); lafm0 = ((mask & 0x07ff) << 4); - + lafm0 |= 0x0003; /* ignore Ext ID 17:16 */ + can_write_reg_w(chip, ctrl0, (int) obj->obj_base_addr + HCAN2_MB_CTRL0); can_write_reg_w(chip, 0x0000, (int) obj->obj_base_addr + HCAN2_MB_CTRL1); can_write_reg_w(chip, lafm0, (int) obj->obj_base_addr + HCAN2_MB_MASK); can_write_reg_w(chip, 0xffff, (int) obj->obj_base_addr + HCAN2_MB_MASK + 2); - DEBUGMSG("Set standard_mask [id:0x%04x, m:0x%04x]\n", code, mask); + DEBUGMSG("MB%02d: Set standard_mask [id:0x%04x, m:0x%04x]\n", obj_idx, code, lafm0); return 0; } @@ -333,7 +364,7 @@ int hcan2_extended_mask(struct canchip_t *chip, unsigned long code, unsigned lon struct msgobj_t * obj; int obj_idx = (int) (chip->chip_data); - + if (obj_idx > 0 && obj_idx <= 32) obj = chip->msgobj[obj_idx - 1]; else @@ -349,14 +380,14 @@ int hcan2_extended_mask(struct canchip_t *chip, unsigned long code, unsigned lon lafm0 = ((mask & 0x1ffc0000) >> 14); lafm0 |=((mask & 0x00030000) >> 16); lafm1 = (mask & 0x0000ffff); - + can_write_reg_w(chip, ctrl0, (int) obj->obj_base_addr + HCAN2_MB_CTRL0); can_write_reg_w(chip, ctrl1, (int) obj->obj_base_addr + HCAN2_MB_CTRL1); can_write_reg_w(chip, lafm0, (int) obj->obj_base_addr + HCAN2_MB_MASK); can_write_reg_w(chip, lafm1, (int) obj->obj_base_addr + HCAN2_MB_MASK + 2); - - DEBUGMSG("Set extended_mask [id:0x%08x, m:0x%08x]\n", (uint32_t)code, (uint32_t)mask); - + + DEBUGMSG("MB%02d: Set extended_mask [id:0x%08x, m:0x%08x]\n", obj_idx, (uint32_t)code, (uint32_t)mask); + return 0; } @@ -369,7 +400,7 @@ int hcan2_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj) /* clears mailbox and setup LFA to accept all Exted Messages */ hcan2_setup_mbox4read(obj); - + hcan2_disable_configuration(chip); return 0; @@ -379,15 +410,15 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct { DEBUGMSG("Pre write config\n"); - /* change Mailbox header only if neccessary */ + /* change Mailbox header only if neccessary */ /* otherwise change only data */ if (hcan2_compare_msg(obj, msg)) { if (hcan2_enable_configuration(chip)) return -ENODEV; - + hcan2_setup_mbox4write(obj, msg); - + if (hcan2_disable_configuration(chip)) return -ENODEV; } @@ -400,10 +431,10 @@ int hcan2_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct int hcan2_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg) { unsigned obj_bit; - int b_addr = ((obj->object - 1) / 16) * (-2); + int b_addr = ((obj->object - 1) / 16) * (-2); obj_bit = (1 << ((obj->object - 1) % 16)); - + /* CANMSG("Sending message [obj: %d]\n", obj->object - 1); */ can_write_reg_w(chip, obj_bit, b_addr + HCAN2_TXPR0); @@ -454,25 +485,24 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip) /* Received message */ if (irq_reg & HCAN2_IRR_DFRI) { - rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) + - can_read_reg_w(chip, HCAN2_RXPR0); + rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) + + can_read_reg_w(chip, HCAN2_RXPR0); - DEBUGMSG("Received message [0x%08x]\n", rxdf); + while(rxdf) { + DEBUGMSG("Received message [0x%08x]\n", rxdf); - while (rxdf) { /* find the message object */ - for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<max_objects) { - hcan2_irq_read_handler(chip, chip->msgobj[idx]); - - /* clear RXPR flag for this msgobj */ - can_write_reg_w(chip, (1 << (idx % 16)), HCAN2_RXPR0 - 2*(idx / 16)); - - rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) + + for (idx = 0; (idx < chip->max_objects) && rxdf; idx++) + if ((rxdf & (1<msgobj[idx]); + /* RXPR flag for this msgobj is cleared during irq_read_handler*/ + rxdf &= ~(1 << idx); + } + + + DEBUGMSG("Before reset flags [0x%08x]\n", rxdf); + rxdf = (can_read_reg_w(chip, HCAN2_RXPR1) << 16) + can_read_reg_w(chip, HCAN2_RXPR0); - } } } @@ -503,7 +533,7 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip) CANMSG("Warning: entering ERROR PASSIVE state\nTEC: %d REC: %d\n", (uint16_t)((tecrec >> 8) & 0x00ff), (uint16_t)(tecrec & 0x00ff)); - + /* Show warning only */ /* reset flag - by writing '1' */ @@ -511,17 +541,17 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip) } /* Message Overrun/Overwritten */ - if (irq_reg & HCAN2_IRR_MOOI) { + if (irq_reg & HCAN2_IRR_MOOI) { /* put get Unread Message Status Register */ rxdf = (can_read_reg_w(chip, HCAN2_UMSR1) << 16) + can_read_reg_w(chip, HCAN2_UMSR0); /* find the message object */ for (idx = 0; (idx < chip->max_objects) && !(rxdf & (1<max_objects) + if (idx < chip->max_objects) hcan2_notifyRXends(chip->msgobj[idx], CANQUEUE_NOTIFY_ERROR); /* reset flag */ @@ -543,12 +573,12 @@ int hcan2_irq_handler(int irq, struct canchip_t *chip) can_write_reg_w(chip, 0xffff, HCAN2_ABACK0); can_write_reg_w(chip, 0xffff, HCAN2_ABACK1); return CANCHIP_IRQ_HANDLED; - } + } - /* Clear TXACK flag */ + /* Clear TXACK flag */ can_write_reg_w(chip, 1 << (idx % 16), HCAN2_TXACK0 - 2 * (idx / 16)); - /* sends message */ + /* sends message */ hcan2_wakeup_tx(chip, chip->msgobj[idx]); } @@ -569,11 +599,11 @@ int hcan2_config_irqs(struct canchip_t *chip, short irqs) hcan2_clear_irq_flags(chip); can_write_reg_w(chip, irqs, HCAN2_IMR); - + /* allow all mailboxes to generate IRQ */ can_write_reg_w(chip, 0, HCAN2_MBIMR0); can_write_reg_w(chip, 0, HCAN2_MBIMR1); - + /* CANMSG("IRQ Mask set [0x%02x]\n", irqs); */ return 0; } @@ -603,7 +633,7 @@ int hcan2_check_tx_stat(struct canchip_t *chip) int hcan2_check_MB_tx_stat(struct canchip_t *chip, struct msgobj_t *obj) { /* Transmition is complete return 0 - no error */ - + /* MB1-MB15 are in CANTXPR0 and MB16-MB31 are in CANTXPR1 CANTXPR0 = CANTXPR1 + 0x0002 MB0 - receive only */ @@ -618,9 +648,9 @@ int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) if (obj->object == 1) /* msgbox 0 cant transmit only receive ! */ return -ENODEV; - + can_preempt_disable(); - + can_msgobj_set_fl(obj,TX_REQUEST); if(!can_msgobj_test_and_set_fl(obj,TX_LOCK) && !hcan2_check_MB_tx_stat(chip, obj)) @@ -628,7 +658,7 @@ int hcan2_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj) can_msgobj_clear_fl(obj,TX_REQUEST); hcan2_irq_write_handler(chip, obj); - + can_msgobj_clear_fl(obj,TX_LOCK); } else @@ -672,7 +702,7 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj) unsigned ctrl0, ctrl2, data; unsigned long flag_addr; uint16_t mb_offset; - + mb_offset = (int ) obj->obj_base_addr; @@ -684,7 +714,7 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj) obj->rx_msg.length = len = ctrl2 & HCAN2_MBCT2_DLC; obj->rx_msg.flags = (ctrl0 & HCAN2_MBCT0_RTR) ? MSG_RTR : 0; obj->rx_msg.cob = obj->object - 1; - + /* get ID of received message */ if (ctrl0 & HCAN2_MBCT0_IDE) { @@ -695,23 +725,23 @@ void hcan2_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj) } else obj->rx_msg.id = (ctrl0 & HCAN2_MBCT0_STDID)>>4; - + if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; for (i = 0; i < len; i++) { /* rcanqueue_ends_filt_conjuctionead 16bit data - two data bytes*/ data = can_read_reg_w(chip, (int) obj->obj_base_addr + HCAN2_MB_DATA1 + i); - obj->rx_msg.data[i] = (data & 0xff00) >> 8; - if (++i < len) obj->rx_msg.data[i] = data & 0x00ff; + obj->rx_msg.data[i] = (data & 0xff00) >> 8; // one data byte + if (++i < len) obj->rx_msg.data[i] = data & 0x00ff; // second data byte } /* Computes correct offset address of register from MSGBOX_IDX and RTR flag * result is one of these: * HCAN2_RXPR1, HCAN2_RXPR0, HCAN2_RFPR1, HCAN2_RFPR0 */ - flag_addr = ((ctrl0 & HCAN2_MBCT0_RTR) << 3) + HCAN2_RXPR0 - ((obj->object - 1) / 16) * 2; - + flag_addr = HCAN2_RXPR0 - (int)((obj->object - 1) / 16) * 2; + /* Reset flag by writing 1 to its position */ can_write_reg_w(chip, (1 << ((obj->object - 1) % 16)), flag_addr); @@ -800,7 +830,7 @@ int hcan2_fill_chipspecops(struct canchip_t *chip) chip->max_objects = 32; chip->write_register = chip->hostdevice->hwspecops->write_register; chip->read_register = chip->hostdevice->hwspecops->read_register; - + /* chip->flags; chip->baudrate; @@ -832,7 +862,7 @@ int hcan2_reset_chip(struct canchip_t *chip) * 11 recessive bits to join CAN bus activity */ - int i; + int i; unsigned gsr_reset; DEBUGMSG("Resetting HCAN2 chip %d...\n", chip->chip_idx); @@ -840,7 +870,7 @@ int hcan2_reset_chip(struct canchip_t *chip) /* send Reset Request */ can_write_reg_w(chip, HCAN2_MCR_RESET, HCAN2_MCR ); - /* Check hardware reset status */ + /* Check hardware reset status */ i = 0; gsr_reset = can_read_reg_w(chip, HCAN2_GSR) & HCAN2_GSR_RESET; while (!(gsr_reset) && ((i++) <= MAX_SETTING_WAIT_LOOPS)) @@ -947,14 +977,14 @@ void hcan2_clear_mbox(struct canchip_t *chip, int msgobj_idx) void hcan2_setup_mbox4write(struct msgobj_t * obj, struct canmsg_t * msg) { int mb_offset; - uint16_t ctrl0, ctrl1, ctrl2; + uint16_t ctrl0, ctrl1, ctrl2; struct canchip_t * chip = obj->hostchip; DEBUGMSG("Change Header\n"); mb_offset = (int) obj->obj_base_addr; - + hcan2_setup_ctrl_regs(msg, &ctrl0, &ctrl1, &ctrl2); can_write_reg_w(chip, ctrl0, mb_offset + HCAN2_MB_CTRL0); @@ -968,17 +998,17 @@ void hcan2_setup_mbox4write(struct msgobj_t * obj, struct canmsg_t * msg) void hcan2_setup_mbox4write_data(struct msgobj_t * obj, struct canmsg_t * msg) { int len,i, mb_offset; - uint16_t data; - + uint16_t data; + struct canchip_t * chip = obj->hostchip; DEBUGMSG("Change Data\n"); mb_offset = (int) obj->obj_base_addr; - + len = msg->length; if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; - + for (i = 0; i < len; i+=2) { data = (msg->data[i] << 8) + (i+1 < len ? msg->data[i+1] : 0); @@ -989,7 +1019,7 @@ void hcan2_setup_mbox4write_data(struct msgobj_t * obj, struct canmsg_t * msg) void hcan2_setup_mbox4read(struct msgobj_t * obj) { struct canchip_t * chip = obj->hostchip; - + hcan2_clear_mbox(chip, obj->object - 1); // in structure chip->chip_data is Mailbox number @@ -1034,7 +1064,7 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg) uint16_t ctrl0, ctrl1, ctrl2; uint16_t mb_offset; uint16_t c0,c1,c2; - + struct canchip_t * chip = obj->hostchip; mb_offset = (int) obj->obj_base_addr; @@ -1048,7 +1078,7 @@ int hcan2_compare_msg(struct msgobj_t * obj, struct canmsg_t * msg) /* if using EXT ID conpare also ctrl1 */ if (msg->flags & MSG_EXT && ctrl1 ^ c1) return 1; - + DEBUGMSG("C0 0x%04x HW: 0x%04x\n", ctrl0, c0); DEBUGMSG("C1 0x%04x HW: 0x%04x\n", ctrl1, c1);