diff options
author | Denys Dmytriyenko <denis@denix.org> | 2009-03-17 14:32:59 -0400 |
---|---|---|
committer | Denys Dmytriyenko <denis@denix.org> | 2009-03-17 14:32:59 -0400 |
commit | 709c4d66e0b107ca606941b988bad717c0b45d9b (patch) | |
tree | 37ee08b1eb308f3b2b6426d5793545c38396b838 /packages/linux/linux-davinci/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch | |
parent | fa6cd5a3b993f16c27de4ff82b42684516d433ba (diff) |
rename packages/ to recipes/ per earlier agreement
See links below for more details:
http://thread.gmane.org/gmane.comp.handhelds.openembedded/21326
http://thread.gmane.org/gmane.comp.handhelds.openembedded/21816
Signed-off-by: Denys Dmytriyenko <denis@denix.org>
Acked-by: Mike Westerhof <mwester@dls.net>
Acked-by: Philip Balister <philip@balister.org>
Acked-by: Khem Raj <raj.khem@gmail.com>
Acked-by: Marcin Juszkiewicz <hrw@openembedded.org>
Acked-by: Koen Kooi <koen@openembedded.org>
Acked-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
Diffstat (limited to 'packages/linux/linux-davinci/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch')
-rw-r--r-- | packages/linux/linux-davinci/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch | 1512 |
1 files changed, 0 insertions, 1512 deletions
diff --git a/packages/linux/linux-davinci/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch b/packages/linux/linux-davinci/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch deleted file mode 100644 index 0e034f609a..0000000000 --- a/packages/linux/linux-davinci/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch +++ /dev/null @@ -1,1512 +0,0 @@ -From 500b0887632165f77f2604b07df746b4a3a16d2c Mon Sep 17 00:00:00 2001 -From: Hugo Villeneuve <hugo@hugovil.com> -Date: Fri, 6 Mar 2009 10:23:44 -0500 -Subject: [PATCH 10/12] Add generic FPGA bitstream loader driver - -This driver is a generic interface for programming a -bitstream into a FPGA. It can work with serial or -parallel programming interfaces and support multiple -devices and partial reconfiguration. Currently Xilinx -XC3S and XC4V FPGAs are implemented, but other -manufacturers like Altera could be easily added. - -Signed-off-by: Hugo Villeneuve <hugo@hugovil.com> ---- - drivers/misc/Kconfig | 31 ++ - drivers/misc/Makefile | 3 + - drivers/misc/fpgadl.c | 806 +++++++++++++++++++++++++++++++++++++++++++++ - drivers/misc/fpgadl_par.c | 258 +++++++++++++++ - drivers/misc/fpgadl_ser.c | 244 ++++++++++++++ - include/linux/fpgadl.h | 96 ++++++ - 6 files changed, 1438 insertions(+), 0 deletions(-) - create mode 100644 drivers/misc/fpgadl.c - create mode 100644 drivers/misc/fpgadl_par.c - create mode 100644 drivers/misc/fpgadl_ser.c - create mode 100644 include/linux/fpgadl.h - -diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index a11e2a0..bdc0517 100644 ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -510,6 +510,37 @@ config SGI_GRU_DEBUG - This option enables addition debugging code for the SGI GRU driver. If - you are unsure, say N. - -+config FPGADL -+ tristate "FPGA bitstream loader support" -+ help -+ This option enables support for the FPGA bitstream loader. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called fpgadl. -+ -+ If unsure, say N. -+ -+config FPGADL_SER -+ tristate "FPGA serial programming driver" -+ depends on SPI_MASTER && FPGADL -+ help -+ Say Y here if your FPGA bitstream is loaded using a serial -+ interface (SPI). -+ -+ To compile this driver as a module, choose M here: the -+ module will be called fpgadl_ser. -+ -+config FPGADL_PAR -+ tristate "FPGA parallel programming driver" -+ depends on FPGADL -+ select BITREVERSE -+ help -+ Say Y here if your FPGA bitstream is loaded using a parallel -+ interface. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called fpgadl_par. -+ - source "drivers/misc/c2port/Kconfig" - - endif # MISC_DEVICES -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 78be134..4fb6dfc 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -32,5 +32,8 @@ obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o - obj-$(CONFIG_KGDB_TESTS) += kgdbts.o - obj-$(CONFIG_SGI_XP) += sgi-xp/ - obj-$(CONFIG_SGI_GRU) += sgi-gru/ -+obj-$(CONFIG_FPGADL) += fpgadl.o -+obj-$(CONFIG_FPGADL_SER) += fpgadl_ser.o -+obj-$(CONFIG_FPGADL_PAR) += fpgadl_par.o - obj-$(CONFIG_HP_ILO) += hpilo.o - obj-$(CONFIG_C2PORT) += c2port/ -diff --git a/drivers/misc/fpgadl.c b/drivers/misc/fpgadl.c -new file mode 100644 -index 0000000..2f03d9b ---- /dev/null -+++ b/drivers/misc/fpgadl.c -@@ -0,0 +1,806 @@ -+/* -+ * fpgadl core driver -+ * -+ * Copyright (C) 2008 Lyrtech <www.lyrtech.com> -+ * -+ * Based on code found in book "Linux Device Drivers" by -+ * Alessandro Rubini and Jonathan Corbet, published by O'Reilly & Associates. -+ * -+ * 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/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/miscdevice.h> -+#include <linux/string.h> -+#include <linux/err.h> -+#include <linux/fs.h> -+#include <linux/firmware.h> -+#include <linux/delay.h> -+#include <linux/fpgadl.h> -+ -+#include <asm/gpio.h> -+#include <asm/uaccess.h> -+ -+#define MODULE_NAME "fpgadl" -+ -+/* Define this to enable verbose debug messages */ -+#define FPGADL_DEBUG 1 -+ -+static const char fpgadl_driver_version[] = "v1.0"; -+ -+/* Module parameters */ -+static unsigned int fpgadl_debug; -+EXPORT_SYMBOL_GPL(fpgadl_debug); -+module_param_named(debug, fpgadl_debug, int, 0644); -+ -+#ifdef FPGADL_DEBUG -+#define INFOMSG(fmt, args...) \ -+ do { \ -+ printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ## args); \ -+ } while (0) -+#define DBGMSG(fmt, args...) \ -+ do { \ -+ if (fpgadl_debug > 0) \ -+ printk(KERN_DEBUG "%s: "fmt"\n", \ -+ MODULE_NAME, ## args); \ -+ } while (0) -+#define DBGMSG_ENTER() \ -+ DBGMSG("%s() enter", __func__); -+#define DBGMSG_LEAVE() \ -+ DBGMSG("%s() leave", __func__); -+#else -+#define INFOMSG(fmt, args...) do {} while (0) -+#define DBGMSG(fmt, args...) do {} while (0) -+#define DBGMSG_ENTER() do {} while (0) -+#define DBGMSG_LEAVE() do {} while (0) -+#endif -+ -+#define FAILMSG(fmt, args...) \ -+ do { \ -+ printk(KERN_ERR "%s: "fmt"\n", MODULE_NAME, ## args); \ -+ } while (0) -+ -+#define FPGA_WAIT_TIMEOUT 100000 -+#define XFER_SIZE 100 /* Transfer size when writing bytes to -+ * device. */ -+ -+#define BITSTREAM_MAX_SIZE_OVERHEAD 10240 -+ -+#define XC3S_WORD_SIZE 2 -+#define XC4V_WORD_SIZE 4 -+ -+#define BITSTREAM_SYNC_BYTE1 0xAA -+#define BITSTREAM_SYNC_BYTE2 0x99 -+#define BITSTREAM_SYNC_BYTE3 0x55 -+#define BITSTREAM_SYNC_BYTE4 0x66 -+ -+#define BITSTREAM_PACKET_HEADER_TYPE1 1 -+#define BITSTREAM_PACKET_HEADER_TYPE2 2 -+#define BITSTREAM_TYPE1_OPCODE_WRITE 2 -+#define BITSTREAM_TYPE1_REG_ADDR_FDRI 2 -+ -+/* Structure of a TYPE1 packet. */ -+struct t1_pkt_xc4v_t { -+ u32 word_count:11; -+ u32 reserved2:2; -+ u32 address:5; -+ u32 reserved1:9; -+ u32 opcode:2; -+ u32 header:3; -+}; -+ -+struct t1_pkt_xc3s_t { -+ u16 word_count:5; -+ u16 address:6; -+ u16 opcode:2; -+ u16 header:3; /* type */ -+}; -+ -+/* Structure of a TYPE2 packet. */ -+struct t2_pkt_xc4v_t { -+ u32 word_count:27; -+ u32 opcode:2; /* Reserved. */ -+ u32 header:3; -+}; -+ -+struct t2_pkt_xc3s_t { -+ u16 word_count:11; -+ u16 opcode:2; /* Reserved. */ -+ u16 header:3; -+}; -+ -+#define MAX_FPGADL_DEV 4 -+ -+static int fpgadl_dev_count; -+static struct fpgadl_device *fpgadl_dev_array[MAX_FPGADL_DEV]; -+ -+int fpgadl_is_bitstream_loaded(const char *name) -+{ -+ int k; -+ struct fpgadl_device *fpgadl_dev; -+ -+ DBGMSG_ENTER(); -+ -+ for (k = 0; k < MAX_FPGADL_DEV; k++) { -+ fpgadl_dev = fpgadl_dev_array[k]; -+ if (fpgadl_dev) -+ if (strncmp(fpgadl_dev->name, name, strlen(name)) == 0) -+ return fpgadl_dev->bitstream_loaded; -+ } -+ -+ FAILMSG(" Device <%s> not found", name); -+ return -ENOMEM; -+} -+EXPORT_SYMBOL(fpgadl_is_bitstream_loaded); -+ -+/* Respond to hotplug events. */ -+static int fpgadl_uevent(struct device *dev, struct kobj_uevent_env *env) -+{ -+ DBGMSG_ENTER(); -+ -+ if (add_uevent_var(env, "FPGADL_BUS_VERSION=%s", fpgadl_driver_version)) -+ return -ENOMEM; -+ return 0; -+}; -+ -+/* -+ * Toggles the CCLK line on the board-specific interface the number of times -+ * specified by <cycles>. -+ */ -+static int bitstr_load_make_clock(struct fpgadl_device *fpgadl_dev, -+ int cycles) -+{ -+ int retval; -+ int k; -+ u8 dummy = 0; -+ -+ for (k = 0; k < cycles; k++) { -+ retval = fpgadl_dev->write_byte(fpgadl_dev, &dummy, 1); -+ if (retval < 0) -+ return retval; -+ } -+ -+ return 0; -+} -+ -+/* Search for bitstream sync word. */ -+static int bitstr_search_sync_word(const u8 *buffer, size_t length, -+ const u8 *sync_word, ssize_t sync_word_size) -+{ -+ int k; -+ -+ for (k = 0; k < length; k++, buffer++) { -+ if (memcmp(buffer, sync_word, sync_word_size) == 0) { -+ DBGMSG(" Synchronization word found at offset 0x%02X", -+ k); -+ return k; -+ } -+ } -+ -+ return 0; -+} -+ -+static int bitstr_get_payload_size(int fpga_family, int sws, -+ const u8 *buffer, ssize_t length) -+{ -+ int index = 0; -+ -+ /* Find the payload size. */ -+ while (index < length) { -+ switch (fpga_family) { -+ case FPGA_FAMILY_XILINX_XC4V: -+ { -+ u32 tmp = ntohl(*((u32 *) &buffer[index])); -+ struct t1_pkt_xc4v_t *t1 = -+ (struct t1_pkt_xc4v_t *) &tmp; -+ -+ /* Search for type 1 packet header. */ -+ if ((t1->header == BITSTREAM_PACKET_HEADER_TYPE1) && -+ (t1->opcode == BITSTREAM_TYPE1_OPCODE_WRITE) && -+ (t1->address == BITSTREAM_TYPE1_REG_ADDR_FDRI)) { -+ if (t1->word_count != 0) -+ return t1->word_count; -+ else { -+ struct t2_pkt_xc4v_t *t2; -+ -+ tmp = ntohl(*((u32 *) -+ &buffer[index + sws])); -+ t2 = (struct t2_pkt_xc4v_t *) &tmp; -+ -+ /* Search for type 2 packet header just -+ * after type1 packet. */ -+ if ((t2->header == -+ BITSTREAM_PACKET_HEADER_TYPE2)) -+ return t2->word_count; -+ } -+ } -+ } -+ break; -+ case FPGA_FAMILY_XILINX_XC3S: -+ { -+ u16 tmp = ntohs(*((u16 *) &buffer[index])); -+ struct t2_pkt_xc3s_t *t2 = -+ (struct t2_pkt_xc3s_t *) &tmp; -+ -+ /* Search for type 2 packet header just after -+ * type1 packet. */ -+ if ((t2->header == BITSTREAM_PACKET_HEADER_TYPE2)) { -+ DBGMSG(" Type 2 packet found at offset $%02X", -+ index); -+ return ntohl(*((u32 *) &buffer[index + sws])); -+ } -+ /* Word-size aligned when sync word has been found. */ -+ index += sws; -+ } -+ break; -+ } -+ -+ /* Word-size aligned when sync word has been found. */ -+ index += sws; -+ } -+ -+ return 0; /* Not found */ -+} -+ -+/* -+ * Return value: -+ * 0: Error -+ * 1: Full bitstream -+ * 2: Partial bitstream -+ */ -+static int bitstream_parse_header(const u8 *buffer, size_t length, -+ int fpga_family, size_t payload_full_size) -+{ -+ int index = 0; -+ size_t payload_size = 0; -+ u8 sync_word[] = { -+ BITSTREAM_SYNC_BYTE1, -+ BITSTREAM_SYNC_BYTE2, -+ BITSTREAM_SYNC_BYTE3, -+ BITSTREAM_SYNC_BYTE4, -+ }; -+ int sync_word_size; /* Size in bytes */ -+ -+ switch (fpga_family) { -+ case FPGA_FAMILY_XILINX_XC3S: -+ sync_word_size = XC3S_WORD_SIZE; -+ break; -+ case FPGA_FAMILY_XILINX_XC4V: -+ sync_word_size = XC4V_WORD_SIZE; -+ break; -+ default: -+ FAILMSG("Error, invalid FPGA family number"); -+ return BITSTREAM_MODE_UNKNOWN; -+ } -+ -+ /* Search for bitstream sync word. */ -+ index = bitstr_search_sync_word(buffer, length, -+ sync_word, sync_word_size); -+ if (index == 0) { -+ FAILMSG("Error: Synchronization word not found"); -+ return BITSTREAM_MODE_UNKNOWN; -+ } -+ -+ /* Get payload size. */ -+ payload_size = bitstr_get_payload_size(fpga_family, sync_word_size, -+ &buffer[index], length - index); -+ payload_size *= sync_word_size; /* Length in bytes. */ -+ -+ if (payload_size == 0) { -+ /* Warning only, assuming FULL bitstream. */ -+ DBGMSG(" Warning: payload size not found"); -+ return BITSTREAM_MODE_FULL; -+ } else { -+ DBGMSG(" Payload size: %d kb", payload_size / 1024); -+ -+ /* Is it a full or a partial bitstream? */ -+ if (payload_size == payload_full_size) -+ return BITSTREAM_MODE_FULL; -+ else -+ return BITSTREAM_MODE_PARTIAL; -+ } -+} -+ -+/* -+ * Bitstreams supported: Full or Partial. -+ * Note: Full bitstream that supports partial bitstream must be generated with -+ * option "Persist = true" in ISE. -+ */ -+static int fpgadl_bitstream_load(struct fpgadl_device *fpgadl_dev, -+ const u8 *data, size_t size) -+{ -+ int k; -+ int retval; -+ int timeout_counter; -+ -+ fpgadl_dev->bitstream_loaded = 0; -+ -+ fpgadl_dev->bitstream_mode = -+ bitstream_parse_header(data, size, -+ fpgadl_dev->pdata->fpga_family, -+ fpgadl_dev->pdata->payload_full_size); -+ switch (fpgadl_dev->bitstream_mode) { -+ case BITSTREAM_MODE_FULL: -+ DBGMSG(" Bitstream type: FULL"); -+ /* Toggle PROG_B Pin and wait 300nS before proceeding. */ -+ gpio_set_value(fpgadl_dev->pdata->program_b, 0); -+ udelay(1); -+ -+ /* Confirm that INIT_B is low */ -+ if (gpio_get_value(fpgadl_dev->pdata->init_b) != 0) { -+ FAILMSG("Error: INIT_B not LOW when PROG is LOW"); -+ return -EIO; -+ } -+ -+ break; -+ case BITSTREAM_MODE_PARTIAL: -+ DBGMSG(" Bitstream type: PARTIAL"); -+ break; -+ case BITSTREAM_MODE_UNKNOWN: -+ default: -+ FAILMSG(" Bitstream type: UNKNOWN"); -+ return -EINVAL; -+ break; -+ } -+ -+ /* For partial bitstream, PROGRAM_B is already high. */ -+ retval = bitstr_load_make_clock(fpgadl_dev, 3); -+ if (retval < 0) -+ return retval; -+ -+ gpio_set_value(fpgadl_dev->pdata->program_b, 1); -+ -+ /* Wait for INIT_B pin to go high. */ -+ timeout_counter = 0; -+ while ((gpio_get_value(fpgadl_dev->pdata->init_b) == 0) && -+ (timeout_counter < FPGA_WAIT_TIMEOUT)) { -+ retval = bitstr_load_make_clock(fpgadl_dev, 3); -+ if (retval < 0) -+ return retval; -+ -+ timeout_counter++; -+ } -+ -+ if (timeout_counter == FPGA_WAIT_TIMEOUT) { -+ /* Timeout error. */ -+ FAILMSG("Error: timeout while waiting for INIT_B to go HIGH"); -+ return -EIO; -+ } -+ -+ /* Send actual bitstream data to FPGA one byte at a time. */ -+ for (k = 0; k < size; k += XFER_SIZE) { -+ retval = fpgadl_dev->write_byte(fpgadl_dev, -+ (u8 *) &data[k], XFER_SIZE); -+ if (retval < 0) -+ return retval; -+ -+ if (fpgadl_dev->pdata->check_init_low) { -+ if (gpio_get_value(fpgadl_dev->pdata->init_b) == 0) { -+ /* Error if INIT_B goes low here. */ -+ FAILMSG("Error: INIT_B LOW during programming"); -+ return -EIO; -+ } -+ } -+ } -+ -+ /* Pulse the clock line ten times at the end. */ -+ retval = bitstr_load_make_clock(fpgadl_dev, 10); -+ if (retval < 0) -+ return retval; -+ -+ /* FPGA DONE pin must go high. */ -+ timeout_counter = 0; -+ while ((gpio_get_value(fpgadl_dev->pdata->done) == 0) && -+ (timeout_counter < FPGA_WAIT_TIMEOUT)) -+ timeout_counter++; -+ -+ if (gpio_get_value(fpgadl_dev->pdata->done) == 0) { -+ /* Timeout error. */ -+ FAILMSG("Error: timeout while waiting for DONE to go HIGH"); -+ return -EIO; -+ } -+ -+ INFOMSG("Bitstream loaded"); -+ fpgadl_dev->bitstream_loaded = 1; -+ -+ return 0; -+} -+ -+/* Open method. */ -+static int fpgadl_open(struct inode *inode, struct file *filp) -+{ -+ int k; -+ int found = 0; -+ struct fpgadl_device *fpgadl_dev; -+ -+ DBGMSG_ENTER(); -+ DBGMSG(" Opening device minor %d", MINOR(inode->i_rdev)); -+ -+ for (k = 0; k < fpgadl_dev_count; k++) { -+ fpgadl_dev = fpgadl_dev_array[k]; -+ if (fpgadl_dev) { -+ if (fpgadl_dev->miscdev.minor == MINOR(inode->i_rdev)) { -+ found = 1; -+ break; -+ } -+ } -+ } -+ -+ if (!found) { -+ FAILMSG(" Invalid minor device"); -+ return -ENOMEM; -+ } -+ -+ filp->private_data = fpgadl_dev; -+ -+ fpgadl_dev->bitstream_length = 0; -+ fpgadl_dev->bitstream_data = kmalloc(fpgadl_dev->bitstream_max_size, -+ GFP_KERNEL); -+ if (!fpgadl_dev->bitstream_data) { -+ FAILMSG("Failed to allocate memory for bitstream"); -+ return -ENOMEM; -+ } -+ -+ fpgadl_dev->bitstream_buffer_allocated = 1; -+ -+ return 0; -+} -+ -+/* Write method. Fill buffer with bitstream data. */ -+static ssize_t fpgadl_write(struct file *filp, const char __user *buff, -+ size_t count, loff_t *offp) -+{ -+ struct fpgadl_device *fpgadl_dev = filp->private_data; -+ -+ if ((fpgadl_dev->bitstream_length + count) >= -+ fpgadl_dev->bitstream_max_size) { -+ FAILMSG("Bitstream buffer size exceeded"); -+ return -EFBIG; -+ } -+ -+ if (copy_from_user(fpgadl_dev->bitstream_data + -+ fpgadl_dev->bitstream_length, -+ (void __user *) buff, count)) -+ return -EFAULT; -+ -+ fpgadl_dev->bitstream_length += count; -+ -+ return count; -+} -+ -+/* Release method. This will initiate the FPGA programming. */ -+static int fpgadl_release(struct inode *inode, struct file *filp) -+{ -+ int retval; -+ struct fpgadl_device *fpgadl_dev = filp->private_data; -+ -+ if (!fpgadl_dev->bitstream_data) -+ return -EFAULT; -+ -+ retval = fpgadl_bitstream_load(fpgadl_dev, -+ fpgadl_dev->bitstream_data, -+ fpgadl_dev->bitstream_length); -+ kfree(fpgadl_dev->bitstream_data); -+ fpgadl_dev->bitstream_buffer_allocated = 0; -+ -+ return retval; -+} -+ -+static struct file_operations fops_fpgadl = { -+ .owner = THIS_MODULE, -+ .open = fpgadl_open, -+ .write = fpgadl_write, -+ .release = fpgadl_release -+}; -+ -+/* Match fpgadl devices to drivers. Just do a simple name test. */ -+static int fpgadl_device_match(struct device *dev, -+ struct device_driver *drv) -+{ -+ DBGMSG_ENTER(); -+ return !strncmp(dev->bus_id, drv->name, strlen(drv->name)); -+} -+ -+static ssize_t show_version(struct device_driver *driver, char *buf) -+{ -+ struct fpgadl_driver *fpgadldriver = to_fpgadl_driver(driver); -+ -+ sprintf(buf, "%s\n", fpgadldriver->version); -+ return strlen(buf); -+} -+ -+int fpgadl_register_driver(struct fpgadl_driver *drv) -+{ -+ int res; -+ -+ DBGMSG_ENTER(); -+ -+ /* Initialize common driver fields */ -+ drv->driver.bus = &fpgadl_bus_type; -+ -+ /* Register with core */ -+ res = driver_register(&drv->driver); -+ if (res) -+ FAILMSG(" driver_register() failed"); -+ -+ drv->version_attr.attr.name = "version"; -+ drv->version_attr.attr.owner = drv->module; -+ drv->version_attr.attr.mode = S_IRUGO; -+ drv->version_attr.show = show_version; -+ drv->version_attr.store = NULL; -+ res = driver_create_file(&drv->driver, &drv->version_attr); -+ -+ return res; -+} -+EXPORT_SYMBOL(fpgadl_register_driver); -+ -+void fpgadl_unregister_driver(struct fpgadl_driver *drv) -+{ -+ DBGMSG_ENTER(); -+ driver_unregister(&drv->driver); -+} -+EXPORT_SYMBOL(fpgadl_unregister_driver); -+ -+/* The fpgadl bus device. */ -+static void fpgadl_bus_release(struct device *dev) -+{ -+ DBGMSG_ENTER(); -+} -+ -+struct device fpgadl_bus = { -+ .bus_id = "fpgadl0", -+ .release = fpgadl_bus_release -+}; -+ -+struct bus_type fpgadl_bus_type = { -+ .name = "fpgadl", -+ .match = fpgadl_device_match, -+ .uevent = fpgadl_uevent, -+}; -+EXPORT_SYMBOL(fpgadl_bus_type); -+ -+/* Export a simple sysfs attribute. */ -+static ssize_t show_bus_version(struct bus_type *bus, char *buf) -+{ -+ return snprintf(buf, PAGE_SIZE, "%s\n", fpgadl_driver_version); -+} -+ -+static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); -+ -+/* -+ * fpgadl devices. -+ * For now, no references to fpgadlbus devices go out which are not -+ * tracked via the module reference count, so we use a no-op -+ * release function. -+ */ -+static void fpgadl_dev_release(struct device *dev) -+{ -+ DBGMSG_ENTER(); -+} -+ -+/* Release DaVinci GPIO to FPGA control pins. */ -+static void fpgadl_release_gpio(struct fpgadl_pdata_t *pdata) -+{ -+ gpio_free(pdata->done); -+ gpio_free(pdata->init_b); -+ gpio_free(pdata->program_b); -+} -+ -+static int fpgadl_setup_gpio(struct fpgadl_pdata_t *pdata) -+{ -+ int retval; -+ -+ /* Configure FPGA PROGRAM_B GPIO. */ -+ retval = gpio_request(pdata->program_b, "fpga_program_b"); -+ if (retval == 0) /* FPGA_PROGRAM_B must be initially HIGH. */ -+ retval = gpio_direction_output(pdata->program_b, 1); -+ if (retval != 0) -+ goto gpio_error; -+ -+ /* Configure FPGA INIT_B GPIO. */ -+ retval = gpio_request(pdata->init_b, "fpga_init_b"); -+ if (retval == 0) -+ retval = gpio_direction_input(pdata->init_b); -+ if (retval != 0) -+ goto gpio_error; -+ -+ /* Configure FPGA DONE GPIO. */ -+ retval = gpio_request(pdata->done, "fpga_done"); -+ if (retval == 0) -+ retval = gpio_direction_input(pdata->done); -+ if (retval != 0) -+ goto gpio_error; -+ -+ return 0; -+ -+gpio_error: -+ fpgadl_release_gpio(pdata); -+ return retval; -+} -+ -+static void fpgadl_cleanup(struct fpgadl_device *fpgadl_dev) -+{ -+ DBGMSG_ENTER(); -+ -+ if (!fpgadl_dev) -+ return; -+ -+ fpgadl_dev_array[fpgadl_dev->id] = NULL; -+ -+ /* Get rid of any allocated buffer, not freed */ -+ if (fpgadl_dev->bitstream_buffer_allocated) -+ kfree(fpgadl_dev->bitstream_data); -+ -+ switch (fpgadl_dev->state) { -+ case FPGADL_DEV_STATE_CHAR_DEV_REGISTERED: -+ misc_deregister(&fpgadl_dev->miscdev); -+ case FPGADL_DEV_STATE_GPIO_REGISTERED: -+ fpgadl_release_gpio(fpgadl_dev->pdata); -+ case FPGADL_DEV_STATE_DEVICE_REGISTERED: -+ device_unregister(&fpgadl_dev->dev); -+ case FPGADL_DEV_STATE_START: -+ break; -+ } -+} -+ -+int fpgadl_register_device(struct fpgadl_device *fpgadl_dev) -+{ -+ int res; -+ const struct firmware *fw_entry; -+ -+ DBGMSG_ENTER(); -+ -+ fpgadl_dev->state = FPGADL_DEV_STATE_START; -+ -+ /* Sanity checks. */ -+ if (!fpgadl_dev->name) { -+ FAILMSG(" Error, missing device name"); -+ res = -EFAULT; -+ goto error; -+ } -+ -+ if (!fpgadl_dev->write_byte) { -+ FAILMSG(" Error, missing write_byte() callback"); -+ res = -ENOMEM; -+ goto error; -+ } -+ -+ if (fpgadl_dev_count == MAX_FPGADL_DEV) { -+ FAILMSG("Maximum number of devices reached (%d)", -+ fpgadl_dev_count); -+ res = -ENODEV; -+ goto error; -+ } -+ -+ DBGMSG(" device %d", fpgadl_dev_count); -+ -+ /* Set some default values. */ -+ fpgadl_dev->bitstream_loaded = 0; -+ fpgadl_dev->bitstream_buffer_allocated = 0; -+ fpgadl_dev->bitstream_max_size = -+ fpgadl_dev->pdata->payload_full_size + -+ BITSTREAM_MAX_SIZE_OVERHEAD; -+ -+ fpgadl_dev->dev.bus = &fpgadl_bus_type; -+ fpgadl_dev->dev.parent = &fpgadl_bus; -+ fpgadl_dev->dev.release = fpgadl_dev_release; -+ strncpy(fpgadl_dev->dev.bus_id, fpgadl_dev->name, BUS_ID_SIZE); -+ res = device_register(&fpgadl_dev->dev); -+ if (res) { -+ FAILMSG(" device_register() failed"); -+ goto error; -+ } -+ fpgadl_dev->state = FPGADL_DEV_STATE_DEVICE_REGISTERED; -+ -+ res = fpgadl_setup_gpio(fpgadl_dev->pdata); -+ if (res < 0) { -+ FAILMSG("Error registering GPIOs"); -+ goto error; -+ } -+ fpgadl_dev->state = FPGADL_DEV_STATE_GPIO_REGISTERED; -+ -+ fpgadl_dev->miscdev.name = fpgadl_dev->name; -+ fpgadl_dev->miscdev.minor = MISC_DYNAMIC_MINOR; -+ fpgadl_dev->miscdev.fops = &fops_fpgadl; -+ res = misc_register(&fpgadl_dev->miscdev); -+ if (res < 0) { -+ FAILMSG("Error registering misc driver"); -+ goto error; -+ } -+ DBGMSG(" MINOR = %d", fpgadl_dev->miscdev.minor); -+ fpgadl_dev->state = FPGADL_DEV_STATE_CHAR_DEV_REGISTERED; -+ -+ /* Try to load firmware through hotplug if available. */ -+ res = request_firmware(&fw_entry, fpgadl_dev->pdata->bitstream_name, -+ &fpgadl_dev->dev); -+ if (res < 0) { -+ /* Not an error preventing the driver from being loaded. */ -+ res = 0; -+ DBGMSG("Info: firmware not available"); -+ } else { -+ res = fpgadl_bitstream_load(fpgadl_dev, fw_entry->data, -+ fw_entry->size); -+ release_firmware(fw_entry); -+ } -+ -+ fpgadl_dev->id = fpgadl_dev_count; -+ fpgadl_dev_array[fpgadl_dev_count] = fpgadl_dev; -+ fpgadl_dev_count++; -+ -+ return 0; -+ -+error: -+ fpgadl_cleanup(fpgadl_dev); -+ return res; -+} -+EXPORT_SYMBOL(fpgadl_register_device); -+ -+void fpgadl_unregister_device(struct fpgadl_device *fpgadl_dev) -+{ -+ DBGMSG_ENTER(); -+ fpgadl_cleanup(fpgadl_dev); -+} -+EXPORT_SYMBOL(fpgadl_unregister_device); -+ -+static int __init fpgadl_init(void) -+{ -+ int res; -+ -+ DBGMSG_ENTER(); -+ INFOMSG("FPGA bitstream loader %s", fpgadl_driver_version); -+ -+ res = bus_register(&fpgadl_bus_type); -+ if (res) { -+ FAILMSG(" bus_register() failed"); -+ goto fail_bus; -+ } -+ -+ if (bus_create_file(&fpgadl_bus_type, &bus_attr_version)) { -+ FAILMSG("Unable to create version attribute"); -+ goto fail_create_file; -+ } -+ -+ res = device_register(&fpgadl_bus); -+ if (res) { -+ FAILMSG(" failed registering %s", fpgadl_bus.bus_id); -+ goto fail_dev_reg; -+ } -+ -+ return 0; -+ -+fail_dev_reg: -+fail_create_file: -+ bus_unregister(&fpgadl_bus_type); -+fail_bus: -+ return res; -+} -+module_init(fpgadl_init); -+ -+static void __exit fpgadl_exit(void) -+{ -+ DBGMSG_ENTER(); -+ device_unregister(&fpgadl_bus); -+ bus_unregister(&fpgadl_bus_type); -+} -+module_exit(fpgadl_exit); -+ -+MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@lyrtech.com>"); -+MODULE_DESCRIPTION("FPGA bitstream loader"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/misc/fpgadl_par.c b/drivers/misc/fpgadl_par.c -new file mode 100644 -index 0000000..66f8eba ---- /dev/null -+++ b/drivers/misc/fpgadl_par.c -@@ -0,0 +1,258 @@ -+/* -+ * fpgadl_par.c - FPGA parallel programming driver -+ * -+ * Copyright (C) 2008 Lyrtech <www.lyrtech.com> -+ * -+ * 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/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/string.h> -+#include <linux/err.h> -+#include <linux/fs.h> -+#include <linux/delay.h> -+#include <linux/bitrev.h> -+#include <linux/fpgadl.h> -+ -+#include <asm/gpio.h> /* For ioremap() */ -+ -+#define MODULE_NAME "fpgadl_par" -+#define MODULE_VERSION_STR "v1.0" -+ -+/* Define this to enable verbose debug messages */ -+#define FPGADL_PAR_DEBUG 1 -+ -+/* Module parameters */ -+static unsigned int fpgadl_par_debug; -+EXPORT_SYMBOL_GPL(fpgadl_par_debug); -+module_param_named(debug, fpgadl_par_debug, int, 0644); -+ -+#ifdef FPGADL_PAR_DEBUG -+#define INFOMSG(fmt, args...) \ -+do { \ -+ printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) -+#define DBGMSG(fmt, args...) \ -+do { if (fpgadl_par_debug > 0) \ -+ printk(KERN_DEBUG "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) -+#define DBGMSG_ENTER() \ -+ DBGMSG("%s() enter", __func__); -+#define DBGMSG_LEAVE() \ -+ DBGMSG("%s() leave", __func__); -+#else -+#define INFOMSG(fmt, args...) do {} while (0) -+#define DBGMSG(fmt, args...) do {} while (0) -+#define DBGMSG_ENTER() do {} while (0) -+#define DBGMSG_LEAVE() do {} while (0) -+#endif -+ -+#define FAILMSG(fmt, args...) \ -+do { \ -+ printk(KERN_ERR "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) -+ -+struct fpgadl_par_dev_t { -+ char devname[32]; -+ enum { -+ FPGADL_PAR_DEV_STATE_STRUCT_ALLOCATED, -+ FPGADL_PAR_DEV_STATE_HAVE_IOREMAP, -+ FPGADL_PAR_DEV_STATE_FPGADL_DEV_REGISTERED, -+ } state; -+ u8 *selectmap; -+ struct fpgadl_device fpgadl_dev; -+}; -+ -+#define MAX_FPGADL_PAR_DEV 5 -+ -+static int fpgadl_par_dev_count; -+ -+/* -+ * Writes a byte of data to the FPGA using the SelectMAP -+ * interface. The FPGA_SELECT_MAP_REG address is within -+ * the FPGA address space (CS3), and when we write a byte -+ * to that address, the CCLK line will be toggled. -+ */ -+static int selectmap_write_byte(struct fpgadl_device *fpgadl_dev, -+ u8 *data, int size) -+{ -+ int k; -+ struct fpgadl_par_dev_t *fpgadl_par_dev; -+ -+ fpgadl_par_dev = (struct fpgadl_par_dev_t *) fpgadl_dev->devdata; -+ -+ for (k = 0; k < size; k++) -+ fpgadl_par_dev->selectmap[0] = bitrev8(data[k]); -+ -+ return 0; -+} -+ -+static void fpgadl_par_cleanup(struct fpgadl_par_dev_t *dev) -+{ -+ DBGMSG("fpgadl_par_cleanup"); -+ -+ if (!dev) -+ return; -+ -+ switch (dev->state) { -+ case FPGADL_PAR_DEV_STATE_FPGADL_DEV_REGISTERED: -+ fpgadl_unregister_device(&dev->fpgadl_dev); -+ case FPGADL_PAR_DEV_STATE_HAVE_IOREMAP: -+ iounmap(dev->selectmap); -+ case FPGADL_PAR_DEV_STATE_STRUCT_ALLOCATED: -+ kfree(dev); -+ break; -+ } -+} -+ -+static int __devinit fpgadl_par_probe(struct platform_device *pdev) -+{ -+ int len; -+ int res; -+ struct fpgadl_par_dev_t *dev = NULL; -+ const struct resource *selectmap_res; -+ -+ DBGMSG("fpgadl_par_probe()"); -+ -+ if (fpgadl_par_dev_count == MAX_FPGADL_PAR_DEV) { -+ FAILMSG("Maximum number of devices reached (%d)", -+ fpgadl_par_dev_count); -+ res = -ENODEV; -+ goto error; -+ } -+ -+ DBGMSG(" device %d", fpgadl_par_dev_count); -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) { -+ FAILMSG("Failed to allocate device structure"); -+ res = -ENOMEM; -+ goto error; -+ } -+ /* Set some default values. */ -+ dev->state = FPGADL_PAR_DEV_STATE_STRUCT_ALLOCATED; -+ -+ if (!pdev->dev.platform_data) { -+ FAILMSG("Error getting platform data"); -+ res = -ENODEV; -+ goto error; -+ } -+ dev->fpgadl_dev.pdata = pdev->dev.platform_data; -+ pdev->dev.driver_data = dev; /* Private driver data */ -+ -+ /* Assign virtual addresses to SELECTMAP I/O memory regions. */ -+ selectmap_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "selectmap"); -+ if (!selectmap_res) { -+ FAILMSG("Error getting selectmap ressource"); -+ res = -ENODEV; -+ goto error; -+ } -+ len = selectmap_res->end - selectmap_res->start; -+ dev->selectmap = ioremap(selectmap_res->start, len); -+ if (!dev->selectmap) { -+ FAILMSG("Can't remap selectmap register"); -+ res = -ENXIO; -+ goto error; -+ } -+ dev->state = FPGADL_PAR_DEV_STATE_HAVE_IOREMAP; -+ -+ dev->fpgadl_dev.write_byte = selectmap_write_byte; -+ sprintf(dev->devname, "fpgadl_par%d", fpgadl_par_dev_count); -+ DBGMSG(" NAME = %s", dev->devname); -+ dev->fpgadl_dev.name = dev->devname; -+ dev->fpgadl_dev.devdata = dev; /* For our write_byte() callback */ -+ res = fpgadl_register_device(&dev->fpgadl_dev); -+ if (res < 0) { -+ FAILMSG("Error registering fpgadl_par device"); -+ goto error; -+ } -+ dev->state = FPGADL_PAR_DEV_STATE_FPGADL_DEV_REGISTERED; -+ -+ fpgadl_par_dev_count++; -+ -+ return 0; -+ -+error: -+ fpgadl_par_cleanup(dev); -+ return res; -+} -+ -+static int __devexit fpgadl_par_remove(struct platform_device *pdev) -+{ -+ struct fpgadl_par_dev_t *dev = platform_get_drvdata(pdev); -+ -+ DBGMSG("fpgadl_par_remove()"); -+ -+ fpgadl_par_cleanup(dev); -+ -+ return 0; -+} -+ -+static struct fpgadl_driver fpgadl_par_driver = { -+ .version = MODULE_VERSION_STR, -+ .module = THIS_MODULE, -+ .driver = { -+ .name = "fpgadl_par", -+ }, -+}; -+ -+static struct platform_driver fpgadl_platform_driver = { -+ .driver = { -+ .name = MODULE_NAME, -+ .owner = THIS_MODULE, -+ }, -+ .remove = fpgadl_par_remove, -+}; -+ -+static int __init fpgadl_par_init(void) -+{ -+ int res; -+ -+ DBGMSG("fpgadl_par_init()"); -+ -+ /* Register with the driver core. */ -+ res = fpgadl_register_driver(&fpgadl_par_driver); -+ if (res) { -+ FAILMSG("Can't register fpgadl parallel driver"); -+ return res; -+ } -+ -+ /* The probe function will be called for each platform device declared -+ * in board setup code. */ -+ res = platform_driver_probe(&fpgadl_platform_driver, -+ fpgadl_par_probe); -+ if (res) { -+ FAILMSG("platform_driver_probe() failed"); -+ return res; -+ } -+ -+ return 0; -+} -+module_init(fpgadl_par_init); -+ -+static void __exit fpgadl_par_exit(void) -+{ -+ DBGMSG("fpgadl_par_exit()"); -+ platform_driver_unregister(&fpgadl_platform_driver); -+ fpgadl_unregister_driver(&fpgadl_par_driver); -+} -+module_exit(fpgadl_par_exit); -+ -+MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@lyrtech.com>"); -+MODULE_DESCRIPTION("FPGA parallel programming driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/misc/fpgadl_ser.c b/drivers/misc/fpgadl_ser.c -new file mode 100644 -index 0000000..01ca5e0 ---- /dev/null -+++ b/drivers/misc/fpgadl_ser.c -@@ -0,0 +1,244 @@ -+/* -+ * fpgadl_ser.c - FPGA serial programming driver -+ * -+ * Copyright (C) 2008 Lyrtech <www.lyrtech.com> -+ * -+ * Based on SH SCI SPI interface -+ * Copyright (c) 2008 Magnus Damm -+ * -+ * 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/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/spi/spi.h> -+#include <linux/fpgadl.h> -+ -+#define MODULE_NAME "fpgadl_ser" -+#define MODULE_VERSION_STR "v1.0" -+ -+/* Define this to enable verbose debug messages */ -+#define FPGADL_SER_DEBUG 1 -+ -+/* Module parameters */ -+static unsigned int fpgadl_ser_debug; -+EXPORT_SYMBOL_GPL(fpgadl_ser_debug); -+module_param_named(debug, fpgadl_ser_debug, int, 0644); -+ -+#ifdef FPGADL_SER_DEBUG -+#define INFOMSG(fmt, args...) \ -+do { \ -+ printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) -+#define DBGMSG(fmt, args...) \ -+do { if (fpgadl_ser_debug > 0) \ -+ printk(KERN_DEBUG "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) -+#define DBGMSG_ENTER() \ -+ DBGMSG("%s() enter", __func__); -+#define DBGMSG_LEAVE() \ -+ DBGMSG("%s() leave", __func__); -+#else -+#define INFOMSG(fmt, args...) do {} while (0) -+#define DBGMSG(fmt, args...) do {} while (0) -+#define DBGMSG_ENTER() do {} while (0) -+#define DBGMSG_LEAVE() do {} while (0) -+#endif -+ -+#define FAILMSG(fmt, args...) \ -+do { \ -+ printk(KERN_ERR "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) -+ -+struct fpgadl_ser_dev_t { -+ char devname[32]; -+ enum { -+ FPGADL_SER_DEV_STATE_STRUCT_ALLOCATED, -+ FPGADL_SER_DEV_STATE_SPI_SETUP, -+ FPGADL_SER_DEV_STATE_FPGADL_DEV_REGISTERED, -+ } state; -+ struct spi_transfer t; -+ struct spi_message m; -+ struct spi_device *spi; -+ struct fpgadl_device fpgadl_dev; -+}; -+ -+#define MAX_FPGADL_SER_DEV 5 -+ -+static int fpgadl_ser_dev_count; -+ -+static int fpgadl_ser_write_byte(struct fpgadl_device *fpgadl_dev, -+ u8 *data, int size) -+{ -+ int status; -+ struct fpgadl_ser_dev_t *fpgadl_ser_dev; -+ -+ fpgadl_ser_dev = (struct fpgadl_ser_dev_t *) fpgadl_dev->devdata; -+ -+ if (!data) { -+ FAILMSG("NULL data pointer"); -+ return -EFAULT; -+ } -+ -+ spi_message_init(&fpgadl_ser_dev->m); -+ fpgadl_ser_dev->t.tx_buf = data; -+ fpgadl_ser_dev->t.len = size; -+ spi_message_add_tail(&fpgadl_ser_dev->t, &fpgadl_ser_dev->m); -+ -+ status = spi_sync(fpgadl_ser_dev->spi, &fpgadl_ser_dev->m); -+ if (status < 0) -+ FAILMSG("spi_sync() failed (%d)", status); -+ -+ return status; -+} -+ -+static void fpgadl_ser_cleanup(struct fpgadl_ser_dev_t *dev) -+{ -+ DBGMSG_ENTER(); -+ -+ if (!dev) -+ return; -+ -+ switch (dev->state) { -+ case FPGADL_SER_DEV_STATE_FPGADL_DEV_REGISTERED: -+ fpgadl_unregister_device(&dev->fpgadl_dev); -+ case FPGADL_SER_DEV_STATE_SPI_SETUP: -+ case FPGADL_SER_DEV_STATE_STRUCT_ALLOCATED: -+ kfree(dev); -+ break; -+ } -+} -+ -+static int __devinit fpgadl_ser_probe(struct spi_device *spi) -+{ -+ int res; -+ struct fpgadl_ser_dev_t *dev = NULL; -+ -+ DBGMSG_ENTER(); -+ -+ if (fpgadl_ser_dev_count == MAX_FPGADL_SER_DEV) { -+ FAILMSG("Maximum number of devices reached (%d)", -+ fpgadl_ser_dev_count); -+ res = -ENODEV; -+ goto error; -+ } -+ -+ DBGMSG(" device %d", fpgadl_ser_dev_count); -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) { -+ FAILMSG("Failed to allocate device structure"); -+ res = -ENOMEM; -+ goto error; -+ } -+ /* Set some default values. */ -+ dev->state = FPGADL_SER_DEV_STATE_STRUCT_ALLOCATED; -+ -+ DBGMSG(" SPI mode = %d", spi->mode); -+ -+ if (!spi->dev.platform_data) { -+ FAILMSG("Error getting platform data"); -+ res = -ENODEV; -+ goto error; -+ } -+ dev->fpgadl_dev.pdata = spi->dev.platform_data; -+ spi->dev.driver_data = dev; /* Private driver data */ -+ -+ spi->bits_per_word = 8; /* Size of Tx and Rx transfers. */ -+ res = spi_setup(spi); -+ if (res < 0) { -+ FAILMSG("Error setting-up SPI"); -+ goto error; -+ } -+ dev->spi = spi; -+ dev->state = FPGADL_SER_DEV_STATE_SPI_SETUP; -+ -+ dev->fpgadl_dev.write_byte = fpgadl_ser_write_byte; -+ sprintf(dev->devname, "fpgadl_ser%d", fpgadl_ser_dev_count); -+ DBGMSG(" NAME = %s", dev->devname); -+ dev->fpgadl_dev.name = dev->devname; -+ dev->fpgadl_dev.devdata = dev; /* For our write_byte() callback */ -+ res = fpgadl_register_device(&dev->fpgadl_dev); -+ if (res < 0) { -+ FAILMSG("Error registering fpgadl_ser device"); -+ goto error; -+ } -+ dev->state = FPGADL_SER_DEV_STATE_FPGADL_DEV_REGISTERED; -+ -+ fpgadl_ser_dev_count++; -+ -+ return 0; -+ -+error: -+ fpgadl_ser_cleanup(dev); -+ return res; -+} -+ -+static int __devexit fpgadl_ser_remove(struct spi_device *spi) -+{ -+ struct fpgadl_ser_dev_t *dev = spi_get_drvdata(spi); -+ -+ DBGMSG_ENTER(); -+ fpgadl_ser_cleanup(dev); -+ return 0; -+} -+ -+static struct spi_driver fpgadl_ser_spi_driver = { -+ .driver = { -+ .name = MODULE_NAME, -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ .probe = fpgadl_ser_probe, -+ .remove = fpgadl_ser_remove, -+}; -+ -+static struct fpgadl_driver fpgadl_ser_driver = { -+ .version = MODULE_VERSION_STR, -+ .module = THIS_MODULE, -+ .driver = { -+ .name = "fpgadl_ser", -+ }, -+}; -+ -+static int __init fpgadl_ser_init(void) -+{ -+ int res; -+ -+ DBGMSG_ENTER(); -+ -+ /* Register with the driver core. */ -+ res = fpgadl_register_driver(&fpgadl_ser_driver); -+ if (res) { -+ FAILMSG("Can't register fpgadl serial driver"); -+ return res; -+ } -+ -+ return spi_register_driver(&fpgadl_ser_spi_driver); -+} -+module_init(fpgadl_ser_init); -+ -+static void __exit fpgadl_ser_exit(void) -+{ -+ DBGMSG_ENTER(); -+ spi_unregister_driver(&fpgadl_ser_spi_driver); -+ fpgadl_unregister_driver(&fpgadl_ser_driver); -+} -+module_exit(fpgadl_ser_exit); -+ -+MODULE_DESCRIPTION("FPGA serial programming driver"); -+MODULE_AUTHOR("Hugo Villeneuve"); -+MODULE_LICENSE("GPL"); -diff --git a/include/linux/fpgadl.h b/include/linux/fpgadl.h -new file mode 100644 -index 0000000..27d83f1 ---- /dev/null -+++ b/include/linux/fpgadl.h -@@ -0,0 +1,96 @@ -+/* -+ * FPGA bitstream load header file. -+ * -+ * Copyright (C) 2008 Lyrtech <www.lyrtech.com> -+ * -+ * 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. -+ */ -+ -+#ifndef FPGADL_H -+#define FPGADL_H 1 -+ -+#include <linux/miscdevice.h> -+ -+/* FPGA device-specific informations and functions. */ -+struct fpgadl_pdata_t { -+ enum { -+ FPGA_VENDOR_XILINX, -+ FPGA_VENDOR_ALTERA, -+ } fpga_vendor; -+ enum { -+ FPGA_FAMILY_XILINX_XC3S, -+ FPGA_FAMILY_XILINX_XC4V, -+ } fpga_family; -+ ssize_t payload_full_size; -+ u8 program_b; -+ u8 init_b; -+ u8 done; -+ char *bitstream_name; -+ int check_init_low; /* Set to 1 to check that the INIT pin is low during -+ * programming. Normally, we should check if INIT_B -+ * is low during configuration, indicating a -+ * configuration error. But this may cause problems -+ * for bitstreams where the INIT_B pin is used as a -+ * GPIO after configuration. */ -+}; -+ -+struct fpgadl_driver { -+ char *version; -+ struct module *module; -+ struct device_driver driver; -+ struct driver_attribute version_attr; -+}; -+ -+struct fpgadl_device { -+ int id; -+ char *name; -+ enum { -+ FPGADL_DEV_STATE_START, -+ FPGADL_DEV_STATE_DEVICE_REGISTERED, -+ FPGADL_DEV_STATE_GPIO_REGISTERED, -+ FPGADL_DEV_STATE_CHAR_DEV_REGISTERED, -+ } state; -+ int bitstream_buffer_allocated; -+ u8 *bitstream_data; -+ size_t bitstream_length; -+ size_t bitstream_max_size; -+ int bitstream_mode; -+ int bitstream_loaded; -+ int (*write_byte)(struct fpgadl_device *, u8 *, int); -+ void *devdata; /* Pointer to interface-specific (SPI/PAR) device */ -+ struct miscdevice miscdev; -+ struct fpgadl_driver *driver; -+ struct fpgadl_pdata_t *pdata; -+ struct device dev; -+}; -+ -+/* Bitstream types. */ -+#define BITSTREAM_MODE_UNKNOWN 0 -+#define BITSTREAM_MODE_FULL 1 -+#define BITSTREAM_MODE_PARTIAL 2 -+ -+extern struct bus_type fpgadl_bus_type; -+ -+#define to_fpgadl_driver(drv) container_of(drv, struct fpgadl_driver, driver); -+ -+extern int fpgadl_register_driver(struct fpgadl_driver *drv); -+extern void fpgadl_unregister_driver(struct fpgadl_driver *drv); -+ -+extern int fpgadl_register_device(struct fpgadl_device *fpgadldev); -+extern void fpgadl_unregister_device(struct fpgadl_device *fpgadldev); -+ -+int fpgadl_is_bitstream_loaded(const char *name); -+ -+#endif /* FPGADL_H */ --- -1.5.4.5 - |