]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/hms30c7202_can.c
The first phase of integration of Hynix HMS30c7202 C_CAN support
[lincan.git] / lincan / src / hms30c7202_can.c
1 /* hms30c7202_can.c - Hynix HMS30c7202 ARM device specific code
2  * Linux CAN-bus device driver.
3  * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de
4  * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl
5  * and Ake Hedman, eurosource, akhe@eurosource.se
6  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
7  * email:pisa@cmp.felk.cvut.cz
8  * This software is released under the GPL-License.
9  * Version lincan-0.2  9 Jul 2003
10  */
11
12 #include <linux/delay.h>
13
14 #include "../include/can.h"
15 #include "../include/can_sysdep.h"
16 #include "../include/main.h"
17 #include "../include/c_can.h"
18 #include "../include/hms30c7202_can.h"
19
20 /*
21  * IO_RANGE is the io-memory range that gets reserved, please adjust according
22  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
23  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
24  */
25 #define IO_RANGE 0x17E
26
27 /**
28  * hms30c7202_request_io: - reserve io or memory range for can board
29  * @candev: pointer to candevice/board which asks for io. Field @io_addr
30  *      of @candev is used in most cases to define start of the range
31  *
32  * The function hms30c7202_request_io() is used to reserve the io-memory. If your
33  * hardware uses a dedicated memory range as hardware control registers you
34  * will have to add the code to reserve this memory as well. 
35  * %IO_RANGE is the io-memory range that gets reserved, please adjust according
36  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
37  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
38  * Return Value: The function returns zero on success or %-ENODEV on failure
39  * File: src/template.c
40  */
41 int hms30c7202_request_io(struct candevice_t *candev)
42 {
43         DEBUGMSG("(c%d)calling hms30c7202_request_io(...)\n", pchip->chip_nr);
44
45         if(!can_request_mem_region(candev->io_addr, IO_RANGE, DEVICE_NAME )) {
46                 CANMSG("hmsc30c7202_can failed to request mem region %lx.\n",
47                 (unsigned long)candev->io_addr );
48         }
49         
50         if (!( candev->dev_base_addr = (long)ioremap( candev->io_addr, IO_RANGE ))) {
51                 DEBUGMSG( "Failed to map IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
52                         (unsigned long)candev->io_addr,
53                         (unsigned long)candev->io_addr + IO_RANGE - 1,
54                         (unsigned long)candev->dev_base_addr);
55                 can_release_mem_region(candev->io_addr, IO_RANGE);
56                 return -ENODEV;
57         } else {
58         
59                 DEBUGMSG( "Mapped IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
60                         (unsigned long)candev->io_addr,
61                         (unsigned long)candev->io_addr + IO_RANGE - 1,
62                         (unsigned long)candev->dev_base_addr);
63         
64         }
65         
66         candev->chip[0]->chip_base_addr=candev->dev_base_addr;
67         
68         //pchip->write_register(0, pchip->vbase_addr + CCCR);
69         //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n",
70         //      (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR)));
71         candev->chip[0]->chipspecops->start_chip(candev->chip[0]);
72         //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n",
73         //      (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR)));
74         
75         //DEBUGMSG("hms30c7202_can request i/o, leaving.\n");
76         return 0;
77 }
78
79
80 /**
81  * hms30c7202_release_io - free reserved io memory range
82  * @candev: pointer to candevice/board which releases io
83  *
84  * The function hms30c7202_release_io() is used to free reserved io-memory.
85  * In case you have reserved more io memory, don't forget to free it here.
86  * IO_RANGE is the io-memory range that gets released, please adjust according
87  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
88  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
89  * Return Value: The function always returns zero
90  * File: src/template.c
91  */
92 int hms30c7202_release_io(struct candevice_t *candev)
93 {
94         u16 tempReg;
95         
96         //disable IRQ generation
97         tempReg = hms30c7202_read_reg_w(candev->chip[0], CCCR);
98
99         c_can_config_irqs(candev->chip[0], 0);
100         
101         /*  // clear all message objects
102         for (i=1; i<=15; i++) {
103         ccscan_write_register(
104                         INTPD_RES |
105                         RXIE_RES |
106                         TXIE_RES |
107                         MVAL_RES,
108                         pchip->vbase_addr +
109                         i*0x10 + iMSGCTL0 );
110         ccscan_write_register(
111                         NEWD_RES |
112                         MLST_RES |
113                         CPUU_RES |
114                         TXRQ_RES |
115                         RMPD_RES,
116                         pchip->vbase_addr +
117                         i*0x10 + iMSGCTL1 );
118         }
119         */
120         // power down HMS30c7202 - C_CAN
121         candev->chip[0]->chipspecops->stop_chip(candev->chip[0]);
122         
123         // release I/O memory mapping
124         iounmap((void*)candev->dev_base_addr);
125         
126         // Release the memory region
127         can_release_mem_region(candev->io_addr, IO_RANGE);
128         
129         return 0;
130 }
131
132 /**
133  * hms30c7202_reset - hardware reset routine
134  * @card: Number of the hardware card.
135  *
136  * The function hms30c7202_reset() is used to give a hardware reset. This is
137  * rather hardware specific so I haven't included example code. Don't forget to
138  * check the reset status of the chip before returning.
139  * Return Value: The function returns zero on success or %-ENODEV on failure
140  * File: src/template.c
141  */
142 int hms30c7202_reset(  struct candevice_t *candev)
143 {
144         int i=0;
145         int enableTest=0, disableTest=0;
146         struct chip_t *pchip = candev->chip[0];
147         
148         enableTest = pchip->chipspecops->enable_configuration(pchip);
149         disableTest = pchip->chipspecops->disable_configuration(pchip);
150         if( enableTest || disableTest) {
151                 CANMSG("Reset status timeout!\n");
152                 CANMSG("Please check your hardware.\n");
153                 return -ENODEV;
154         }
155         
156         /* Check busoff status */
157         
158         while ( (hms30c7202_read_reg_w(pchip, CCSR) & SR_BOFF) && (i<=15)) {
159                 udelay(20000);
160                 i++;
161         }
162         if (i>=15) {
163                 CANMSG("Reset status timeout!\n");
164                 CANMSG("Please check your hardware.\n");
165                 return -ENODEV;
166         }
167         else
168                 DEBUGMSG("Chip0 reset status ok.\n");
169         
170         //pchip->config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE);
171         return 0;
172 }
173
174 #define RESET_ADDR 0x0
175 #define NR_C_CAN 1
176 #define NR_MSGOBJ 32
177
178 /**
179  * hms30c7202_init_hw_data - Initialize hardware cards
180  * @candev: Pointer to candevice/board structure
181  *
182  * The function hms30c7202_init_hw_data() is used to initialize the hardware
183  * structure containing information about the installed CAN-board.
184  * %RESET_ADDR represents the io-address of the hardware reset register.
185  * %NR_82527 represents the number of intel 82527 chips on the board.
186  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
187  * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
188  * the hardware uses programmable interrupts.
189  * Return Value: The function always returns zero
190  * File: src/template.c
191  */
192 int hms30c7202_init_hw_data(struct candevice_t *candev) 
193 /*( struct chip_t *pchip, u16 chip_nr, u16 startminor, u32 baseaddr, u8 irq )*/
194 {
195         //      u32 intCntrVAddr = 0;
196         u32 gpioVAddr = 0;
197         u32 tempReg = 0;
198         u32 baseaddr=candev->io_addr;
199         
200         //      if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) ))
201         //              & (! ( gpioVAddr = (u32)ioremap( 0x80023000, 0xAD ) ))) {
202         //              DEBUGMSG("Failed to map Int and GPIO memory\n");
203         //              return -EIO;
204         //      }
205         if ( ! ( gpioVAddr = (u32)ioremap( 0x80023000, 0xAD ) )) {
206                 DEBUGMSG("Failed to map GPIO memory\n");
207                 return -EIO;
208         } else {
209         
210                 //   DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
211                 //            (unsigned long)0X80024000,
212                 //            (unsigned long)0X800240CC,
213                 //            (unsigned long)intCntrVAddr);
214                 DEBUGMSG( "Mapped GPIO IO-memory: 0x%lx - 0x%lx to 0x%lx\n",
215                         (unsigned long)0X80023000,
216                         (unsigned long)0X800240AC,
217                         (unsigned long)gpioVAddr);
218         }
219         
220         if (baseaddr == 0x8002f000) {
221                 //              tempReg = readl(intCntrVAddr);
222                 //              DEBUGMSG("Read Interrupt Enable Register : 0x%.4lx\n",(long)tempReg);
223                 //              DEBUGMSG("Trying to activate CAN0 Interrupt (Bit 18)\n");
224                 //              writel((tempReg | (1<<18)), intCntrVAddr);
225                 //              tempReg = readl(intCntrVAddr);
226                 //              DEBUGMSG("Read changed Interrupt Enable Register : 0x%.4lx\n",(long)tempReg);
227                 tempReg = readl(gpioVAddr + 0x5C);
228                 DEBUGMSG("Read GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg);
229                 DEBUGMSG("Trying to activate CAN0 (Bit 1 = 0 for CANTx0, Bit 2 = 0 for CANRx0,)\n");
230                 writel(tempReg & ~0x6, gpioVAddr + 0x5C);
231                 tempReg = readl(gpioVAddr + 0x5C);
232                 DEBUGMSG("Read changed GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg);
233                 tempReg = readl(gpioVAddr + 0x44);
234                 DEBUGMSG("Read GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg);
235                 DEBUGMSG("Trying to set CAN0 directions (Bit 1 = 0 for CANTx0 as OUT, Bit 2 = 1 for CANRx0 as IN,)\n");
236                 writel((tempReg & ~0x2) | 0x4, gpioVAddr + 0x44);
237                 tempReg = readl(gpioVAddr + 0x44);
238                 DEBUGMSG("Read changed GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg);
239         }
240         else if (baseaddr == 0x80030000) {
241                 //              tempReg = readl(intCntrVAddr);
242                 //              writel((tempReg | (1<<19)), intCntrVAddr);
243                 tempReg = readl(gpioVAddr + 0x9C);
244                 DEBUGMSG("Read GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg);
245                 DEBUGMSG("Trying to activate CAN1 (Bit 22 = 0 for CANRx1, Bit 23 = 0 for CANTx1,)\n");
246                 writel(tempReg & 0xFF3FFFFF, gpioVAddr + 0x9C);
247                 tempReg = readl(gpioVAddr + 0x9C);
248                 DEBUGMSG("Read changed GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg);
249                 tempReg = readl(gpioVAddr + 0x84);
250                 DEBUGMSG("Read GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg);
251                 DEBUGMSG("Trying to set CAN1 directions (Bit 22 = 1 for CANRx1 as IN, Bit 23 = 0 for CANTx1 as OUT,)\n");
252                 writel((tempReg & ~(1<<23)) | 1<<22, gpioVAddr + 0x84);
253                 tempReg = readl(gpioVAddr + 0x84);
254                 DEBUGMSG("Read changed GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg);
255         }
256
257         //DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n",
258         //                      (long)readl(intCntrVAddr + 4));
259         //DEBUGMSG("Current Interrupt ID: %d\n",
260         //                      (int)(readl(intCntrVAddr + 0x90) & 0xF));
261         //      iounmap( (void*)intCntrVAddr);
262         iounmap( (void*)gpioVAddr );
263         //      DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n",
264         //            (unsigned long)intCntrVAddr);
265         DEBUGMSG( "Unmapped GPIO IO-memory: 0x%lx\n",
266                 (unsigned long)gpioVAddr);
267
268         // Initialize chip data ( only one chip )
269         //  pcandev->pchip[ 0 ]->powner = pcandev;
270         /*pchip->ntype = CAN_CHIPTYPE_C_CAN;*/
271         
272         candev->nr_82527_chips=0;
273         candev->nr_sja1000_chips=0;
274         candev->nr_all_chips=NR_C_CAN;
275
276         // Register hardware operations
277         candev->hwspecops->request_io = hms30c7202_request_io;
278         candev->hwspecops->release_io = hms30c7202_release_io;
279         candev->hwspecops->reset = hms30c7202_reset;
280         /* private register read and write routines used */
281         candev->hwspecops->write_register = NULL; /*hms30c7202_write_register;*/
282         candev->hwspecops->read_register = NULL; /*hms30c7202_read_register;*/
283
284         return 0;
285 }
286
287
288 #define CHIP_TYPE "c_can"
289 /**
290  * hms30c7202_init_chip_data - Initialize chips
291  * @candev: Pointer to candevice/board structure
292  * @chipnr: Number of the CAN chip on the hardware card
293  *
294  * The function hms30c7202_init_chip_data() is used to initialize the hardware
295  * structure containing information about the CAN chips.
296  * %CHIP_TYPE represents the type of CAN chip.
297  * The @chip_base_addr entry represents the start of the 'official' memory map
298  * of the installed chip. It's likely that this is the same as the @io_addr
299  * argument supplied at module loading time.
300  * The @clock entry holds the chip clock value in Hz.
301  * File: src/template.c
302  */
303 int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr)
304 {
305         candev->chip[chipnr]->chip_type=CHIP_TYPE;
306         candev->chip[chipnr]->chip_base_addr=candev->io_addr;
307         
308         candev->chip[chipnr]->clock = 16000000;
309         
310         candev->chip[chipnr]->max_objects = NR_MSGOBJ;
311         
312         /*candev->chip[chipnr]->int_clk_reg = 0x0;
313         candev->chip[chipnr]->int_bus_reg = 0x0;
314         candev->chip[chipnr]->sja_cdr_reg = 0x0;
315         candev->chip[chipnr]->sja_ocr_reg = 0x0;*/
316         
317         // Register chip operations
318         c_can_register(candev->chip[chipnr]->chipspecops);
319
320         return 0;
321 }
322
323
324 /**
325  * hms30c7202_init_obj_data - Initialize message buffers
326  * @chip: Pointer to chip specific structure
327  * @objnr: Number of the message buffer
328  *
329  * The function hms30c7202_init_obj_data() is used to initialize the hardware
330  * structure containing information about the different message objects on the
331  * CAN chip. 
332  * The entry @obj_base_addr represents the first memory address of the message 
333  * object. 
334  * Unless the hardware uses a segmented memory map, flags can be set zero.
335  * Return Value: The function always returns zero
336  * File: src/template.c
337  */
338 int hms30c7202_init_obj_data(struct chip_t *chip, int objnr)
339 {
340
341         DEBUGMSG("(c%d)calling hms30c7202_init_obj_data( ...)\n", pchip->chip_nr);
342
343         /* It seems, that there is no purpose to setup object base address */
344         chip->msgobj[objnr]->obj_base_addr=0;
345         
346         /*can_msgobj_test_fl(pmsgobj,RX_MODE_EXT);*/
347         return 0;
348 }
349
350 /**
351  * hms30c7202_write_register - Low level write register routine
352  * @data: data to be written
353  * @address: memory address to write to
354  *
355  * The function hms30c7202_write_register() is used to write to hardware registers
356  * on the CAN chip. You should only have to edit this function if your hardware
357  * uses some specific write process.
358  * Return Value: The function does not return a value
359  * File: src/template.c
360  */
361
362 void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg)
363 {
364    int i;
365    u32 address = pchip->chip_base_addr + reg;
366         //unsigned long usecs = 1;
367
368    //DEBUGMSG("Trying to write 0x%u16x to address 0x%lx\n",data,address);
369
370    writew(data,address);
371         //udelay( usecs );
372    for (i=0; i<5; i++);
373 }
374
375 /**
376  * hms30c7202_read_register - Low level read register routine
377  * @address: memory address to read from
378  *
379  * The function hms30c7202_read_register() is used to read from hardware registers
380  * on the CAN chip. You should only have to edit this function if your hardware
381  * uses some specific read process.
382  * Return Value: The function returns the value stored in @address
383  * File: src/template.c
384  */
385 u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg)
386 {
387    u16 value, i;
388    u32 address = pchip->chip_base_addr + reg;
389         //unsigned long usecs = 1;
390
391    //DEBUGMSG("Trying to read from address 0x%lx :",address);
392
393    value = readw(address);
394    //udelay( usecs );
395    for (i=0;i<5;i++);
396    value = readw(address);
397         //udelay( usecs );
398    for (i=0;i<5;i++);
399
400    //DEBUGMSG("0x%u16x\n",value);
401    return value;
402
403 }
404
405 /**
406  * hms30c7202_program_irq - program interrupts
407  * @candev: Pointer to candevice/board structure
408  *
409  * The function hms30c7202_program_irq() is used for hardware that uses 
410  * programmable interrupts. If your hardware doesn't use programmable interrupts
411  * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
412  * leave this function unedited. Again this function is hardware specific so 
413  * there's no example code.
414  * Return value: The function returns zero on success or %-ENODEV on failure
415  * File: src/template.c
416  */
417 int hms30c7202_program_irq(struct candevice_t *candev)
418 {
419         return 0;
420 }
421
422 int hms30c7202_register(struct hwspecops_t *hwspecops)
423 {
424         hwspecops->request_io = hms30c7202_request_io;
425         hwspecops->release_io = hms30c7202_release_io;
426         hwspecops->reset = hms30c7202_reset;
427         hwspecops->init_hw_data = hms30c7202_init_hw_data;
428         hwspecops->init_chip_data = hms30c7202_init_chip_data;
429         hwspecops->init_obj_data = hms30c7202_init_obj_data;
430         /* private register read and write routines used */
431         hwspecops->write_register = NULL; /*hms30c7202_write_register;*/
432         hwspecops->read_register = NULL; /*hms30c7202_read_register;*/
433         hwspecops->program_irq = hms30c7202_program_irq;
434         return 0;
435 }
436