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.3 17 Jun 2004
10 #include <linux/err.h>
11 #include <linux/errno.h>
12 #include <linux/mutex.h>
13 #include <linux/irq.h>
14 #include <linux/interrupt.h>
15 #include <linux/types.h>
16 #include <linux/proc_fs.h>
17 #include <linux/clk.h>
18 #include <linux/spi/spi.h>
20 #include "../include/can.h"
21 #include "../include/can_sysdep.h"
22 #include "../include/main.h"
23 #include "../include/setup.h"
24 #include "../include/omap2_spican.h"
25 #include "../include/mcp2515.h"
27 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
29 #include <asm/uaccess.h>
30 #include <plat/dmtimer.h>
31 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
33 static const char* omap2_spican_defaulttype = "mcp2515";
35 static struct workqueue_struct *omap2_spican_wq;
37 /*******************************************************************/
39 * We can't use the standard synchronous wrappers for file I/O; we
40 * need to protect against async removal of the underlying spi_device.
42 static void omap2_spican_spi_complete(void *arg)
44 DEBUGMSG("SPICAN sync: complete\n");
48 ssize_t omap2_spican_spi_sync(struct candevice_t *candev, struct spi_message *message)
50 DECLARE_COMPLETION_ONSTACK(done);
51 struct omap2_spican_platform_data *pdata;
57 panic("SPICAN: trying to send null pointered message");
59 pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
63 message->complete = omap2_spican_spi_complete;
64 message->context = &done;
65 spin_lock_irq(&pdata->spi_lock);
66 if (pdata->spi == NULL)
69 DEBUGMSG("SPICAN sync: transfer\n");
70 status = spi_async(pdata->spi, message);
72 spin_unlock_irq(&pdata->spi_lock);
75 while (!wait_for_completion_interruptible_timeout(&done, msecs_to_jiffies(10))) {
76 DEBUGMSG("SPICAN sync: timeout 10 msecs\n");
78 // do { ;} while (wait_for_completion_interruptible(&done));
79 status = message->status;
81 status = message->actual_length;
86 static ssize_t omap2_spican_spi_transfer(struct candevice_t *candev,void *tx, void *rx, uint16_t len)
88 struct omap2_spican_platform_data *pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
89 struct spi_transfer t = {
94 .speed_hz = pdata->speed_hz,
102 if(len > SPI_BUF_LEN) panic("long CAN spi transfer: %u",len);
104 spi_message_init(&m);
106 spi_message_add_tail(&t, &m);
107 status = omap2_spican_spi_sync(candev, &m);
111 static void hi_async_tasklet_handler(unsigned long data)
113 struct omap2_spican_platform_data *pdata=(struct omap2_spican_platform_data *)data;
121 n = find_first_bit(pdata->hi_async_done_map,OMAP2_SPICAN_PRE_ASYNC);
122 if (n == OMAP2_SPICAN_PRE_ASYNC)
125 DEBUGMSG("SPICAN async %d: high priority tasklet\n",n);
126 if (pdata->async[n].complete)
127 pdata->async[n].complete(pdata->async[n].data,pdata->async[n].count);
129 clear_bit(n,pdata->hi_async_done_map);
130 clear_bit(n,pdata->async_req_map);
131 } while (n < OMAP2_SPICAN_PRE_ASYNC);
134 static void lo_async_workqueue_handler(struct work_struct *work)
136 struct omap2_spican_platform_data *pdata = container_of(work,struct omap2_spican_platform_data,lo_async_workqueue);
137 struct omap2_spican_async_t *async;
144 n = find_first_bit(pdata->lo_async_done_map,OMAP2_SPICAN_PRE_ASYNC);
145 if (n >= OMAP2_SPICAN_PRE_ASYNC)
148 DEBUGMSG("SPICAN async %d: low priority workqueue\n",n);
149 async = pdata->async + n;
152 async->complete(async->data,async->count);
154 clear_bit(n,pdata->lo_async_done_map);
155 clear_bit(n,pdata->async_req_map);
156 } while (n < OMAP2_SPICAN_PRE_ASYNC);
159 static void omap2_spican_spi_async_complete(void *arg)
161 struct omap2_spican_async_t *as = (struct omap2_spican_async_t *)arg;
162 struct omap2_spican_platform_data *pdata = container_of(as,struct omap2_spican_platform_data,async[as->bitmap_bit]);
165 // DEBUGMSG("SPICAN async: complete\n");
166 for (i=1;i<as->count;i++)
167 can_filltimestamp(&as->data[i].timestamp);
168 // Serve the fast handlers ASAP
169 if ((as->fasthandler) && (as->complete)){
170 // DEBUGMSG("SPICAN async: fasthandler\n");
171 /* set_bit(as->bitmap_bit,pdata->hi_async_done_map);
172 tasklet_hi_schedule(&pdata->hi_async_tasklet);*/
174 as->complete(as->data,as->count);
176 clear_bit(as->bitmap_bit,pdata->lo_async_done_map);
177 clear_bit(as->bitmap_bit,pdata->async_req_map);
178 // DEBUGMSG("SPICAN async: fasthandler done\n");
182 DEBUGMSG("SPICAN async %d: slowhandler register\n",as->bitmap_bit);
183 set_bit(as->bitmap_bit,pdata->lo_async_done_map);
184 queue_work(omap2_spican_wq,&pdata->lo_async_workqueue);
187 ssize_t omap2_spican_spi_async_transfer(struct candevice_t *candev, void (*callback)(void *data), struct can_spi_async_t *data, uint8_t count, uint8_t fasthandler)
189 struct omap2_spican_platform_data *pdata;
190 struct omap2_spican_async_t *async;
197 pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
201 if (count > OMAP2_SPICAN_MAX_TRANSFERS)
205 n = find_first_zero_bit(pdata->async_req_map, OMAP2_SPICAN_PRE_ASYNC);
206 // There's no free transfer slot
207 if (n == OMAP2_SPICAN_PRE_ASYNC)
209 } while (test_and_set_bit(n,pdata->async_req_map));
211 async = pdata->async+n;
213 memset(async,0,sizeof(struct omap2_spican_async_t));
215 for (i=0;i<count;i++){
216 if(data[i].len > SPI_MESSAGE_LENGTH)
217 panic("too long CAN spi transfer: %u",data[i].len);
220 memcpy(async->data,data,count*sizeof(struct can_spi_async_t));
221 async->count = count;
222 async->bitmap_bit = n;
223 async->complete = callback;
224 async->fasthandler = fasthandler;
226 spi_message_init(&async->m);
228 for (i=0;i<count;i++){
229 if ((async->data[i].tx_buf == NULL) && (async->data[i].rx_buf == NULL) && async->data[i].len != 0)
230 panic("Trying to send NULL pointered buffers");
232 async->t[i].tx_buf = async->data[i].tx_buf;
233 async->t[i].rx_buf = async->data[i].rx_buf;
234 async->t[i].len = async->data[i].len;
235 async->t[i].cs_change = 1;
236 async->t[i].speed_hz = pdata->speed_hz;
237 async->t[i].bits_per_word = 8;
239 spi_message_add_tail(&async->t[i], &async->m);
242 async->m.complete = omap2_spican_spi_async_complete;
243 async->m.context = async;
244 spin_lock_irq(&pdata->spi_lock);
245 if (pdata->spi == NULL)
248 DEBUGMSG("SPICAN async %d: transfer\n",n);
249 status = spi_async(pdata->spi, &async->m);
251 spin_unlock_irq(&pdata->spi_lock);
254 clear_bit(n,pdata->async_req_map);
261 * omap2_spican_irq_handler: - GPT (general purpose timer) and waiting
262 * thread interrupt handler
263 * @irq: the interrupt line number
264 * @dev_id: pointer to can device data
266 * Return Value: Interrupt handled status is returned
267 * File: src/omap2_spican.c
269 static irqreturn_t omap2_spican_irq_handler(int irq, void *dev_id)
271 struct candevice_t *candev = dev_id;
272 struct omap2_spican_platform_data *pdata;
279 pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
283 /* if (((pdata->trigger == OMAP2_SPICAN_TRIG_GPT) && (irq != pdata->timer_irq))
284 || ((pdata->trigger == OMAP2_SPICAN_TRIG_IRQ) && (irq != pdata->irq))
287 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
288 if ((irq != pdata->timer_irq) && (irq != pdata->irq))
291 if (irq != pdata->irq)
296 DEBUGMSG("SPICAN: Got interrupt");
297 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
298 // if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
299 if (irq == pdata->timer_irq){
300 // reset the timer interrupt status
301 omap_dm_timer_write_status(pdata->timer_ptr, OMAP_TIMER_INT_OVERFLOW);
302 omap_dm_timer_read_status(pdata->timer_ptr); // YES, you really need to do this 'wasteful' read
304 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
306 for (i=0;i<candev->nr_all_chips;i++){
307 if (candev->chip[i]->chipspecops->irq_handler)
308 candev->chip[i]->chipspecops->irq_handler(irq, candev->chip[i]);
316 * omap2_spican_request_io: - reserve io or memory range for can board
317 * @candev: pointer to candevice/board which asks for io. Field @io_addr
318 * of @candev is used in most cases to define start of the range
320 * The function omap2_spican_request_io() is used to reserve the io-memory. If your
321 * hardware uses a dedicated memory range as hardware control registers you
322 * will have to add the code to reserve this memory as well.
323 * %IO_RANGE is the io-memory range that gets reserved, please adjust according
324 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
325 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
326 * Return Value: The function returns zero on success or %-ENODEV on failure
327 * File: src/omap2_spican.c
329 int omap2_spican_request_io(struct candevice_t *candev)
335 * omap2_spican_release_io - free reserved io memory range
336 * @candev: pointer to candevice/board which releases io
338 * The function omap2_spican_release_io() is used to free reserved io-memory.
339 * In case you have reserved more io memory, don't forget to free it here.
340 * IO_RANGE is the io-memory range that gets released, please adjust according
341 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
342 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
343 * Return Value: The function always returns zero
344 * File: src/omap2_spican.c
346 int omap2_spican_release_io(struct candevice_t *candev)
352 * omap2_spican_reset - hardware reset routine
353 * @candev: Pointer to candevice/board structure
355 * The function omap2_spican_reset() is used to give a hardware reset. This is
356 * rather hardware specific so I haven't included example code. Don't forget to
357 * check the reset status of the chip before returning.
358 * Return Value: The function returns zero on success or %-ENODEV on failure
359 * File: src/omap2_spican.c
361 int omap2_spican_reset(struct candevice_t *candev)
364 DEBUGMSG("Resetting all underlying chips\n");
365 for(i=0;i<OMAP2_SPICAN_NCHIPS;i++)
366 (candev->chip[i]->chipspecops->reset_chip)(candev->chip[i]);
372 * omap2_spican_init_hw_data - Initialize hardware cards
373 * @candev: Pointer to candevice/board structure
375 * The function omap2_spican_init_hw_data() is used to initialize the hardware
376 * structure containing information about the installed CAN-board.
377 * %RESET_ADDR represents the io-address of the hardware reset register.
378 * %NR_82527 represents the number of Intel 82527 chips on the board.
379 * %NR_SJA1000 represents the number of Philips sja1000 chips on the board.
380 * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
381 * the hardware uses programmable interrupts.
382 * Return Value: The function always returns zero
383 * File: src/omap2_spican.c
385 int omap2_spican_init_hw_data(struct candevice_t *candev)
387 candev->dev_base_addr = 0;
388 candev->nr_82527_chips = 0;
389 candev->nr_sja1000_chips = 0;
390 candev->nr_mcp2515_chips = OMAP2_SPICAN_NCHIPS;
391 candev->nr_all_chips = candev->nr_82527_chips +
392 candev->nr_sja1000_chips +
393 candev->nr_mcp2515_chips;
394 candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
400 * omap2_spican_init_chip_data - Initialize chips
401 * @candev: Pointer to candevice/board structure
402 * @chipnr: Number of the CAN chip on the hardware card
404 * The function omap2_spican_init_chip_data() is used to initialize the hardware
405 * structure containing information about the CAN chips.
406 * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
408 * The @chip_base_addr entry represents the start of the 'official' memory map
409 * of the installed chip. It's likely that this is the same as the @io_addr
410 * argument supplied at module loading time.
411 * The @clock entry holds the chip clock value in Hz.
412 * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
413 * register. Options defined in the %sja1000.h file:
414 * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN
415 * The entry @sja_ocr_reg holds hardware specific options for the Output Control
416 * register. Options defined in the %sja1000.h file:
417 * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK,
418 * %sjaOCR_TX0_LH, %sjaOCR_TX1_ZZ.
419 * The entry @int_clk_reg holds hardware specific options for the Clock Out
420 * register. Options defined in the %i82527.h file:
421 * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
422 * The entry @int_bus_reg holds hardware specific options for the Bus
423 * Configuration register. Options defined in the %i82527.h file:
424 * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
425 * The entry @int_cpu_reg holds hardware specific options for the cpu interface
426 * register. Options defined in the %i82527.h file:
427 * %iCPU_CEN, %iCPU_MUX, %iCPU_SLP, %iCPU_PWD, %iCPU_DMC, %iCPU_DSC, %iCPU_RST.
428 * Return Value: The function always returns zero
429 * File: src/omap2_spican.c
431 int omap2_spican_init_chip_data(struct candevice_t *candev, int chipnr)
433 if(chipnr >= OMAP2_SPICAN_NCHIPS || chipnr < 0) {
434 CANMSG("Error: chipnr=%d\n",chipnr);
438 mcp2515_fill_chipspecops(candev->chip[chipnr]);
439 /* candev->chip[chipnr]->chip_base_addr = 0;
440 candev->chip[chipnr]->spi_channel = 2;*/
441 candev->chip[chipnr]->chip_data = can_checked_malloc(sizeof(MCP2515_PRIV));
442 if(candev->chip[chipnr]->chip_data == NULL) return -ENOMEM;
443 memset(candev->chip[chipnr]->chip_data,0,sizeof(MCP2515_PRIV));
448 int omap2_spican_register_chip_data(struct canchip_t *ch,void *data){
449 struct omap2_spican_platform_data *pdata = (struct omap2_spican_platform_data *)data;
450 ch->clock = pdata->clk;
451 ch->baudrate = pdata->baudrate;
454 ch->flags |= CHIP_IRQ_CUSTOM;
455 // if (pdata->trigger == OMAP2_SPICAN_TRIG_IRQ){
456 // ch->chip_irq = pdata->irq;
459 ret = ch->chipspecops->chip_config(ch);
461 CANMSG("Error configuring chip.\n");
464 ch->flags |= CHIP_CONFIGURED;
469 * omap2_spican_init_obj_data - Initialize message buffers
470 * @chip: Pointer to chip specific structure
471 * @objnr: Number of the message buffer
473 * The function omap2_spican_init_obj_data() is used to initialize the hardware
474 * structure containing information about the different message objects on the
475 * CAN chip. In case of the sja1000 there's only one message object but on the
476 * i82527 chip there are 15.
477 * The code below is for a i82527 chip and initializes the object base addresses
478 * The entry @obj_base_addr represents the first memory address of the message
479 * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
481 * Unless the hardware uses a segmented memory map, flags can be set zero.
482 * Return Value: The function always returns zero
483 * File: src/omap2_spican.c
485 int omap2_spican_init_obj_data(struct canchip_t *chip, int objnr)
487 chip->msgobj[objnr]->obj_base_addr=0;
488 chip->msgobj[objnr]->obj_flags=0;
494 * omap2_spican_write_register - Low level write register routine
495 * @data: data to be written
496 * @address: memory address to write to
498 * The function omap2_spican_write_register() is used to write to hardware registers
499 * on the CAN chip. You should only have to edit this function if your hardware
500 * uses some specific write process.
501 * Return Value: The function does not return a value
502 * File: src/omap2_spican.c
504 void omap2_spican_write_register(unsigned data, can_ioptr_t address)
506 panic("omap2_spican_write_register");
510 * omap2_spican_read_register - Low level read register routine
511 * @address: memory address to read from
513 * The function omap2_spican_read_register() is used to read from hardware registers
514 * on the CAN chip. You should only have to edit this function if your hardware
515 * uses some specific read process.
516 * Return Value: The function returns the value stored in @address
517 * File: src/omap2_spican.c
519 unsigned omap2_spican_read_register(can_ioptr_t address)
521 panic("omap2_spican_read_register");
526 * omap2_spican_program_irq - program interrupts
527 * @candev: Pointer to candevice/board structure
529 * The function omap2_spican_program_irq() is used for hardware that uses
530 * programmable interrupts. If your hardware doesn't use programmable interrupts
531 * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
532 * leave this function unedited. Again this function is hardware specific so
533 * there's no example code.
534 * Return value: The function returns zero on success or %-ENODEV on failure
535 * File: src/omap2_spican.c
537 int omap2_spican_program_irq(struct candevice_t *candev)
542 /*******************************************************************/
543 int omap2_spican_spi_acquire_bus(struct candevice_t *candev, short channel, int block){
544 /* Subsystem is always ready to accept messages */
548 /*******************************************************************/
549 void omap2_spican_spi_release_bus(struct candevice_t *candev, short channel){
553 int omap2_spican_register(struct hwspecops_t *hwspecops)
555 hwspecops->request_io = omap2_spican_request_io;
556 hwspecops->release_io = omap2_spican_release_io;
557 hwspecops->reset = omap2_spican_reset;
558 hwspecops->init_hw_data = omap2_spican_init_hw_data;
559 hwspecops->init_chip_data = omap2_spican_init_chip_data;
560 hwspecops->init_obj_data = omap2_spican_init_obj_data;
561 hwspecops->write_register = omap2_spican_write_register;
562 hwspecops->read_register = omap2_spican_read_register;
563 hwspecops->program_irq = omap2_spican_program_irq;
565 // SPI specific functions
566 hwspecops->spi_transfer = omap2_spican_spi_transfer;
567 hwspecops->spi_async_transfer = omap2_spican_spi_async_transfer;
568 hwspecops->spi_acquire_bus = omap2_spican_spi_acquire_bus;
569 hwspecops->spi_release_bus = omap2_spican_spi_release_bus;
574 /*******************************************************************/
576 static int omap2_spican_probe(struct spi_device *spi)
578 struct lincan_spican_platform_data *spidata = spi->dev.platform_data;
579 struct omap2_spican_platform_data *pdata;
580 struct candevice_t *dev;
583 DEBUGMSG("Starting probe for omap2_spican...\n");
585 // Structure checks and initialization
586 pdata = (struct omap2_spican_platform_data *)can_checked_malloc(sizeof(struct omap2_spican_platform_data));
588 memset(pdata,0,sizeof(struct omap2_spican_platform_data));
593 memcpy(pdata,spidata,sizeof(struct lincan_spican_platform_data));
595 if (!pdata->cs_change) pdata->cs_change = OMAP2_SPICAN_CS_CHANGE;
596 if (!pdata->delay_usecs) pdata->delay_usecs = OMAP2_SPICAN_DELAY_USECS;
598 if (!pdata->clk) pdata->clk = OMAP2_SPICAN_MCP_CLK;
599 if (!pdata->baudrate) pdata->baudrate = OMAP2_SPICAN_BAUDRATE;
600 if (!pdata->speed_hz) pdata->speed_hz = OMAP2_SPICAN_SPEED_HZ;
601 if (!pdata->chiptype) pdata->chiptype = omap2_spican_defaulttype;
603 spin_lock_init(&pdata->spi_lock);
607 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
608 INIT_WORK(&pdata->lo_async_workqueue,
609 lo_async_workqueue_handler,
610 &pdata->lo_async_workqueue);
612 INIT_WORK(&pdata->lo_async_workqueue,
613 lo_async_workqueue_handler);
615 tasklet_init(&pdata->hi_async_tasklet,
616 hi_async_tasklet_handler,
617 (unsigned long)pdata);
620 DEBUGMSG("Interrupt line number %d provided.\n",spi->irq);
621 pdata->trigger = OMAP2_SPICAN_TRIG_IRQ;
622 pdata->irq = spi->irq;
625 DEBUGMSG("no IRQ given, trying to find timers. Performance loss will be observed.\n");
627 /* Register device data in LinCAN - 1 chip, 2 msgobjs */
628 dev = register_hotplug_dev("omap2_spican",omap2_spican_register_chip_data,pdata);
632 if (pdata->trigger == OMAP2_SPICAN_TRIG_IRQ) {
634 DEBUGMSG("Requesting interrupt line %d.\n",spi->irq);
635 status = set_irq_type(pdata->irq,IRQ_TYPE_EDGE_FALLING);
637 CANMSG("Setting falling edge trigger on irq %d failed.\n", spi->irq);
640 status = request_irq(pdata->irq, omap2_spican_irq_handler, IRQF_DISABLED , "omap2_spican", dev);
642 CANMSG("request_irq failed on irq %d\n", spi->irq);
646 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
647 // if (pdata->trigger == 0){
654 DEBUGMSG("Setting up OMAP GPT\n");
656 pdata->timer_ptr = omap_dm_timer_request();
657 if(pdata->timer_ptr == NULL){
658 CANMSG("No more gp timers available, bailing out\n");
663 omap_dm_timer_set_source(pdata->timer_ptr, OMAP_TIMER_SRC_SYS_CLK); // We use the system clock 38.4 MHz
665 omap_dm_timer_set_prescaler(pdata->timer_ptr, prescaler); // Set prescaler to 2^(n+1)
667 // get clock rate in Hz
668 gt_fclk = omap_dm_timer_get_fclk(pdata->timer_ptr);
669 gt_rate = clk_get_rate(gt_fclk)/(1<<(prescaler+1));
671 // set preload, and autoreload
672 // we set it to the clock rate in order to get 1 overflow every 1 msec
673 omap_dm_timer_set_load(pdata->timer_ptr, 1, 0xFFFFFFFF - (uint32_t)(gt_rate / 1000));
675 // Request for the irq
676 pdata->timer_irq = omap_dm_timer_get_irq(pdata->timer_ptr);
677 DEBUGMSG("Requesting irq %d for OMAP GPT\n", pdata->timer_irq);
678 status = request_irq(pdata->timer_irq, omap2_spican_irq_handler, IRQF_DISABLED | IRQF_TIMER , "omap2_spican", dev);
680 CANMSG("request_irq failed (on irq %d), bailing out\n", pdata->timer_irq);
681 omap_dm_timer_free(pdata->timer_ptr);
685 // setup timer to trigger our IRQ on the overflow event
686 omap_dm_timer_set_int_enable(pdata->timer_ptr, OMAP_TIMER_INT_OVERFLOW);
687 // pdata->trigger = OMAP2_SPICAN_TRIG_GPT;
689 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
691 spi_set_drvdata(spi, dev);
693 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
694 // if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
696 // Everything's ready, let's roll!
697 DEBUGMSG("Starting OMAP GPT\n");
698 omap_dm_timer_start(pdata->timer_ptr);
700 #endif /* CONFIG_OC_LINCAN_OMAP_DM_TIMER */
701 DEBUGMSG("Device omap2_spican successfully configured. Have fun!\n");
705 can_checked_free(pdata);
709 static int omap2_spican_remove(struct spi_device *spi)
711 struct candevice_t *candev = spi_get_drvdata(spi);
712 struct omap2_spican_platform_data *pdata = (struct omap2_spican_platform_data *)(candev->sysdevptr.anydev);
714 if (pdata->trigger == OMAP2_SPICAN_TRIG_IRQ){
715 // release the IRQ handler
716 free_irq(pdata->irq, candev);
718 #ifdef CONFIG_OC_LINCAN_OMAP_DM_TIMER
719 // if (pdata->trigger == OMAP2_SPICAN_TRIG_GPT){
721 DEBUGMSG("Stopping OMAP GPT\n");
722 omap_dm_timer_stop(pdata->timer_ptr);
723 // release the IRQ handler
724 free_irq(pdata->timer_irq, candev);
726 omap_dm_timer_free(pdata->timer_ptr);
730 DEBUGMSG("Removing omap2_spican from device structure...");
731 // make sure ops on existing fds can abort cleanly
732 deregister_hotplug_dev(candev);
733 cleanup_hotplug_dev(candev);
735 spin_lock_irq(&pdata->spi_lock);
737 spi_set_drvdata(spi, NULL);
738 // candev->sysdevptr.anydev = NULL;
739 spin_unlock_irq(&pdata->spi_lock);
741 DEBUGMSG("Kill tasklets.\n");
742 tasklet_kill(&pdata->hi_async_tasklet);
744 can_checked_free(pdata);
745 DEBUGMSG(" done.\n");
750 static struct spi_driver omap2_spican_driver = {
752 .name = "omap2_spican",
753 .owner = THIS_MODULE,
755 .probe = omap2_spican_probe,
756 .remove = omap2_spican_remove,
757 /* .suspend = omap2_spican_suspend,
758 .resume = omap2_spican_resume,*/
761 int omap2_spican_init(void){
762 omap2_spican_wq = create_singlethread_workqueue("omap2_spican");
763 if (omap2_spican_wq == NULL)
765 return spi_register_driver(&omap2_spican_driver);
768 void omap2_spican_exit(void){
769 spi_unregister_driver(&omap2_spican_driver);
770 destroy_workqueue(omap2_spican_wq);
774 MODULE_ALIAS("spi:omap2_spican");