OSDN Git Service

Initial commit
authorNaoya Takamura <ntaka@nt-sys.jp>
Thu, 8 Dec 2011 11:07:45 +0000 (20:07 +0900)
committerNaoya Takamura <ntaka@nt-sys.jp>
Thu, 8 Dec 2011 11:07:45 +0000 (20:07 +0900)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
overo-source-me.txt [new file with mode: 0644]
spike-ad.c [new file with mode: 0644]
spike-ad.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ef64378
--- /dev/null
@@ -0,0 +1,8 @@
+*.cmd
+.tmp_versions*
+Module.symvers
+modules.order
+*.ko
+*.o
+*.mod.c
+*.d
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..bc7de59
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+DRIVER = spike-ad
+
+ifneq ($(KERNELRELEASE),)
+    obj-m := $(DRIVER).o
+else
+    PWD := $(shell pwd)
+
+default:
+ifeq ($(strip $(KERNELDIR)),)
+       $(error "KERNELDIR is undefined!")
+else
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
+endif
+
+
+clean:
+       rm -rf *~ *.ko *.o *.mod.c modules.order Module.symvers .$(DRIVER)* .tmp_versions
+
+endif
+
diff --git a/overo-source-me.txt b/overo-source-me.txt
new file mode 100644 (file)
index 0000000..b652225
--- /dev/null
@@ -0,0 +1,31 @@
+if [[ -z "${KERNEL_CROSS_BUILD_ENVIRONMENT_SOURCED}" ]]; then
+
+       MACHINE=overo
+
+       # normally OETMP will be ${OVEROTOP}/tmp, but really it is whatever TMPDIR
+       # in ${OVEROTOP}/build/conf/site.conf points to.
+       OETMP=${OVEROTOP}/tmp
+       # OETMP=/oe5            
+
+       SYSROOTSDIR=${OETMP}/sysroots
+       STAGEDIR=${SYSROOTSDIR}/`uname -m`-linux/usr
+
+       export KERNELDIR=${SYSROOTSDIR}/${MACHINE}-angstrom-linux-gnueabi/kernel
+
+       PATH=${PATH}:${STAGEDIR}/bin:${STAGEDIR}/armv7a/bin
+
+       unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS MACHINE
+
+       export ARCH="arm"
+       export CROSS_COMPILE="arm-angstrom-linux-gnueabi-"
+       export CC="arm-angstrom-linux-gnueabi-gcc"
+       export LD="arm-angstrom-linux-gnueabi-ld"
+       export STRIP="arm-angstrom-linux-gnueabi-strip"
+
+       export KERNEL_CROSS_BUILD_ENVIRONMENT_SOURCED="true"
+
+       echo "Altered environment for cross building a kernel module with OE tools."
+else
+       echo "Cross build environment already configured."
+fi
+
diff --git a/spike-ad.c b/spike-ad.c
new file mode 100644 (file)
index 0000000..5e32129
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+  sciLogger SPI driver
+  spike.c
+
+  GPIO144 DRDY signal from PIC24@CPU2010
+  SPI2 AD data receive and CMD send for PIC24@CPU2010
+  
+  Copyright Naoya Takamura, 2011
+  This program based on spike.c
+---------------------------------------------
+  spike.c
+  Copyright Scott Ellis, 2010
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/spi/spi.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include "spike-ad.h"
+
+#define SPI_BUFF_SIZE  2048
+#define USER_BUFF_SIZE 128
+
+#define SPI_BUS 1
+#define SPI_BUS_CS0 0
+#define SPI_BUS_SPEED 500000   // Hz
+
+#define        SPI_DATA_SIZE   945     // $含む
+
+#define GPIO_DRDY_IN 144       // DRDY Input = GPIO144
+
+#define        DEBUG_TOGGLE_OUT        // デバッグ時定義する
+#ifdef DEBUG_TOGGLE_OUT
+       #define GPIO_TOGGLE_OUT 145     // Debug用toggle出力 = GPIO145
+#endif
+
+/**** 注意! Version */
+#define VERSION        "1.0"
+#define MODULE_NAME            "spike-ad"
+
+const char this_driver_name[] = MODULE_NAME;
+
+struct spike_control {
+       struct spi_message msg;
+       struct spi_transfer transfer;
+       u32 busy;       // 1=spi_async()終了待ち
+       u32 spi_callbacks;
+//     u32 busy_counter;
+       u8 *tx_buff; 
+       u8 *rx_buff;
+       int     received_len;
+};
+
+static struct spike_control spike_ctl;
+
+struct irq_device {
+       struct semaphore sem;
+       int irq;
+};
+
+static struct irq_device irq_dev;
+
+
+struct spike_dev {
+       spinlock_t spi_lock;
+       struct semaphore spi_sem;
+       struct semaphore fop_sem;
+       dev_t devt;
+       struct cdev cdev;
+       struct class *class;
+       struct spi_device *spi_device;
+       char *user_buff;
+//     u8 test_data;
+};
+
+static struct spike_dev spike_dev;
+
+// ファイル管理領域
+typedef struct {
+       unsigned long f_version;   // 識別用 f_version
+       wait_queue_head_t wait;    /* read and write queues */
+       int sleep_mode;            // 0: 起きてる 1: 待ち
+       int     intflag;                        // 割り込みフラグ 1=割り込み入った
+} FileInfo;
+
+static FileInfo finfo;
+
+void spike_tasklet_func(unsigned long data);
+DECLARE_TASKLET(spike_tasklet, spike_tasklet_func, 0);
+
+//仮
+static char    ring_buf[SPI_DATA_SIZE];
+
+// 送信データ
+#define        SPI_TX_MAX      (64)
+static unsigned char   spitxbuf[SPI_TX_MAX];
+int    spi_tx_len;
+
+
+/*
+       spike_queue_spi_write()で開始した
+       spi_async()終了後に呼ばれる
+*/
+static void spike_spi_completion_handler(void *arg)
+{
+       // Streaming mapping DMA unmap
+//     unmap_dma_buf();
+
+       spike_ctl.spi_callbacks++;
+       spike_ctl.busy = 0;
+// 受信したデータを保存 仮
+memcpy(ring_buf, spike_ctl.rx_buff, SPI_DATA_SIZE);
+       // 実際に受信できたデータ長
+       spike_ctl.received_len = spike_ctl.msg.actual_length;
+
+       // 書き込み位置進める
+//     ring_write_plus();
+
+       // 寝ているものを起こす
+       if (finfo.sleep_mode) {
+               // 待ちを
+               wake_up_interruptible(&(finfo.wait));        // 起こす
+//printk(KERN_INFO "intsel_interrupt: wakeup %ld\n", fi[i].f_version);
+               finfo.sleep_mode = 0;
+               finfo.intflag = 1;
+       }
+}
+/*
+       spi_async()で送信
+*/
+static int spike_queue_spi_write(void)
+{
+       int status;
+       unsigned long flags;
+
+       // struct spi_messageを初期化 ゼロクリア
+       spi_message_init(&spike_ctl.msg);
+
+       // Callback関数設定
+       spike_ctl.msg.complete = spike_spi_completion_handler;
+       spike_ctl.msg.context = NULL;
+
+       /* write some toggling bit patterns, doesn't really matter */   
+       memset(spike_ctl.tx_buff, 0, SPI_BUFF_SIZE);
+       spike_ctl.tx_buff[0] = '$';
+       memset(spike_ctl.rx_buff, 0, SPI_BUFF_SIZE);
+
+       spike_ctl.transfer.tx_buf = spike_ctl.tx_buff;
+       spike_ctl.transfer.rx_buf = spike_ctl.rx_buff;
+       spike_ctl.transfer.len = SPI_DATA_SIZE;
+
+       spi_message_add_tail(&spike_ctl.transfer, &spike_ctl.msg);
+
+       spin_lock_irqsave(&spike_dev.spi_lock, flags);
+
+       if (spike_dev.spi_device)
+               status = spi_async(spike_dev.spi_device, &spike_ctl.msg);
+       else
+               status = -ENODEV;
+
+       spin_unlock_irqrestore(&spike_dev.spi_lock, flags);
+       
+       if (status == 0)
+               spike_ctl.busy = 1;
+       
+       return status;  
+}
+/*
+  Tasklet
+  IRQ Handlerで呼び出される
+*/
+void spike_tasklet_func(unsigned long data)
+{
+       int status;
+       // SPI送受信開始
+       status = spike_queue_spi_write();
+       if (status) {
+               // error
+       } else {
+               // ok
+       }
+}
+/*
+       DRDY Interrupt Handler
+*/
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+#ifdef DEBUG_TOGGLE_OUT
+       if (gpio_get_value(GPIO_TOGGLE_OUT)) {
+               gpio_set_value(GPIO_TOGGLE_OUT, 0);
+       } else {
+               gpio_set_value(GPIO_TOGGLE_OUT, 1);
+       }
+#endif
+       // タスクレットにまかせる
+       tasklet_schedule(&spike_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+static ssize_t spike_file_read(struct file *filp, char __user *buff, size_t count,
+                       loff_t *offp)
+{
+       size_t len;
+       ssize_t status = 0;
+
+       if (!buff) 
+               return -EFAULT;
+
+       if (*offp > 0) 
+               return 0;
+
+       if (down_interruptible(&spike_dev.fop_sem)) 
+               return -ERESTARTSYS;
+
+if (spike_ctl.busy) {
+       sprintf(spike_dev.user_buff, "spike_ctl.busy==1\n");
+       count = strlen(spike_dev.user_buff);
+       up(&spike_dev.fop_sem);
+       return count;
+} else {
+//sprintf(spike_dev.user_buff, "DMA\n");
+
+               sprintf(spike_dev.user_buff, 
+                       "Status: %d\nTX: %d %d %d %d\nRX: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\nCallback=%d DRDY=%d\n",
+                       spike_ctl.msg.status,
+                       spike_ctl.tx_buff[0], spike_ctl.tx_buff[1], 
+                       spike_ctl.tx_buff[2], spike_ctl.tx_buff[3],
+                       spike_ctl.rx_buff[0], spike_ctl.rx_buff[1], 
+                       spike_ctl.rx_buff[2], spike_ctl.rx_buff[3],
+                       spike_ctl.rx_buff[4], spike_ctl.rx_buff[5], 
+                       spike_ctl.rx_buff[6], spike_ctl.rx_buff[7],
+                       spike_ctl.rx_buff[8], spike_ctl.rx_buff[9], 
+                       spike_ctl.rx_buff[10], spike_ctl.rx_buff[11],
+                       spike_ctl.rx_buff[12], spike_ctl.rx_buff[13], 
+                       spike_ctl.rx_buff[14], spike_ctl.rx_buff[15],
+                       spike_ctl.spi_callbacks, gpio_get_value(GPIO_DRDY_IN));
+
+}
+//     status = spike_do_one_message();
+//status = spike_send_cmd();
+//status = spike_rcv_data();
+
+#if 0
+// SPI送受信開始
+status = spike_queue_spi_write();
+
+       if (status) {
+               sprintf(spike_dev.user_buff, 
+                       "spike_do_one_message failed : %d\n",
+                       status);
+       }
+       else {
+       }
+#endif
+
+       len = strlen(spike_dev.user_buff);
+       if (len < count) 
+               count = len;
+
+       if (copy_to_user(buff, spike_dev.user_buff, count))  {
+               printk(KERN_ALERT "spike_read(): copy_to_user() failed\n");
+               status = -EFAULT;
+       } else {
+               *offp += count;
+               status = count;
+       }
+
+       up(&spike_dev.fop_sem);
+
+       return status;  
+}
+
+static int spike_file_open(struct inode *inode, struct file *filp)
+{      
+       int status = 0;
+
+       printk(KERN_INFO "spike_open: (%Lu)\n", filp->f_version);
+
+       if (down_interruptible(&spike_dev.fop_sem)) 
+               return -ERESTARTSYS;
+
+       if (!spike_dev.user_buff) {
+               spike_dev.user_buff = kmalloc(USER_BUFF_SIZE, GFP_KERNEL);
+               if (!spike_dev.user_buff) 
+                       status = -ENOMEM;
+       }       
+
+       if (finfo.f_version != 0) {
+               printk(KERN_INFO "spike_open: busy\n");
+               return -EBUSY;
+       }
+
+       finfo.f_version = filp->f_version;
+       finfo.sleep_mode = 0;
+       finfo.intflag = 0;
+       init_waitqueue_head(&(finfo.wait));
+       filp->private_data = (void*)&finfo;      // プライベートデータに構造体ポインタ設定
+
+//     ring_clear();
+
+       up(&spike_dev.fop_sem);
+
+       return status;
+}
+
+static int spike_file_close(struct inode * inode, struct file * file)
+{
+       printk(KERN_INFO "spike_close: (%Lu)\n",file->f_version);
+
+       ((FileInfo *)(file->private_data))->f_version = 0;
+       ((FileInfo *)(file->private_data))->sleep_mode = 0;
+       ((FileInfo *)(file->private_data))->intflag = 0;
+       return 0;
+}
+
+static unsigned int spike_file_poll(struct file *file, struct poll_table_struct *ptab)
+{
+//printk(KERN_INFO "spike_file_poll: (%ld)\n",file->f_version);
+       // 割り込み入っている
+       if ( ((FileInfo *)(file->private_data))->intflag ) {
+               // フラグクリア
+               ((FileInfo *)(file->private_data))->intflag = 0;
+//printk(KERN_INFO "spike_file_poll: (%ld) interrupted\n",file->f_version);
+               return POLLIN | POLLRDNORM;                        // 読み込みOK
+       }
+       // 割り込み入っていないので待ち行列に追加する 割り込みハンドラが起こす
+       poll_wait(file, &(((FileInfo *)(file->private_data))->wait), ptab);
+//printk(KERN_INFO "spike_file_poll: (%ld) poll_wait\n",file->f_version);
+
+       // sleep_mode=寝ている
+       ((FileInfo *)(file->private_data))->sleep_mode = 1;
+
+       return 0;
+}
+
+static long spike_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int     i;
+       unsigned char   *p;
+
+//  printk(KERN_INFO "spike_file_ioctl: (%ld)\n",file->f_version);
+       switch(cmd) {
+       // SPI送信データ長セット
+       case CMD_TX_LEN:
+               if (copy_from_user(&spi_tx_len, (void *)arg, sizeof(int))) {
+                       printk(KERN_ALERT "spike_file_ioctl(): copy_from_user() failed\n");
+                       return -EFAULT;
+               }
+               if (spi_tx_len > SPI_TX_MAX) spi_tx_len = SPI_TX_MAX;
+               return 0;
+       // SPI送信データセット
+       case CMD_TX_SET:
+               if (copy_from_user(&spitxbuf, (void *)arg, spi_tx_len)) {
+                       printk(KERN_ALERT "spike_file_ioctl(): copy_from_user() failed\n");
+                       return -EFAULT;
+               }
+               return 0;
+       // SPI受信データ返す
+       case CMD_RX_GET:
+               // リングバッファからデータ取得
+//             p = ring_get(ring_read_get());
+p = ring_buf;
+               // 読み込み位置進める
+//             ring_read_plus();
+               if (copy_to_user((void *)arg, p, SPI_DATA_SIZE)) {
+                       printk(KERN_ALERT "spike_file_ioctl(): copy_to_user() failed\n");
+                       return -EFAULT;
+               }
+               return 0;
+       // SPIで実際に受信しているデータ長を返す
+       case CMD_RECEIVED_LEN_GET:
+               i = spike_ctl.received_len;
+               if (copy_to_user((void *)arg, &i, sizeof(int))) {
+                       printk(KERN_ALERT "spike_file_ioctl(): copy_to_user() failed\n");
+                       return -EFAULT;
+               }
+               return 0;
+       // リングバッファにあるデータ数を返す
+       case CMD_DNUM_GET:
+//             i = ring_num_get();
+i = 1;
+               if (copy_to_user((void *)arg, &i, sizeof(int))) {
+                       printk(KERN_ALERT "spike_file_ioctl(): copy_to_user() failed\n");
+                       return -EFAULT;
+               }
+               return 0;
+       // リングバッファクリア
+       case CMD_BUF_CLEAR:
+//             ring_clear();
+               return 0;
+       default:
+               printk(KERN_INFO "spike_file_ioctl: unknown cmd=%d\n", cmd);
+               return 0;
+       }
+}
+
+static const struct file_operations spike_fops = {
+       .owner =        THIS_MODULE,
+//     .read =         spike_file_read,
+       .open =         spike_file_open,
+       .release =      spike_file_close,
+       .poll =         spike_file_poll,
+       .unlocked_ioctl =       spike_file_ioctl,
+};
+
+
+static int spike_probe(struct spi_device *spi_device)
+{
+       if (down_interruptible(&spike_dev.spi_sem))
+               return -EBUSY;
+
+       spike_dev.spi_device = spi_device;
+
+       up(&spike_dev.spi_sem);
+
+       return 0;
+}
+
+static int spike_remove(struct spi_device *spi_device)
+{
+       if (down_interruptible(&spike_dev.spi_sem))
+               return -EBUSY;
+       
+       spike_dev.spi_device = NULL;
+
+       up(&spike_dev.spi_sem);
+
+       return 0;
+}
+/*
+       SPIデバイスの設定
+*/
+static int __init add_spike_device_to_bus(void)
+{
+       struct spi_master *spi_master;
+       struct spi_device *spi_device;
+       struct device *pdev;
+       char buff[64];
+       int status = 0;
+
+       spi_master = spi_busnum_to_master(SPI_BUS);
+       if (!spi_master) {
+               printk(KERN_ALERT "spi_busnum_to_master(%d) returned NULL\n",
+                       SPI_BUS);
+               printk(KERN_ALERT "Missing modprobe omap2_mcspi?\n");
+               return -1;
+       }
+
+       spi_device = spi_alloc_device(spi_master);
+       if (!spi_device) {
+               put_device(&spi_master->dev);
+               printk(KERN_ALERT "spi_alloc_device() failed\n");
+               return -1;
+       }
+
+       spi_device->chip_select = SPI_BUS_CS0;
+
+       /* Check whether this SPI bus.cs is already claimed */
+       snprintf(buff, sizeof(buff), "%s.%u", 
+                       dev_name(&spi_device->master->dev),
+                       spi_device->chip_select);
+
+       pdev = bus_find_device_by_name(spi_device->dev.bus, NULL, buff);
+       if (pdev) {
+               /* We are not going to use this spi_device, so free it */ 
+               spi_dev_put(spi_device);
+               
+               /* 
+                * There is already a device configured for this bus.cs  
+                * It is okay if it us, otherwise complain and fail.
+                */
+               if (pdev->driver && pdev->driver->name && 
+                               strcmp(this_driver_name, pdev->driver->name)) {
+                       printk(KERN_ALERT 
+                               "Driver [%s] already registered for %s\n",
+                               pdev->driver->name, buff);
+                       status = -1;
+               } 
+       } else {
+               spi_device->max_speed_hz = SPI_BUS_SPEED;
+               spi_device->mode = SPI_MODE_0;
+               spi_device->bits_per_word = 8;
+               spi_device->irq = -1;
+               spi_device->controller_state = NULL;
+               spi_device->controller_data = NULL;
+               strlcpy(spi_device->modalias, this_driver_name, SPI_NAME_SIZE);
+               
+               status = spi_add_device(spi_device);            
+               if (status < 0) {       
+                       spi_dev_put(spi_device);
+                       printk(KERN_ALERT "spi_add_device() failed: %d\n", 
+                               status);                
+               }                               
+       }
+
+       put_device(&spi_master->dev);
+
+       return status;
+}
+
+static struct spi_driver spike_driver = {
+       .driver = {
+               .name = this_driver_name,
+               .owner = THIS_MODULE,
+       },
+       .probe = spike_probe,
+       .remove = __devexit_p(spike_remove),    
+};
+
+static int __init spike_init_spi(void)
+{
+       int error;
+
+       spike_ctl.tx_buff = kmalloc(SPI_BUFF_SIZE, GFP_KERNEL | GFP_DMA);
+       if (!spike_ctl.tx_buff) {
+               error = -ENOMEM;
+               goto spike_init_error;
+       }
+
+       spike_ctl.rx_buff = kmalloc(SPI_BUFF_SIZE, GFP_KERNEL | GFP_DMA);
+       if (!spike_ctl.rx_buff) {
+               error = -ENOMEM;
+               goto spike_init_error;
+       }
+
+       error = spi_register_driver(&spike_driver);
+       if (error < 0) {
+               printk(KERN_ALERT "spi_register_driver() failed %d\n", error);
+               goto spike_init_error;
+       }
+
+       error = add_spike_device_to_bus();
+       if (error < 0) {
+               printk(KERN_ALERT "add_spike_to_bus() failed\n");
+               spi_unregister_driver(&spike_driver);
+               goto spike_init_error;  
+       }
+// 一貫性のあるDMAマッピング
+/*
+spike_dev.spi_device->dev.coherent_dma_mask = 0xFFFFFFFF;
+
+spike_ctl.tx_buff = dma_alloc_coherent(&(spike_dev.spi_device->dev), SPI_BUFF_SIZE, &spike_ctl.tx_dma, GFP_ATOMIC);
+       if (!spike_ctl.tx_buff) {
+               error = -ENOMEM;
+               goto spike_init_error;
+       }
+
+//     spike_ctl.rx_buff = kmalloc(SPI_BUFF_SIZE, GFP_KERNEL | GFP_DMA);
+spike_ctl.rx_buff = dma_alloc_coherent(&(spike_dev.spi_device->dev), SPI_BUFF_SIZE, &spike_ctl.rx_dma, GFP_ATOMIC);
+       if (!spike_ctl.rx_buff) {
+               error = -ENOMEM;
+               goto spike_init_error;
+       }
+*/
+
+       return 0;
+
+spike_init_error:
+
+       if (spike_ctl.tx_buff) {
+               kfree(spike_ctl.tx_buff);
+               spike_ctl.tx_buff = 0;
+//dma_free_coherent(&(spike_dev.spi_device->dev), SPI_BUFF_SIZE, spike_ctl.tx_buff, spike_ctl.tx_dma);
+//spike_ctl.tx_dma = 0;
+       }
+
+       if (spike_ctl.rx_buff) {
+               kfree(spike_ctl.rx_buff);
+               spike_ctl.rx_buff = 0;
+//dma_free_coherent(&(spike_dev.spi_device->dev), SPI_BUFF_SIZE, spike_ctl.rx_buff, spike_ctl.rx_dma);
+//spike_ctl.rx_dma = 0;
+       }
+       
+       return error;
+}
+
+
+static int __init spike_init_cdev(void)
+{
+       int error;
+
+       spike_dev.devt = MKDEV(0, 0);
+
+       error = alloc_chrdev_region(&spike_dev.devt, 0, 1, this_driver_name);
+       if (error < 0) {
+               printk(KERN_ALERT "alloc_chrdev_region() failed: %d \n", 
+                       error);
+               return -1;
+       }
+
+       cdev_init(&spike_dev.cdev, &spike_fops);
+       spike_dev.cdev.owner = THIS_MODULE;
+       
+       error = cdev_add(&spike_dev.cdev, spike_dev.devt, 1);
+       if (error) {
+               printk(KERN_ALERT "cdev_add() failed: %d\n", error);
+               unregister_chrdev_region(spike_dev.devt, 1);
+               return -1;
+       }       
+
+       return 0;
+}
+
+static int __init spike_init_class(void)
+{
+       spike_dev.class = class_create(THIS_MODULE, this_driver_name);
+
+       if (!spike_dev.class) {
+               printk(KERN_ALERT "class_create() failed\n");
+               return -1;
+       }
+
+       if (!device_create(spike_dev.class, NULL, spike_dev.devt, NULL,         
+                       this_driver_name)) {
+               printk(KERN_ALERT "device_create(..., %s) failed\n",
+                       this_driver_name);
+               class_destroy(spike_dev.class);
+               return -1;
+       }
+
+       return 0;
+}
+int spike_init_gpio(void)
+{
+       if (gpio_request(GPIO_DRDY_IN, "GPIO_DRDY_IN")) {
+               printk(KERN_ALERT "gpio_request(GPIO_DRDY_IN) failed\n");
+               goto init_gpio_fail_1;
+       }
+
+       if (gpio_direction_input(GPIO_DRDY_IN)) {
+               printk(KERN_ALERT "gpio_direction_input(GPIO_DRDY_IN) failed\n");
+               goto init_gpio_fail_2;
+       }
+#ifdef DEBUG_TOGGLE_OUT
+       if (gpio_request(GPIO_TOGGLE_OUT, "GPIO_TOGGLE_OUT")) {
+               printk(KERN_ALERT "gpio_request(GPIO_TOGGLE_OUT) failed\n");
+               goto init_gpio_fail_2;
+       }
+
+       if (gpio_direction_output(GPIO_TOGGLE_OUT, 0)) {
+               printk(KERN_ALERT "gpio_direction_output(GPIO_TOGGLE_OUT) failed\n");
+               goto init_gpio_fail_3;
+       }
+#endif
+
+       return 0;
+
+#ifdef DEBUG_TOGGLE_OUT
+init_gpio_fail_3:
+       gpio_free(GPIO_TOGGLE_OUT);
+#endif
+
+init_gpio_fail_2:
+       gpio_free(GPIO_DRDY_IN);
+
+init_gpio_fail_1:
+
+       return -1;
+}
+void spike_free_gpio(void)
+{
+       gpio_free(GPIO_DRDY_IN);
+#ifdef DEBUG_TOGGLE_OUT
+       gpio_free(GPIO_TOGGLE_OUT);
+#endif
+}
+int spike_init_irq(void)
+{
+       int result;
+
+       irq_dev.irq = OMAP_GPIO_IRQ(GPIO_DRDY_IN);
+       result = request_irq(irq_dev.irq,
+                               irq_handler,
+                               IRQF_TRIGGER_FALLING,
+                               "spike",
+                               &irq_dev);
+
+       if (result < 0) {
+               printk(KERN_ALERT "request_irq failed: %d\n", result);
+               return -1;
+       }
+
+       return 0;
+}
+void spike_free_irq(void)
+{
+       free_irq(irq_dev.irq, &irq_dev);
+}
+
+static int __init spike_init(void)
+{
+       memset(&spike_dev, 0, sizeof(spike_dev));
+       memset(&spike_ctl, 0, sizeof(spike_ctl));
+
+       sema_init(&spike_dev.spi_sem, 1);
+       sema_init(&spike_dev.fop_sem, 1);
+       spin_lock_init(&spike_dev.spi_lock);
+
+       memset(&irq_dev, 0, sizeof(irq_dev));
+       sema_init(&irq_dev.sem, 1);
+
+       finfo.f_version = 0;            // 未使用マーク
+       spi_tx_len = 0;
+       // リングバッファ初期化
+//     ring_init();
+
+       if (spike_init_cdev() < 0) 
+               goto fail_1;
+       
+       if (spike_init_class() < 0)  
+               goto fail_2;
+
+       if (spike_init_spi() < 0) 
+               goto fail_3;
+       // DRDY GPIO144 Input config
+       if (spike_init_gpio() < 0)
+               goto fail_4;
+#if 1
+       // DRDY GPIO144 Interrupt config
+       if (spike_init_irq() < 0)
+               goto fail_5;
+#endif
+
+       printk(KERN_INFO "%s %s initialized\n", MODULE_NAME, VERSION);
+       return 0;
+
+fail_5:
+       spike_free_gpio();
+
+fail_4:
+       if (spike_ctl.tx_buff)
+               kfree(spike_ctl.tx_buff);
+       if (spike_ctl.rx_buff)
+               kfree(spike_ctl.rx_buff);
+
+fail_3:
+       device_destroy(spike_dev.class, spike_dev.devt);
+       class_destroy(spike_dev.class);
+
+fail_2:
+       cdev_del(&spike_dev.cdev);
+       unregister_chrdev_region(spike_dev.devt, 1);
+
+fail_1:
+       return -1;
+}
+module_init(spike_init);
+
+static void __exit spike_exit(void)
+{
+       spi_unregister_device(spike_dev.spi_device);
+       spi_unregister_driver(&spike_driver);
+
+#if 1
+       spike_free_irq();
+#endif
+       spike_free_gpio();
+
+       device_destroy(spike_dev.class, spike_dev.devt);
+       class_destroy(spike_dev.class);
+
+       cdev_del(&spike_dev.cdev);
+       unregister_chrdev_region(spike_dev.devt, 1);
+
+       if (spike_ctl.tx_buff)
+               kfree(spike_ctl.tx_buff);
+//dma_free_coherent(&(spike_dev.spi_device->dev), SPI_BUFF_SIZE, spike_ctl.tx_buff, spike_ctl.tx_dma);
+
+       if (spike_ctl.rx_buff)
+               kfree(spike_ctl.rx_buff);
+//dma_free_coherent(&(spike_dev.spi_device->dev), SPI_BUFF_SIZE, spike_ctl.rx_buff, spike_ctl.rx_dma);
+
+       if (spike_dev.user_buff)
+               kfree(spike_dev.user_buff);
+
+       printk(KERN_INFO "%s %s removed\n", MODULE_NAME, VERSION);
+}
+module_exit(spike_exit);
+
+MODULE_AUTHOR("Naoya Takamura");
+MODULE_DESCRIPTION("sciLog AD SPI driver based on spike");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
diff --git a/spike-ad.h b/spike-ad.h
new file mode 100644 (file)
index 0000000..a8345c0
--- /dev/null
@@ -0,0 +1,19 @@
+\r
+// SPI受信データ取得\r
+#define        CMD_RX_GET      11\r
+\r
+\r
+// SPI送信データ長セット\r
+#define        CMD_TX_LEN      12\r
+// SPI送信データセット\r
+#define        CMD_TX_SET      13\r
+\r
+\r
+// リングバッファにあるデータ数を返す\r
+#define        CMD_DNUM_GET    14\r
+\r
+// リングバッファクリア\r
+#define        CMD_BUF_CLEAR   15\r
+\r
+// SPIで実際に受信したデータ長を取得\r
+#define        CMD_RECEIVED_LEN_GET    20\r