]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/ns_dev_can.c
Actual driver code for directly mapped SJA1000 into PCI mem region 0.
[lincan.git] / lincan / src / ns_dev_can.c
1 /**************************************************************************/
2 /* File: ns_dev_can.c - FPGA version of C_CAN ARM device specific         */
3 /* Ported to FS Forth-Systeme GmbH A9M9750DEVx development boardscode     */
4 /*                                                                        */
5 /* LinCAN - (Not only) Linux CAN bus driver                               */
6 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
7 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
8 /* Copyright (C) 2004 Sebastian Stolzenberg <stolzi@sebastian-stolzenberg.de> */
9 /* Copyright (C) 2005 Neil Bryan <nbryan@embebidos.com>                   */
10 /* Funded by OCERA and FRESCOR IST projects                               */
11 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
12 /* and Ake Hedman, eurosource <akhe@eurosource.se>                        */
13 /*                                                                        */
14 /* LinCAN is free software; you can redistribute it and/or modify it      */
15 /* under terms of the GNU General Public License as published by the      */
16 /* Free Software Foundation; either version 2, or (at your option) any    */
17 /* later version.  LinCAN is distributed in the hope that it will be      */
18 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
19 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
20 /* General Public License for more details. You should have received a    */
21 /* copy of the GNU General Public License along with LinCAN; see file     */
22 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
23 /* Cambridge, MA 02139, USA.                                              */
24 /*                                                                        */
25 /* To allow use of LinCAN in the compact embedded systems firmware        */
26 /* and RT-executives (RTEMS for example), main authors agree with next    */
27 /* special exception:                                                     */
28 /*                                                                        */
29 /* Including LinCAN header files in a file, instantiating LinCAN generics */
30 /* or templates, or linking other files with LinCAN objects to produce    */
31 /* an application image/executable, does not by itself cause the          */
32 /* resulting application image/executable to be covered by                */
33 /* the GNU General Public License.                                        */
34 /* This exception does not however invalidate any other reasons           */
35 /* why the executable file might be covered by the GNU Public License.    */
36 /* Publication of enhanced or derived LinCAN files is required although.  */
37 /**************************************************************************/
38
39 #include <linux/delay.h>
40
41 #include "../include/can.h"
42 #include "../include/can_sysdep.h"
43 #include "../include/main.h"
44 #include "../include/c_can.h"
45 #include "../include/ns_dev_can.h"
46
47 /*
48  * IO range for the C_CAN 1.2 memory map is 0x100 (256bytes)
49  */
50 #define IO_RANGE 0x100
51
52 /**
53  * ns_dev_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
56  *
57  */
58 int ns_dev_request_io(struct candevice_t *candev)
59 {
60         /* Note hard-coded index for the chip number as this
61          * only supports a single instance of the C_CAN controller.
62          */
63         DEBUGMSG("(c%d)ns_dev_request_io (...)\n", candev->chip[0]->chip_idx);
64
65         if (!can_request_mem_region(candev->io_addr, IO_RANGE, DEVICE_NAME)) {
66                 CANMSG("ns_dev failed to  mem region %lx.\n",
67                        (unsigned long)candev->io_addr);
68         }
69
70         if (!(candev->dev_base_addr = ioremap(candev->io_addr, IO_RANGE))) {
71                 DEBUGMSG
72                     ("Failed to map IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
73                      (unsigned long)candev->io_addr,
74                      (unsigned long)candev->io_addr + IO_RANGE - 1,
75                      (unsigned long)candev->dev_base_addr);
76                 can_release_mem_region(candev->io_addr, IO_RANGE);
77                 return -ENODEV;
78         } else {
79
80                 DEBUGMSG("Mapped IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n",
81                          (unsigned long)candev->io_addr,
82                          (unsigned long)candev->io_addr + IO_RANGE - 1,
83                          (unsigned long)candev->dev_base_addr);
84
85         }
86
87         candev->chip[0]->chip_base_addr = candev->dev_base_addr;
88         candev->chip[0]->chipspecops->start_chip(candev->chip[0]);
89
90         return 0;
91 }
92
93 /**
94  * ns_dev_release_io - free reserved io memory range
95  * @candev: pointer to candevice/board which releases io
96  *
97  * The function ns_dev_release_io() is used to free reserved io-memory.
98  * In case you have reserved more io memory, don't forget to free it here.
99  *
100  */
101 int ns_dev_release_io(struct candevice_t *candev)
102 {
103         DEBUGMSG("(c%d)ns_dev_release_io (...)\n", candev->chip[0]->chip_idx);
104
105         /* Release I/O memory mapping */
106         iounmap(candev->dev_base_addr);
107
108         /* Release the memory region */
109         can_release_mem_region(candev->io_addr, IO_RANGE);
110
111         return 0;
112 }
113
114 /**
115  * ns_dev_reset - hardware reset routine
116  * @card: Number of the hardware card.
117  *
118  * The function ns_dev_reset() is used to give a hardware reset. This is
119  * rather hardware specific so I haven't included example code. Don't forget to
120  * check the reset status of the chip before returning.
121  * Return Value: The function returns zero on success or %-ENODEV on failure
122  *
123  */
124 int ns_dev_reset(struct candevice_t *candev)
125 {
126         int i = 0;
127         int enableTest = 0;
128         int disableTest = 0;
129
130         struct canchip_t *pchip = candev->chip[0];
131
132         enableTest = pchip->chipspecops->enable_configuration(pchip);
133         disableTest = pchip->chipspecops->disable_configuration(pchip);
134
135         if (enableTest || disableTest) {
136                 CANMSG("Enable or Disable status failed!\n");
137                 CANMSG("Please check your hardware.\n");
138                 return -ENODEV;
139         }
140
141         /* Check busoff status */
142         while ((c_can_read_reg_w(pchip, CCSR) & SR_BOFF) && (i <= 15)) {
143                 udelay(2000);
144                 i++;
145         }
146
147         if (i >= 15) {
148                 CANMSG("Reset status timeout!\n");
149                 CANMSG("Please check your hardware.\n");
150                 return -ENODEV;
151         }
152         //pchip->config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE);
153         return 0;
154 }
155
156 #define RESET_ADDR 0x0
157 #define NR_C_CAN 1
158 #define NR_MSGOBJ 32
159
160 /**
161  * ns_dev_hw_data - Initialize hardware cards
162  * @candev: Pointer to candevice/board structure
163  *
164  * The function ns_dev_init_hw_data() is used to initialize the hardware
165  * structure containing information about the installed CAN-board.
166  * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
167  * the hardware uses programmable interrupts.
168  * Return Value: The function always returns zero
169  */
170 int ns_dev_init_hw_data(struct candevice_t *candev)
171 {
172         can_ioptr_t sys_contVA = NULL;
173
174         /* LUCAN : Magic numbers */
175         if (!(sys_contVA = ioremap(NS9750_PERIPHERAL_BASE_ADDRESS,
176                                          NS9750_PERIPHERAL_MAP_SIZE))) {
177                 DEBUGMSG("Failed to map FPGA memory\n");
178                 return -EIO;
179         } else {
180                 DEBUGMSG("Writing to NS9750 sys cont\n");
181                 can_writel((BUS_WIDTH_16BIT | ACTIVE_LOW_CHIP_SELECT),
182                        sys_contVA + NS9750_SYSTEM_CONTROLLER_OFFSET);
183         }
184
185         /* We have finished with this mapping */
186         iounmap(sys_contVA);
187
188         candev->nr_82527_chips = 0;
189         candev->nr_sja1000_chips = 0;
190         candev->nr_all_chips = NR_C_CAN;
191         candev->flags |= CANDEV_PROGRAMMABLE_IRQ;
192
193         return 0;
194 }
195
196 /**
197  * ns_dev_init_chip_data - Initialize chips
198  * @candev: Pointer to candevice/board structure
199  * @chipnr: Number of the CAN chip on the hardware card
200  *
201  * The function ns_dev_init_chip_data() is used to initialize the hardware
202  * structure containing information about the CAN chips.
203  * %CHIP_TYPE represents the type of CAN chip.
204  * The @chip_base_addr entry represents the start of the 'official' memory map
205  * of the installed chip. It's likely that this is the same as the @io_addr
206  * argument supplied at module loading time.
207  * The @clock entry holds the chip clock value in Hz.
208  * File: src/template.c
209  */
210 int ns_dev_init_chip_data(struct candevice_t *candev, int chipnr)
211 {
212         /* Register chip operations */
213         c_can_fill_chipspecops(candev->chip[chipnr]);
214
215         /* override chip provided default value */
216         candev->chip[chipnr]->max_objects = MAX_MSGOBJS;
217         candev->chip[chipnr]->chip_base_addr = candev->io_addr;
218         candev->chip[chipnr]->clock = C_CAN_CLOCK_INPUT_FREQUENCY;
219
220         return 0;
221 }
222
223 /**
224  * ns_dev_init_obj_data - Initialize message buffers
225  * @chip: Pointer to chip specific structure
226  * @objnr: Number of the message buffer
227  *
228  * The function ns_dev_init_obj_data() is used to initialize the hardware
229  * structure containing information about the different message objects on the
230  * CAN chip.
231  * The entry @obj_base_addr represents the first memory address of the message
232  * object.
233  * Unless the hardware uses a segmented memory map, flags can be set zero.
234  * Return Value: The function always returns zero
235  * File: src/template.c
236  */
237 int ns_dev_init_obj_data(struct canchip_t *chip, int objnr)
238 {
239
240         DEBUGMSG("(c%d)calling ns_dev_init_obj_data( ...)\n", chip->chip_idx);
241
242         /* It seems, that there is no purpose to setup object base address */
243         chip->msgobj[objnr]->obj_base_addr = 0;
244
245         /*can_msgobj_test_fl(pmsgobj,RX_MODE_EXT); */
246         return 0;
247 }
248
249 /**
250  * ns_dev_write_register - Low level write register routine
251  * @data: data to be written
252  * @address: memory address to write to
253  *
254  * The function ns_dev_write_register() is used to write to hardware registers
255  * on the CAN chip. You should only have to edit this function if your hardware
256  * uses some specific write process.
257  * Return Value: The function does not return a value
258  * File: src/template.c
259  */
260 void ns_dev_write_register(unsigned data, can_ioptr_t address)
261 {
262         int i;
263         //unsigned long usecs = 1;
264
265         can_writew(data, address);
266         //udelay( usecs );
267         for (i = 0; i < 5; i++) ;
268 }
269
270 /**
271  * ns_dev_read_register - Low level read register routine
272  * @address: memory address to read from
273  *
274  * The function ns_dev_read_register() is used to read from hardware registers
275  * on the CAN chip. You should only have to edit this function if your hardware
276  * uses some specific read process.
277  * Return Value: The function returns the value stored in @address
278  * File: src/template.c
279  */
280 unsigned ns_dev_read_register(can_ioptr_t address)
281 {
282         u16 value, i;
283
284         value = can_readw(address);
285         //udelay( usecs );
286         for (i = 0; i < 5; i++) ;
287         value = can_readw(address);
288         //udelay( usecs );
289         for (i = 0; i < 5; i++) ;
290
291         return value;
292 }
293
294 /**
295  * ns_dev_program_irq - program interrupts
296  * @candev: Pointer to candevice/board structure
297  *
298  * The function ns_dev_program_irq() is used for hardware that uses
299  * programmable interrupts. If your hardware doesn't use programmable interrupts
300  * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
301  * leave this function unedited. Again this function is hardware specific so
302  * there's no example code.
303  * Return value: The function returns zero on success or %-ENODEV on failure
304  * File: src/template.c
305  */
306 int ns_dev_program_irq(struct candevice_t *candev)
307 {
308         return 0;
309 }
310
311 int ns_dev_register(struct hwspecops_t *hwspecops)
312 {
313         hwspecops->request_io = ns_dev_request_io;
314         hwspecops->release_io = ns_dev_release_io;
315         hwspecops->reset = ns_dev_reset;
316         hwspecops->init_hw_data = ns_dev_init_hw_data;
317         hwspecops->init_chip_data = ns_dev_init_chip_data;
318         hwspecops->init_obj_data = ns_dev_init_obj_data;
319         hwspecops->write_register = ns_dev_write_register;
320         hwspecops->read_register = ns_dev_read_register;
321         hwspecops->program_irq = ns_dev_program_irq;
322         return 0;
323 }