]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/pcccan.c
LinCAN can be compiled in mode with RT-Linux chip worker threads now.
[lincan.git] / lincan / src / pcccan.c
1 /* pcccan.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.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 /* This file contains the low level functions for the pcccan-1 card from Gespac.
11  * You can probably find more information at http://www.gespac.com
12  */
13
14 #include "../include/can.h"
15 #include "../include/can_sysdep.h"
16 #include "../include/main.h"
17 #include "../include/pcccan.h"
18 #include "../include/i82527.h"
19
20 int pcccan_irq=-1;
21 unsigned long pcccan_base=0x0;
22
23 /*
24  * IO_RANGE is the io-memory range that gets reserved, please adjust according
25  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
26  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
27  */
28
29 /* The pcccan card uses indexed addressing hence the need to only reserve
30  * eight bytes of memory.
31  * base + 0 = Reset
32  * base + 1 = Address loading
33  * base + 2 = Read register
34  * base + 3 = Read register + increment loaded address (saves a write operation
35  * when accessing consecutive registers)
36  * base + 4 = Unused
37  * base + 5 = Address read
38  * base + 6 = Write register
39  * base + 7 = Write register + increment loaded address
40  */
41 #define IO_RANGE 0x8
42
43 /**
44  * pcccan_request_io: - reserve io or memory range for can board
45  * @candev: pointer to candevice/board which asks for io. Field @io_addr
46  *      of @candev is used in most cases to define start of the range
47  *
48  * The function pcccan_request_io() is used to reserve the io-memory. If your
49  * hardware uses a dedicated memory range as hardware control registers you
50  * will have to add the code to reserve this memory as well. 
51  * %IO_RANGE is the io-memory range that gets reserved, please adjust according
52  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
53  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
54  * Return Value: The function returns zero on success or %-ENODEV on failure
55  * File: src/pcccan.c
56  */
57 int pcccan_request_io(struct candevice_t *candev)
58 {
59         if (!can_request_io_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) {
60                 CANMSG("Unable to open port: 0x%lx\n",candev->io_addr);
61                 return -ENODEV;
62         } else {
63                 DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1);
64         }
65         return 0;
66 }
67
68 /**
69  * pcccan_elease_io - free reserved io memory range
70  * @candev: pointer to candevice/board which releases io
71  *
72  * The function pcccan_release_io() is used to free reserved io-memory.
73  * In case you have reserved more io memory, don't forget to free it here.
74  * IO_RANGE is the io-memory range that gets released, please adjust according
75  * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
76  * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
77  * Return Value: The function always returns zero
78  * File: src/pcccan.c
79  */
80 int pcccan_release_io(struct candevice_t *candev)
81 {
82         can_release_io_region(candev->io_addr,IO_RANGE);
83
84         return 0;
85 }
86
87 /**
88  * pcccan_reset - hardware reset routine
89  * @candev: Pointer to candevice/board structure
90  *
91  * The function pcccan_reset() is used to give a hardware reset. This is 
92  * rather hardware specific so I haven't included example code. Don't forget to 
93  * check the reset status of the chip before returning.
94  * Return Value: The function returns zero on success or %-ENODEV on failure
95  * File: src/pcccan.c
96  */
97 int pcccan_reset(struct candevice_t *candev)
98 {
99         int i=0;
100
101         DEBUGMSG("Resetting pcccan-1 hardware ...\n");
102         while (i < 1000000) {
103                 i++;
104                 outb(0x0,candev->res_addr);
105         }
106
107         /* Check hardware reset status */
108         i=0;
109         outb(iCPU,candev->io_addr+0x1);
110         while ( (inb(candev->io_addr+0x2)&0x80) && (i<=15) ) {
111                 udelay(20000);
112                 i++;
113         }
114         if (i>=15) {
115                 CANMSG("Reset status timeout!\n");
116                 CANMSG("Please check your hardware.\n");
117                 return -ENODEV;
118         }
119         else
120                 DEBUGMSG("Chip reset status ok.\n");
121
122         return 0;
123
124
125 #define NR_82527 1
126 #define NR_SJA1000 0
127
128 /**
129  * pcccan_init_hw_data - Initialize hardware cards
130  * @candev: Pointer to candevice/board structure
131  *
132  * The function pcccan_init_hw_data() is used to initialize the hardware
133  * structure containing information about the installed CAN-board.
134  * %RESET_ADDR represents the io-address of the hardware reset register.
135  * %NR_82527 represents the number of intel 82527 chips on the board.
136  * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
137  * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
138  * the hardware uses programmable interrupts.
139  * Return Value: The function always returns zero
140  * File: src/pcccan.c
141  */
142 int pcccan_init_hw_data(struct candevice_t *candev) 
143 {
144         candev->res_addr=candev->io_addr;
145         candev->nr_82527_chips=NR_82527;
146         candev->nr_sja1000_chips=NR_SJA1000;
147         candev->nr_all_chips=NR_82527+NR_SJA1000;
148         candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
149
150         return 0;
151 }
152
153 #define CHIP_TYPE "i82527"
154 /**
155  * pcccan_init_chip_data - Initialize chips
156  * @candev: Pointer to candevice/board structure
157  * @chipnr: Number of the CAN chip on the hardware card
158  *
159  * The function pcccan_init_chip_data() is used to initialize the hardware
160  * structure containing information about the CAN chips.
161  * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
162  * "sja1000".
163  * The @chip_base_addr entry represents the start of the 'official' memory map
164  * of the installed chip. It's likely that this is the same as the @io_addr
165  * argument supplied at module loading time.
166  * The @clock entry holds the chip clock value in Hz.
167  * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
168  * register. Options defined in the %sja1000.h file:
169  * %CDR_CLKOUT_MASK, %CDR_CLK_OFF, %CDR_RXINPEN, %CDR_CBP, %CDR_PELICAN
170  * The entry @sja_ocr_reg holds hardware specific options for the Output Control
171  * register. Options defined in the %sja1000.h file:
172  * %OCR_MODE_BIPHASE, %OCR_MODE_TEST, %OCR_MODE_NORMAL, %OCR_MODE_CLOCK,
173  * %OCR_TX0_LH, %OCR_TX1_ZZ.
174  * The entry @int_clk_reg holds hardware specific options for the Clock Out
175  * register. Options defined in the %i82527.h file:
176  * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
177  * The entry @int_bus_reg holds hardware specific options for the Bus 
178  * Configuration register. Options defined in the %i82527.h file:
179  * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
180  * The entry @int_cpu_reg holds hardware specific options for the cpu interface
181  * register. Options defined in the %i82527.h file:
182  * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST.
183  * Return Value: The function always returns zero
184  * File: src/pcccan.c
185  */
186 int pcccan_init_chip_data(struct candevice_t *candev, int chipnr)
187 {
188         candev->chip[chipnr]->chip_type=CHIP_TYPE;
189         candev->chip[chipnr]->chip_base_addr=candev->io_addr;
190         candev->chip[chipnr]->clock = 16000000;
191         candev->chip[chipnr]->int_cpu_reg = iCPU_DSC | iCPU_DMC;
192         candev->chip[chipnr]->int_clk_reg = iCLK_SL1 | iCLK_CD0;
193         candev->chip[chipnr]->int_bus_reg = iBUS_CBY | iBUS_DR1;
194         candev->chip[chipnr]->sja_cdr_reg = 0;
195         candev->chip[chipnr]->sja_ocr_reg = 0;
196         pcccan_irq=candev->chip[chipnr]->chip_irq;
197         pcccan_base=candev->chip[chipnr]->chip_base_addr;
198
199         return 0;
200 }
201
202 /**
203  * pcccan_init_obj_data - Initialize message buffers
204  * @chip: Pointer to chip specific structure
205  * @objnr: Number of the message buffer
206  *
207  * The function pcccan_init_obj_data() is used to initialize the hardware
208  * structure containing information about the different message objects on the
209  * CAN chip. In case of the sja1000 there's only one message object but on the
210  * i82527 chip there are 15.
211  * The code below is for a i82527 chip and initializes the object base addresses
212  * The entry @obj_base_addr represents the first memory address of the message 
213  * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
214  * base address.
215  * Unless the hardware uses a segmented memory map, flags can be set zero.
216  * Return Value: The function always returns zero
217  * File: src/pcccan.c
218  */
219 int pcccan_init_obj_data(struct chip_t *chip, int objnr)
220 {
221         chip->msgobj[objnr]->obj_base_addr=(objnr+1)*0x10;
222         
223         return 0;
224 }
225
226 /**
227  * pcccan_program_irq - program interrupts
228  * @candev: Pointer to candevice/board structure
229  *
230  * The function pcccan_program_irq() is used for hardware that uses 
231  * programmable interrupts. If your hardware doesn't use programmable interrupts
232  * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and 
233  * leave this function unedited. Again this function is hardware specific so 
234  * there's no example code.
235  * Return value: The function returns zero on success or %-ENODEV on failure
236  * File: src/pcccan.c
237  */
238 int pcccan_program_irq(struct candevice_t *candev)
239 {
240         return 0;
241 }
242
243 /**
244  * pcccan_write_register - Low level write register routine
245  * @data: data to be written
246  * @address: memory address to write to
247  *
248  * The function pcccan_write_register() is used to write to hardware registers
249  * on the CAN chip. You should only have to edit this function if your hardware
250  * uses some specific write process.
251  * Return Value: The function does not return a value
252  * File: src/pcccan.c
253  */
254 void pcccan_write_register(unsigned char data, unsigned long address)
255 {
256         can_disable_irq(pcccan_irq);
257         outb(address - pcccan_base, pcccan_base+1);
258         outb(data, pcccan_base+6);
259         can_enable_irq(pcccan_irq);
260 }
261
262 /**
263  * pcccan_read_register - Low level read register routine
264  * @address: memory address to read from
265  *
266  * The function pcccan_read_register() is used to read from hardware registers
267  * on the CAN chip. You should only have to edit this function if your hardware
268  * uses some specific read process.
269  * Return Value: The function returns the value stored in @address
270  * File: src/pcccan.c
271  */
272 unsigned pcccan_read_register(unsigned long address)
273 {
274         unsigned ret;
275         can_disable_irq(pcccan_irq);
276         outb(address - pcccan_base, pcccan_base+1);
277         ret=inb(pcccan_base+2);
278         can_enable_irq(pcccan_irq);
279         return ret;
280
281 }
282
283 /* !!! Don't change this function !!! */
284 int pcccan_register(struct hwspecops_t *hwspecops)
285 {
286         hwspecops->request_io = pcccan_request_io;
287         hwspecops->release_io = pcccan_release_io;
288         hwspecops->reset = pcccan_reset;
289         hwspecops->init_hw_data = pcccan_init_hw_data;
290         hwspecops->init_chip_data = pcccan_init_chip_data;
291         hwspecops->init_obj_data = pcccan_init_obj_data;
292         hwspecops->write_register = pcccan_write_register;
293         hwspecops->read_register = pcccan_read_register;
294         hwspecops->program_irq = pcccan_program_irq;
295         return 0;
296 }