Changed data size from byte to unsigned for write_register indirect call
[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 = c_can_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 ( (c_can_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         return 0;
277 }
278
279
280 #define CHIP_TYPE "c_can"
281 /**
282  * hms30c7202_init_chip_data - Initialize chips
283  * @candev: Pointer to candevice/board structure
284  * @chipnr: Number of the CAN chip on the hardware card
285  *
286  * The function hms30c7202_init_chip_data() is used to initialize the hardware
287  * structure containing information about the CAN chips.
288  * %CHIP_TYPE represents the type of CAN chip.
289  * The @chip_base_addr entry represents the start of the 'official' memory map
290  * of the installed chip. It's likely that this is the same as the @io_addr
291  * argument supplied at module loading time.
292  * The @clock entry holds the chip clock value in Hz.
293  * File: src/template.c
294  */
295 int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr)
296 {
297         candev->chip[chipnr]->chip_type=CHIP_TYPE;
298         candev->chip[chipnr]->chip_base_addr=candev->io_addr;
299         
300         candev->chip[chipnr]->clock = 16000000;
301         
302         candev->chip[chipnr]->max_objects = NR_MSGOBJ;
303         
304         /*candev->chip[chipnr]->int_clk_reg = 0x0;
305         candev->chip[chipnr]->int_bus_reg = 0x0;
306         candev->chip[chipnr]->sja_cdr_reg = 0x0;
307         candev->chip[chipnr]->sja_ocr_reg = 0x0;*/
308         
309         // Register chip operations
310         c_can_register(candev->chip[chipnr]->chipspecops);
311
312         return 0;
313 }
314
315
316 /**
317  * hms30c7202_init_obj_data - Initialize message buffers
318  * @chip: Pointer to chip specific structure
319  * @objnr: Number of the message buffer
320  *
321  * The function hms30c7202_init_obj_data() is used to initialize the hardware
322  * structure containing information about the different message objects on the
323  * CAN chip. 
324  * The entry @obj_base_addr represents the first memory address of the message 
325  * object. 
326  * Unless the hardware uses a segmented memory map, flags can be set zero.
327  * Return Value: The function always returns zero
328  * File: src/template.c
329  */
330 int hms30c7202_init_obj_data(struct chip_t *chip, int objnr)
331 {
332
333         DEBUGMSG("(c%d)calling hms30c7202_init_obj_data( ...)\n", pchip->chip_nr);
334
335         /* It seems, that there is no purpose to setup object base address */
336         chip->msgobj[objnr]->obj_base_addr=0;
337         
338         /*can_msgobj_test_fl(pmsgobj,RX_MODE_EXT);*/
339         return 0;
340 }
341
342 /**
343  * hms30c7202_write_register - Low level write register routine
344  * @data: data to be written
345  * @address: memory address to write to
346  *
347  * The function hms30c7202_write_register() is used to write to hardware registers
348  * on the CAN chip. You should only have to edit this function if your hardware
349  * uses some specific write process.
350  * Return Value: The function does not return a value
351  * File: src/template.c
352  */
353
354 void hms30c7202_write_register(unsigned data, unsigned long address)
355 {
356         int i;
357         //unsigned long usecs = 1;
358         
359         //DEBUGMSG("Trying to write 0x%u16x to address 0x%lx\n",data,address);
360         
361         writew(data,address);
362         //udelay( usecs );
363         for (i=0; i<5; i++);
364 }
365
366 /**
367  * hms30c7202_read_register - Low level read register routine
368  * @address: memory address to read from
369  *
370  * The function hms30c7202_read_register() is used to read from hardware registers
371  * on the CAN chip. You should only have to edit this function if your hardware
372  * uses some specific read process.
373  * Return Value: The function returns the value stored in @address
374  * File: src/template.c
375  */
376 unsigned hms30c7202_read_register(unsigned long address)
377 {
378         u16 value, i;
379         
380         //DEBUGMSG("Trying to read from address 0x%lx :",address);
381         
382         value = readw(address);
383         //udelay( usecs );
384         for (i=0;i<5;i++);
385         value = readw(address);
386                 //udelay( usecs );
387         for (i=0;i<5;i++);
388         
389         //DEBUGMSG("0x%u16x\n",value);
390         return value;
391
392 }
393
394 /**
395  * hms30c7202_program_irq - program interrupts
396  * @candev: Pointer to candevice/board structure
397  *
398  * The function hms30c7202_program_irq() is used for hardware that uses 
399  * programmable interrupts. If your hardware doesn't use programmable interrupts
400  * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
401  * leave this function unedited. Again this function is hardware specific so 
402  * there's no example code.
403  * Return value: The function returns zero on success or %-ENODEV on failure
404  * File: src/template.c
405  */
406 int hms30c7202_program_irq(struct candevice_t *candev)
407 {
408         return 0;
409 }
410
411 int hms30c7202_register(struct hwspecops_t *hwspecops)
412 {
413         hwspecops->request_io = hms30c7202_request_io;
414         hwspecops->release_io = hms30c7202_release_io;
415         hwspecops->reset = hms30c7202_reset;
416         hwspecops->init_hw_data = hms30c7202_init_hw_data;
417         hwspecops->init_chip_data = hms30c7202_init_chip_data;
418         hwspecops->init_obj_data = hms30c7202_init_obj_data;
419         hwspecops->write_register = hms30c7202_write_register;
420         hwspecops->read_register = hms30c7202_read_register;
421         hwspecops->program_irq = hms30c7202_program_irq;
422         return 0;
423 }
424