1 /**************************************************************************/
2 /* File: hms30c7202_can.c - Hynix HMS30c7202 ARM integrated C_CAN handling*/
4 /* LinCAN - (Not only) Linux CAN bus driver */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
7 /* Copyright (C) 2004 Sebastian Stolzenberg <stolzi@sebastian-stolzenberg.de> */
8 /* Funded by OCERA and FRESCOR IST projects */
9 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
10 /* and Ake Hedman, eurosource <akhe@eurosource.se> */
12 /* LinCAN is free software; you can redistribute it and/or modify it */
13 /* under terms of the GNU General Public License as published by the */
14 /* Free Software Foundation; either version 2, or (at your option) any */
15 /* later version. LinCAN is distributed in the hope that it will be */
16 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
17 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
18 /* General Public License for more details. You should have received a */
19 /* copy of the GNU General Public License along with LinCAN; see file */
20 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
21 /* Cambridge, MA 02139, USA. */
23 /* To allow use of LinCAN in the compact embedded systems firmware */
24 /* and RT-executives (RTEMS for example), main authors agree with next */
25 /* special exception: */
27 /* Including LinCAN header files in a file, instantiating LinCAN generics */
28 /* or templates, or linking other files with LinCAN objects to produce */
29 /* an application image/executable, does not by itself cause the */
30 /* resulting application image/executable to be covered by */
31 /* the GNU General Public License. */
32 /* This exception does not however invalidate any other reasons */
33 /* why the executable file might be covered by the GNU Public License. */
34 /* Publication of enhanced or derived LinCAN files is required although. */
35 /**************************************************************************/
37 #include <linux/delay.h>
39 #include "../include/can.h"
40 #include "../include/can_sysdep.h"
41 #include "../include/main.h"
42 #include "../include/c_can.h"
43 #include "../include/hms30c7202_can.h"
46 * IO_RANGE is the io-memory range that gets reserved, please adjust according
47 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
48 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
50 #define IO_RANGE 0x17E
53 * hms30c7202_request_io: - reserve io or memory range for can board
54 * @candev: pointer to candevice/board which asks for io. Field @io_addr
55 * of @candev is used in most cases to define start of the range
57 * The function hms30c7202_request_io() is used to reserve the io-memory. If your
58 * hardware uses a dedicated memory range as hardware control registers you
59 * will have to add the code to reserve this memory as well.
60 * %IO_RANGE is the io-memory range that gets reserved, please adjust according
61 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
62 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
63 * Return Value: The function returns zero on success or %-ENODEV on failure
64 * File: src/template.c
66 int hms30c7202_request_io(struct candevice_t *candev)
68 DEBUGMSG("(c%d)calling hms30c7202_request_io(...)\n", candev->chip[0]->chip_idx);
70 if(!can_request_mem_region(candev->io_addr, IO_RANGE, DEVICE_NAME )) {
71 CANMSG("hmsc30c7202_can failed to request mem region %lx.\n",
72 (unsigned long)candev->io_addr );
75 if (!( candev->dev_base_addr = ioremap( candev->io_addr, IO_RANGE ))) {
76 DEBUGMSG( "Failed to map IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
77 (unsigned long)candev->io_addr,
78 (unsigned long)candev->io_addr + IO_RANGE - 1,
79 (unsigned long)candev->dev_base_addr);
80 can_release_mem_region(candev->io_addr, IO_RANGE);
84 DEBUGMSG( "Mapped IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
85 (unsigned long)candev->io_addr,
86 (unsigned long)candev->io_addr + IO_RANGE - 1,
87 (unsigned long)candev->dev_base_addr);
91 candev->chip[0]->chip_base_addr=candev->dev_base_addr;
93 //pchip->write_register(0, pchip->vbase_addr + CCCR);
94 //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n",
95 // (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR)));
96 candev->chip[0]->chipspecops->start_chip(candev->chip[0]);
97 //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n",
98 // (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR)));
100 //DEBUGMSG("hms30c7202_can request i/o, leaving.\n");
106 * hms30c7202_release_io - free reserved io memory range
107 * @candev: pointer to candevice/board which releases io
109 * The function hms30c7202_release_io() is used to free reserved io-memory.
110 * In case you have reserved more io memory, don't forget to free it here.
111 * IO_RANGE is the io-memory range that gets released, please adjust according
112 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
113 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
114 * Return Value: The function always returns zero
115 * File: src/template.c
117 int hms30c7202_release_io(struct candevice_t *candev)
121 //disable IRQ generation
122 tempReg = c_can_read_reg_w(candev->chip[0], CCCR);
124 c_can_config_irqs(candev->chip[0], 0);
126 /* // clear all message objects
127 for (i=1; i<=15; i++) {
128 ccscan_write_register(
135 ccscan_write_register(
145 // power down HMS30c7202 - C_CAN
146 candev->chip[0]->chipspecops->stop_chip(candev->chip[0]);
148 // release I/O memory mapping
149 iounmap(candev->dev_base_addr);
151 // Release the memory region
152 can_release_mem_region(candev->io_addr, IO_RANGE);
158 * hms30c7202_reset - hardware reset routine
159 * @card: Number of the hardware card.
161 * The function hms30c7202_reset() is used to give a hardware reset. This is
162 * rather hardware specific so I haven't included example code. Don't forget to
163 * check the reset status of the chip before returning.
164 * Return Value: The function returns zero on success or %-ENODEV on failure
165 * File: src/template.c
167 int hms30c7202_reset( struct candevice_t *candev)
170 int enableTest=0, disableTest=0;
171 struct canchip_t *pchip = candev->chip[0];
173 enableTest = pchip->chipspecops->enable_configuration(pchip);
174 disableTest = pchip->chipspecops->disable_configuration(pchip);
175 if( enableTest || disableTest) {
176 CANMSG("Reset status timeout!\n");
177 CANMSG("Please check your hardware.\n");
181 /* Check busoff status */
183 while ( (c_can_read_reg_w(pchip, CCSR) & SR_BOFF) && (i<=15)) {
188 CANMSG("Reset status timeout!\n");
189 CANMSG("Please check your hardware.\n");
193 DEBUGMSG("Chip0 reset status ok.\n");
195 //pchip->config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE);
199 #define RESET_ADDR 0x0
204 * hms30c7202_init_hw_data - Initialize hardware cards
205 * @candev: Pointer to candevice/board structure
207 * The function hms30c7202_init_hw_data() is used to initialize the hardware
208 * structure containing information about the installed CAN-board.
209 * %RESET_ADDR represents the io-address of the hardware reset register.
210 * %NR_82527 represents the number of intel 82527 chips on the board.
211 * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
212 * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
213 * the hardware uses programmable interrupts.
214 * Return Value: The function always returns zero
215 * File: src/template.c
217 int hms30c7202_init_hw_data(struct candevice_t *candev)
218 /*( struct canchip_t *pchip, u16 chip_nr, u16 startminor, u32 baseaddr, u8 irq )*/
220 // u32 intCntrVAddr = 0;
221 can_ioptr_t gpioVAddr = 0;
223 u32 baseaddr=candev->io_addr;
225 // if ( (!( intCntrVAddr = ioremap( 0x80024000, 0xCD ) ))
226 // & (! ( gpioVAddr = ioremap( 0x80023000, 0xAD ) ))) {
227 // DEBUGMSG("Failed to map Int and GPIO memory\n");
230 if ( ! ( gpioVAddr = ioremap( 0x80023000, 0xAD ) )) {
231 DEBUGMSG("Failed to map GPIO memory\n");
235 // DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
236 // (unsigned long)0X80024000,
237 // (unsigned long)0X800240CC,
238 // (unsigned long)intCntrVAddr);
239 DEBUGMSG( "Mapped GPIO IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
240 (unsigned long)0X80023000,
241 (unsigned long)0X800240AC,
242 (unsigned long)gpioVAddr);
245 if (baseaddr == 0x8002f000) {
246 // tempReg = can_readl(intCntrVAddr);
247 // DEBUGMSG("Read Interrupt Enable Register : 0x%.4lx\n",(long)tempReg);
248 // DEBUGMSG("Trying to activate CAN0 Interrupt (Bit 18)\n");
249 // can_writel((tempReg | (1<<18)), intCntrVAddr);
250 // tempReg = can_readl(intCntrVAddr);
251 // DEBUGMSG("Read changed Interrupt Enable Register : 0x%.4lx\n",(long)tempReg);
252 tempReg = can_readl(gpioVAddr + 0x5C);
253 DEBUGMSG("Read GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg);
254 DEBUGMSG("Trying to activate CAN0 (Bit 1 = 0 for CANTx0, Bit 2 = 0 for CANRx0,)\n");
255 can_writel(tempReg & ~0x6, gpioVAddr + 0x5C);
256 tempReg = can_readl(gpioVAddr + 0x5C);
257 DEBUGMSG("Read changed GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg);
258 tempReg = can_readl(gpioVAddr + 0x44);
259 DEBUGMSG("Read GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg);
260 DEBUGMSG("Trying to set CAN0 directions (Bit 1 = 0 for CANTx0 as OUT, Bit 2 = 1 for CANRx0 as IN,)\n");
261 can_writel((tempReg & ~0x2) | 0x4, gpioVAddr + 0x44);
262 tempReg = can_readl(gpioVAddr + 0x44);
263 DEBUGMSG("Read changed GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg);
265 else if (baseaddr == 0x80030000) {
266 // tempReg = can_readl(intCntrVAddr);
267 // can_writel((tempReg | (1<<19)), intCntrVAddr);
268 tempReg = can_readl(gpioVAddr + 0x9C);
269 DEBUGMSG("Read GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg);
270 DEBUGMSG("Trying to activate CAN1 (Bit 22 = 0 for CANRx1, Bit 23 = 0 for CANTx1,)\n");
271 can_writel(tempReg & 0xFF3FFFFF, gpioVAddr + 0x9C);
272 tempReg = can_readl(gpioVAddr + 0x9C);
273 DEBUGMSG("Read changed GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg);
274 tempReg = can_readl(gpioVAddr + 0x84);
275 DEBUGMSG("Read GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg);
276 DEBUGMSG("Trying to set CAN1 directions (Bit 22 = 1 for CANRx1 as IN, Bit 23 = 0 for CANTx1 as OUT,)\n");
277 can_writel((tempReg & ~(1<<23)) | 1<<22, gpioVAddr + 0x84);
278 tempReg = can_readl(gpioVAddr + 0x84);
279 DEBUGMSG("Read changed GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg);
282 //DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n",
283 // (long)can_readl(intCntrVAddr + 4));
284 //DEBUGMSG("Current Interrupt ID: %d\n",
285 // (int)(can_readl(intCntrVAddr + 0x90) & 0xF));
286 // iounmap( (void*)intCntrVAddr);
287 iounmap( gpioVAddr );
288 // DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n",
289 // (unsigned long)intCntrVAddr);
290 DEBUGMSG( "Unmapped GPIO IO-memory: 0x%lx\n",
291 (unsigned long)gpioVAddr);
293 // Initialize chip data ( only one chip )
294 // pcandev->pchip[ 0 ]->powner = pcandev;
295 /*pchip->ntype = CAN_CHIPTYPE_C_CAN;*/
297 candev->nr_82527_chips=0;
298 candev->nr_sja1000_chips=0;
299 candev->nr_all_chips=NR_C_CAN;
305 #define CHIP_TYPE "c_can"
307 * hms30c7202_init_chip_data - Initialize chips
308 * @candev: Pointer to candevice/board structure
309 * @chipnr: Number of the CAN chip on the hardware card
311 * The function hms30c7202_init_chip_data() is used to initialize the hardware
312 * structure containing information about the CAN chips.
313 * %CHIP_TYPE represents the type of CAN chip.
314 * The @chip_base_addr entry represents the start of the 'official' memory map
315 * of the installed chip. It's likely that this is the same as the @io_addr
316 * argument supplied at module loading time.
317 * The @clock entry holds the chip clock value in Hz.
318 * File: src/template.c
320 int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr)
322 // Register chip operations
323 c_can_fill_chipspecops(candev->chip[chipnr]);
324 /* override chip provided default value */
325 candev->chip[chipnr]->max_objects = NR_MSGOBJ;
327 candev->chip[chipnr]->chip_base_addr=candev->io_addr;
329 candev->chip[chipnr]->clock = 16000000/2;
331 /*candev->chip[chipnr]->int_clk_reg = 0x0;
332 candev->chip[chipnr]->int_bus_reg = 0x0;
333 candev->chip[chipnr]->sja_cdr_reg = 0x0;
334 candev->chip[chipnr]->sja_ocr_reg = 0x0;*/
342 * hms30c7202_init_obj_data - Initialize message buffers
343 * @chip: Pointer to chip specific structure
344 * @objnr: Number of the message buffer
346 * The function hms30c7202_init_obj_data() is used to initialize the hardware
347 * structure containing information about the different message objects on the
349 * The entry @obj_base_addr represents the first memory address of the message
351 * Unless the hardware uses a segmented memory map, flags can be set zero.
352 * Return Value: The function always returns zero
353 * File: src/template.c
355 int hms30c7202_init_obj_data(struct canchip_t *chip, int objnr)
358 DEBUGMSG("(c%d)calling hms30c7202_init_obj_data( ...)\n", chip->chip_idx);
360 /* It seems, that there is no purpose to setup object base address */
361 chip->msgobj[objnr]->obj_base_addr=0;
363 /*can_msgobj_test_fl(pmsgobj,RX_MODE_EXT);*/
368 * hms30c7202_write_register - Low level write register routine
369 * @data: data to be written
370 * @address: memory address to write to
372 * The function hms30c7202_write_register() is used to write to hardware registers
373 * on the CAN chip. The registers are mapped on 32 bit bus on hms30c7202
374 * and thus registers span is twice as one defined by C_CAN manual and defines.
375 * This function compensates this difference.
376 * Return Value: The function does not return a value
377 * File: src/template.c
380 void hms30c7202_write_register(unsigned data, can_ioptr_t address)
382 unsigned long addr=can_ioptr2ulong(address);
384 //unsigned long usecs = 1;
386 address = can_ulong2ioptr(((addr & C_CAN_REGOFFS_MASK) << 1) |
387 (addr & ~C_CAN_REGOFFS_MASK));
389 //DEBUGMSG("Trying to write 0x%u16x to address 0x%lx\n",data,address);
391 can_writew(data,address);
397 * hms30c7202_read_register - Low level read register routine
398 * @address: memory address to read from
400 * The function hms30c7202_read_register() is used to read from hardware registers
401 * on the CAN chip. The registers are mapped on 32 bit bus on hms30c7202
402 * and thus registers span is twice as one defined by C_CAN manual and defines.
403 * This function compensates this difference.
404 * Return Value: The function returns the value stored in @address
405 * File: src/template.c
407 unsigned hms30c7202_read_register(can_ioptr_t address)
409 unsigned long addr=can_ioptr2ulong(address);
412 address = can_ulong2ioptr(((addr & C_CAN_REGOFFS_MASK) << 1) |
413 (addr & ~C_CAN_REGOFFS_MASK));
415 //DEBUGMSG("Trying to read from address 0x%lx :",address);
417 value = can_readw(address);
420 value = can_readw(address);
424 //DEBUGMSG("0x%u16x\n",value);
430 * hms30c7202_program_irq - program interrupts
431 * @candev: Pointer to candevice/board structure
433 * The function hms30c7202_program_irq() is used for hardware that uses
434 * programmable interrupts. If your hardware doesn't use programmable interrupts
435 * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
436 * leave this function unedited. Again this function is hardware specific so
437 * there's no example code.
438 * Return value: The function returns zero on success or %-ENODEV on failure
439 * File: src/template.c
441 int hms30c7202_program_irq(struct candevice_t *candev)
446 int hms30c7202_register(struct hwspecops_t *hwspecops)
448 hwspecops->request_io = hms30c7202_request_io;
449 hwspecops->release_io = hms30c7202_release_io;
450 hwspecops->reset = hms30c7202_reset;
451 hwspecops->init_hw_data = hms30c7202_init_hw_data;
452 hwspecops->init_chip_data = hms30c7202_init_chip_data;
453 hwspecops->init_obj_data = hms30c7202_init_obj_data;
454 hwspecops->write_register = hms30c7202_write_register;
455 hwspecops->read_register = hms30c7202_read_register;
456 hwspecops->program_irq = hms30c7202_program_irq;