Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <linux/kernel.h> /* Для printk() и т.д. */
- #include <linux/module.h> /* Эта частичка древней магии, которая оживляет модули */
- #include <linux/init.h> /* Определения макросов */
- #include <linux/fs.h>
- #include <asm/uaccess.h> /* put_user */
- #include <asm/io.h>
- //#include <asm/system.h>
- #include <linux/ioport.h>
- #include <linux/interrupt.h>
- #include <linux/slab.h>
- #include "mx53.h"
- #include "spislave.h"
- // Ниже мы задаём информацию о модуле, которую можно будет увидеть с помощью Modinfo
- MODULE_LICENSE( "GPL" );
- MODULE_AUTHOR( "" );
- MODULE_DESCRIPTION( "Spi slave driver for imx53" );
- MODULE_SUPPORTED_DEVICE( "spi" ); /* /dev/testdevice */
- #define IRQ_NAME "spislave_irq"
- #define IRQ_NUMB 37 // ECSPI-2 irq number
- #define SUCCESS 0
- #define DEVICE_NAME "spislave" /* Имя нашего устройства */
- #define INPUT_BUFFER_SIZE (1*1024*1024)
- #define BYTES_IN_FIFO_IRQ_OCCURS 24 // кол-во байт в фифо когда генерится прерывание (макс 32)
- //#define DEBUG_OUTPUT_ENABLED
- struct {
- char data [INPUT_BUFFER_SIZE];
- int start;
- int end;
- } inputBuffer;
- static int maxRxFifoLoad;
- static int maxBufferLoad;
- static int rxoverflowedCount;
- static char locked;
- // Поддерживаемые нашим устройством операции
- static int device_open( struct inode *, struct file * );
- static int device_release( struct inode *, struct file * );
- static ssize_t device_read( struct file *, char *, size_t, loff_t * );
- static ssize_t device_write( struct file *, const char *, size_t, loff_t * );
- static int region_size = 256;
- // Глобальные переменные, объявлены как static, воизбежание конфликтов имен.
- static int major_number; /* Старший номер устройства нашего драйвера */
- static int is_device_open = 0; /* Используется ли девайс ? */
- static void *spi_base;
- static void *gpio2_base;
- //-------------------------------------------------------------------------------------
- // Прописываем обработчики операций на устройством
- static struct file_operations fops =
- {
- .read = device_read,
- .write = device_write,
- .open = device_open,
- .release = device_release
- };
- //-------------------------------------------------------------------------------------
- //---------------------------- SPI STUFF -------------------------------------------
- //-------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------
- static void ResetInputBuffer(void)
- {
- inputBuffer.start=0;
- inputBuffer.end=0;
- }
- //-------------------------------------------------------------------------------------
- static void ConfigureSpi(void)
- {
- // ------- CONREG -----------
- // CONREG: 19-18 : 00=channel 0 select (SS0),
- // 7-4 : CHANNEL MODE 0-slave/1-master, [3]-channel 3... [0]-channel 0
- // 3: SMC - immediately starts SPI burst when data is written to TXFIFO
- *(int*)(spi_base+ECSPI2_CONREG) = 0x00 ; // enable bit OFF, to reset block
- *(int*)(spi_base+ECSPI2_CONREG) |= (1<<3) | (0x07<<20); // | (0x08<<20); // channel 0 slave , SMC enabled, 8 bits SPI burst
- // ------- CONFIGREG -----------
- // *(int*)(spi_base+ECSPI2_CONFIGREG) = 0x01 ; // согласно картинке Меньшова нам нужен режим POL=0 PHA=1
- *(int*)(spi_base+ECSPI2_CONFIGREG) = 0x00; // согласно картинке Меньшова нам нужен режим POL=0 PHA=0
- // ------- INTREG -----------
- *(int*)(spi_base+ECSPI2_INTREG) = (1<<4) ; // 4: rx fifo data request enable (rxfifo > rx threshold)
- // ------- DMAREG -----------
- *(int*)(spi_base+ECSPI2_DMAREG) = (BYTES_IN_FIFO_IRQ_OCCURS<<16); // = (1<<23); // DMAREG: 21-16: rx threshold
- // DMAREG:
- // 23-RXDEN-RXFIFO DMA request enable
- // ------- PERIODREG -----------
- // PERIODREG only for master:
- // << PERIODREG SKIPPED >>
- // 15 - CSRC : 0-Spi clock, 1- Low freq ref clk 32.768Khz
- // ------- TESTREG -----------
- // TESTREG:
- // 31- LBC: 1- loopback enabled - receiver is connected to transmitter
- *(int*)(spi_base+ECSPI2_TESTREG) = 0;
- *(int*)(spi_base+ECSPI2_CONREG) |= 0x01; // enable bit ON
- //----------- end of SPI configure ------------------
- }
- //-------------------------------------------------------------------------------------
- // Функция загрузки модуля. Входная точка. Можем считать что это наш main()
- static int __init spislave_init( void )
- {
- struct resource *res;
- printk( KERN_ALERT "spi driver: configuring ECSPI-2...\n" );
- res= request_mem_region(ECSPI2_BASE, region_size, "spi");
- spi_base = ioremap_nocache(ECSPI2_BASE, region_size);
- res= request_mem_region(GPIO2_BASE, region_size, "gpio2");
- gpio2_base= ioremap_nocache(GPIO2_BASE, region_size);
- *(int*)(gpio2_base+GPIO_GDIR) |= (1<<24); // 1 means output
- ConfigureSpi();
- printk( KERN_ALERT "spi driver: spislave driver loaded!\n" );
- // Регистрируем устройсво и получаем старший номер устройства
- major_number = register_chrdev( 0, DEVICE_NAME, &fops );
- if ( major_number < 0 )
- {
- printk( "spi driver: Registering the character device failed with %d\n", major_number );
- return major_number;
- }
- // Сообщаем присвоенный нам старший номер устройства
- printk( "spi driver: spislave module is loaded!\n" );
- printk( "spi driver: Please, create a dev file with 'mknod /dev/spislave c %d 0'.\n", major_number );
- return SUCCESS;
- }
- //-------------------------------------------------------------------------------------
- // Функция выгрузки модуля
- static void __exit spislave_exit( void )
- {
- // Освобождаем устройство
- iounmap(spi_base);
- release_mem_region(ECSPI2_BASE, region_size);
- unregister_chrdev( major_number, DEVICE_NAME );
- printk( KERN_ALERT "spi driver: spislave module is unloaded!\n" );
- }
- //-------------------------------------------------------------------------------------
- // Указываем наши функции загрузки и выгрузки
- module_init( spislave_init );
- module_exit( spislave_exit );
- static void CheckMaxRxFifoLoad(int load)
- {
- if (load> maxRxFifoLoad)
- {
- maxRxFifoLoad=load;
- printk (KERN_ALERT "max rx fifo load=%d\n", maxRxFifoLoad);
- if (maxRxFifoLoad==64)
- {
- printk (KERN_ALERT "rx fifo MAXIMUM REACHED. cleared.\n");
- maxRxFifoLoad=0;
- }
- }
- }
- //-------------------------------------------------------------------------------------
- static irqreturn_t irq_handler(int irq, void *dummy, struct pt_regs * regs)
- {
- int testReg;
- int rxFifoCounter;
- int rxData;
- int counter;
- *(int*)(gpio2_base+GPIO_DR) |= (1<<24);
- // экспериментально выяснил, что irq_handler может возникать во время операции read, т.е.
- // read не являются блокирующим для прерывания (по идее так и должно быть, однако были в свое время подозрения).
- //printk(KERN_ALERT "spi IRQ: Interrupt handler executed!\n");
- counter = 256; // число байт которые можем схавать за раз в одном прерывании. это по сути защита от зависонов.
- //теоретически может быть
- // больше чем весь FIFO, т.к. пока сидим и хаваем данные тут могут прийти еще данные в FIFO
- //printk(KERN_ALERT "spi IRQ: %d bytes in buffer\n", rxFifoCounter);
- testReg = *(int*)(spi_base+ECSPI2_TESTREG);
- rxFifoCounter = ((testReg>>8) & 0x7F);// only 7 bits used
- #if defined(DEBUG_OUTPUT_ENABLED)
- CheckMaxRxFifoLoad(rxFifoCounter);
- #endif
- while (rxFifoCounter>0)
- {
- rxData = *(int*)(spi_base+ECSPI2_RXDATA);
- locked=1; // lock inputBuffer
- inputBuffer.data[inputBuffer.end] = rxData & 0xFF;
- inputBuffer.end = (inputBuffer.end+1) % INPUT_BUFFER_SIZE;
- locked=0; // unlock inputBuffer
- testReg = *(int*)(spi_base+ECSPI2_TESTREG);
- rxFifoCounter = ((testReg>>8) & 0x7F);// only 7 bits used
- #if defined(DEBUG_OUTPUT_ENABLED)
- CheckMaxRxFifoLoad(rxFifoCounter);
- #endif
- if (!(counter--)) // защита от зависонов
- break;
- }
- //*(int*)(spi_base+ECSPI2_INTREG) = 0; //debugging
- *(int*)(gpio2_base+GPIO_DR) &= ~(1<<24);
- return IRQ_HANDLED;
- }
- //-------------------------------------------------------------------------------------
- void ResetMaxRxFifoLoad(void)
- {
- maxRxFifoLoad=0;
- maxBufferLoad=0 ;
- rxoverflowedCount=0;
- #if defined(DEBUG_OUTPUT_ENABLED)
- printk (KERN_ALERT "max rx fifo reset\n");
- #endif
- }
- //-------------------------------------------------------------------------------------
- static int device_open( struct inode *inode, struct file *file )
- {
- int status = 0;
- locked=0;
- if ( is_device_open )
- return -EBUSY;
- ResetInputBuffer();
- printk("spi driver: Requesting interrupt\n");
- status = request_irq(IRQ_NUMB, irq_handler,0,IRQ_NAME, NULL);
- //enable_irq (IRQ_NUMB);
- if (status == 0)
- {
- printk("spi driver: spi IRQ request successful!\n");
- }
- else
- {
- printk("spi driver: spi IRQ request failed!\n");
- return status;
- }
- ResetMaxRxFifoLoad();
- is_device_open++;
- return SUCCESS;
- }
- //-------------------------------------------------------------------------------------
- static int device_release( struct inode *inode, struct file *file )
- {
- is_device_open--;
- printk ("spi driver: spi irq freed\n");
- free_irq(IRQ_NUMB, NULL);
- ResetMaxRxFifoLoad();
- return SUCCESS;
- }
- //-------------------------------------------------------------------------------------
- static ssize_t
- device_write( struct file *filp, const char *buff, size_t len, loff_t * off )
- {
- printk( "spi driver: Sorry, this operation isn't supported.\n" );
- return -EINVAL;
- }
- //-------------------------------------------------------------------------------------
- static ssize_t device_read( struct file *filp, /* include/linux/fs.h */
- char *buffer, /* buffer */
- size_t length, /* buffer length */
- loff_t * offset )
- {
- #define MAX_FAILED_OPS 128
- int byte_read = 0;
- char rx;
- int curBufferLoad = (inputBuffer.end>=inputBuffer.start)? (inputBuffer.end-inputBuffer.start) : (INPUT_BUFFER_SIZE-inputBuffer.start + inputBuffer.start);
- int failedOps=0;
- #if defined(DEBUG_OUTPUT_ENABLED)
- int rxoverflowed = *(int*)(spi_base+ECSPI2_STATREG) & (1<<6);
- if (rxoverflowed)
- {
- *(int*)(spi_base+ECSPI2_STATREG) |= (1<<6) ; // writing to 1 to this bit to clear overflow flag
- rxoverflowedCount++;
- //if (rxoverflowedCount % 5 ==0)
- printk (KERN_ERR "overflow count = %d\n", rxoverflowedCount);
- }
- #endif
- while ( length )
- {
- // need to avoid processing during active interrupt handler process
- // check if inputBuffer is unlocked
- if (locked)
- {
- failedOps++;
- if (failedOps>MAX_FAILED_OPS)
- break;
- else
- continue;
- }
- if (inputBuffer.start==inputBuffer.end)
- break;
- rx = inputBuffer.data[inputBuffer.start];
- inputBuffer.start = (inputBuffer.start+1) % INPUT_BUFFER_SIZE;
- //put_user( rxFifoCounter, buffer++ );
- put_user( rx, buffer++ );
- length--;
- byte_read++;
- }
- #if defined(DEBUG_OUTPUT_ENABLED)
- if (curBufferLoad>maxBufferLoad)
- {
- maxBufferLoad= curBufferLoad;
- printk ("max buffer load = %d\n", maxBufferLoad);
- }
- #endif
- return byte_read;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement