]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/pc_i03.c
CAN driver infrastructure redesign to LinCAN-0.2 version
[lincan.git] / lincan / src / pc_i03.c
1 /* pc-i03.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wnadoo.nl
4  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5  * email:pisa@cmp.felk.cvut.cz
6  * This software is released under the GPL-License.
7  * Version lincan-0.2  9 Jul 2003
8  */ 
9
10 #include <linux/autoconf.h>
11
12 #include <linux/ioport.h>
13 #include <linux/delay.h>
14 #include <asm/errno.h>
15 #include <asm/io.h>
16
17 #include "../include/main.h"
18 #include "../include/pc-i03.h"
19 #include "../include/sja1000.h"
20
21 /* Basic hardware io address. This is also stored in the hardware structure but
22  * we need it global, else we have to change many internal functions.
23  * pc-i03_base_addr is initialized in pc-i03_init_chip_data().
24  */
25 unsigned int pci03_base_addr; 
26
27 /*
28  * IO_RANGE is the io-memory range that gets reserved, please adjust according
29  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
30  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
31  */
32 #define IO_RANGE 0x200  // The pc-i03 uses an additional 0x100 bytes reset space
33
34 /**
35  * pci03_request_io: - reserve io memory
36  * @io_addr: The reserved memory starts at @io_addr, wich is the module 
37  * parameter @io.
38  *
39  * The function pci03_request_io() is used to reserve the io-memory. If your
40  * hardware uses a dedicated memory range as hardware control registers you
41  * will have to add the code to reserve this memory as well. 
42  * %IO_RANGE is the io-memory range that gets reserved, please adjust according
43  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
44  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
45  * Return Value: The function returns zero on success or %-ENODEV on failure
46  * File: src/pc-i03.c
47  */
48 int pci03_request_io(struct candevice_t *candev)
49 {
50         if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) {
51                 CANMSG("Unable to open port: 0x%lx\n",candev->io_addr);
52                 return -ENODEV;
53         } else {
54                 DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1);
55         }
56         return 0;
57 }
58
59 /**
60  * pci03_release_io - free reserved io-memory
61  * @io_addr: Start of the memory range to be released.
62  *
63  * The function pci03_release_io() is used to free reserved io-memory.
64  * In case you have reserved more io memory, don't forget to free it here.
65  * IO_RANGE is the io-memory range that gets released, please adjust according
66  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
67  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
68  * Return Value: The function always returns zero
69  * File: src/pc-i03.c
70  */
71 int pci03_release_io(struct candevice_t *candev)
72 {
73         can_release_io_region(candev->io_addr,IO_RANGE);
74
75         return 0;
76 }
77
78 /**
79  * pci03_reset - hardware reset routine
80  * @card: Number of the hardware card.
81  *
82  * The function pci03_reset() is used to give a hardware reset. This is 
83  * rather hardware specific so I haven't included example code. Don't forget to 
84  * check the reset status of the chip before returning.
85  * Return Value: The function returns zero on success or %-ENODEV on failure
86  * File: src/pc-i03.c
87  */
88 int pci03_reset(struct candevice_t *candev)
89 {
90         int i=0;
91
92         DEBUGMSG("Resetting pc-i03 hardware ...\n");
93         pci03_write_register(0x01,pci03_base_addr +
94                                 0x100); // Write arbitrary data to reset mem
95         udelay(20000);
96
97         pci03_write_register(0x00, pci03_base_addr + SJACR);
98                                                                         
99         /* Check hardware reset status */
100         i=0;
101         while ( (pci03_read_register(pci03_base_addr + SJACR) & CR_RR)
102                                                                  && (i<=15) ) {
103                 udelay(20000);
104                 i++;
105         }
106         if (i>=15) {
107                 CANMSG("Reset status timeout!\n");
108                 CANMSG("Please check your hardware.\n");
109                 return -ENODEV;
110         }
111         else
112                 DEBUGMSG("Chip[0] reset status ok.\n");
113
114         return 0;
115 }
116
117 #define RESET_ADDR 0x100
118 #define NR_82527 0
119 #define NR_SJA1000 1
120
121 /**
122  * pci03_init_hw_data - Initialze hardware cards
123  * @card: Number of the hardware card.
124  *
125  * The function pci03_init_hw_data() is used to initialize the hardware
126  * structure containing information about the installed CAN-board.
127  * %RESET_ADDR represents the io-address of the hardware reset register.
128  * %NR_82527 represents the number of intel 82527 chips on the board.
129  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
130  * The flags entry can currently only be %PROGRAMMABLE_IRQ to indicate that
131  * the hardware uses programmable interrupts.
132  * Return Value: The function always returns zero
133  * File: src/pc-i03.c
134  */
135 int pci03_init_hw_data(struct candevice_t *candev) 
136 {
137         candev->res_addr=RESET_ADDR;
138         candev->nr_82527_chips=NR_82527;
139         candev->nr_sja1000_chips=NR_SJA1000;
140         candev->nr_all_chips=NR_82527+NR_SJA1000;
141         return 0;
142 }
143
144 #define CHIP_TYPE "sja1000"
145 /**
146  * pci03_init_chip_data - Initialize chips
147  * @card: Number of the hardware card
148  * @chipnr: Number of the CAN chip on the hardware card
149  *
150  * The function pci03_init_chip_data() is used to initialize the hardware
151  * structure containing information about the CAN chips.
152  * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
153  * "sja1000".
154  * The @chip_base_addr entry represents the start of the 'official' memory map
155  * of the installed chip. It's likely that this is the same as the @io_addr
156  * argument supplied at module loading time.
157  * The @clock entry holds the chip clock value in Hz.
158  * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
159  * register. Options defined in the %sja1000.h file:
160  * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN
161  * The entry @sja_ocr_reg holds hardware specific options for the Output Control
162  * register. Options defined in the %sja1000.h file:
163  * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK,
164  * %OCR_TX0_LH, %OCR_TX1_ZZ.
165  * The entry @int_clk_reg holds hardware specific options for the Clock Out
166  * register. Options defined in the %i82527.h file:
167  * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
168  * The entry @int_bus_reg holds hardware specific options for the Bus 
169  * Configuration register. Options defined in the %i82527.h file:
170  * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
171  * Return Value: The function always returns zero
172  * File: src/pc-i03.c
173  */
174 int pci03_init_chip_data(struct candevice_t *candev, int chipnr)
175 {
176         pci03_base_addr = candev->io_addr;
177         candev->chip[chipnr]->chip_type=CHIP_TYPE;
178         candev->chip[chipnr]->chip_base_addr=candev->io_addr;
179         candev->chip[chipnr]->clock = 16000000;
180         candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF;
181         candev->chip[chipnr]->sja_ocr_reg = OCR_MODE_NORMAL | 
182                                                         OCR_TX0_HL | OCR_TX1_LZ;
183
184         return 0;
185 }
186
187 /**
188  * pci03_init_obj_data - Initialize message buffers
189  * @chipnr: Number of the CAN chip
190  * @objnr: Number of the message buffer
191  *
192  * The function pci03_init_obj_data() is used to initialize the hardware
193  * structure containing information about the different message objects on the
194  * CAN chip. In case of the sja1000 there's only one message object but on the
195  * i82527 chip there are 15.
196  * The code below is for a i82527 chip and initializes the object base addresses
197  * The entry @obj_base_addr represents the first memory address of the message 
198  * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
199  * base address.
200  * Unless the hardware uses a segmented memory map, flags can be set zero.
201  * Return Value: The function always returns zero
202  * File: src/pc-i03.c
203  */
204 int pci03_init_obj_data(struct chip_t *chip, int objnr)
205 {
206         chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr;
207         chip->msgobj[objnr]->flags=0;
208         
209         return 0;
210 }
211
212 /**
213  * pci03_program_irq - program interrupts
214  * @card: Number of the hardware card.
215  *
216  * The function pci03_program_irq() is used for hardware that uses 
217  * programmable interrupts. If your hardware doesn't use programmable interrupts
218  * you should not set the @candevices_t->flags entry to %PROGRAMMABLE_IRQ and 
219  * leave this function unedited. Again this function is hardware specific so 
220  * there's no example code.
221  * Return value: The function returns zero on success or %-ENODEV on failure
222  * File: src/pc-i03.c
223  */
224 int pci03_program_irq(struct candevice_t *candev)
225 {
226         return 0;
227 }
228
229 /**
230  * pci03_write_register - Low level write register routine
231  * @data: data to be written
232  * @address: memory address to write to
233  *
234  * The function pci03_write_register() is used to write to hardware registers
235  * on the CAN chip. You should only have to edit this function if your hardware
236  * uses some specific write process.
237  * Return Value: The function does not return a value
238  * File: src/pc-i03.c
239  */
240 void pci03_write_register(unsigned char data, unsigned long address)
241 {
242         unsigned int *pci03_base_ptr;
243         unsigned short address_to_write;
244
245         /* The read/write functions are called by an extra abstract function.
246          * This extra function adds the basic io address of the card to the
247          * memory address we want to write to, so we substract the basic io
248          * address again to obtain the offset into the hardware's memory map.
249          */
250         address_to_write = address - pci03_base_addr; // Offset
251         pci03_base_ptr = (unsigned int *)(pci03_base_addr * 0x100001);
252         (*(pci03_base_ptr+address_to_write)) = data;
253 }
254
255 /**
256  * pci03_read_register - Low level read register routine
257  * @address: memory address to read from
258  *
259  * The function pci03_read_register() is used to read from hardware registers
260  * on the CAN chip. You should only have to edit this function if your hardware
261  * uses some specific read process.
262  * Return Value: The function returns the value stored in @address
263  * File: src/pc-i03.c
264  */
265 unsigned pci03_read_register(unsigned long address)
266 {
267         unsigned int *pci03_base_ptr;
268         unsigned short address_to_read;
269
270         /* The read/write functions are called by an extra abstract function.
271          * This extra function adds the basic io address of the card to the
272          * memory address we want to write to, so we substract the basic io
273          * address again to obtain the offset into the hardware's memory map.
274          */
275         address_to_read = address - pci03_base_addr;
276         pci03_base_ptr = (unsigned int *)(pci03_base_addr * 0x100001);
277         return (*(pci03_base_ptr+address_to_read));
278 }
279
280 int pci03_register(struct hwspecops_t *hwspecops)
281 {
282         hwspecops->request_io = pci03_request_io;
283         hwspecops->release_io = pci03_release_io;
284         hwspecops->reset = pci03_reset;
285         hwspecops->init_hw_data = pci03_init_hw_data;
286         hwspecops->init_chip_data = pci03_init_chip_data;
287         hwspecops->init_obj_data = pci03_init_obj_data;
288         hwspecops->write_register = pci03_write_register;
289         hwspecops->read_register = pci03_read_register;
290         hwspecops->program_irq = pci03_program_irq;
291         return 0;
292 }