Fixed directory structure to correspond to the new module name
authorTom Knot <tomasknot@gmail.com>
Fri, 2 Mar 2018 12:16:28 +0000 (13:16 +0100)
committerTom Knot <tomasknot@gmail.com>
Fri, 2 Mar 2018 12:16:28 +0000 (13:16 +0100)
33 files changed:
modules/neuron_spi/Makefile [deleted file]
modules/neuron_spi/src/unipi_common.h [deleted file]
modules/neuron_spi/src/unipi_gpio.c [deleted file]
modules/neuron_spi/src/unipi_gpio.h [deleted file]
modules/neuron_spi/src/unipi_iio.c [deleted file]
modules/neuron_spi/src/unipi_iio.h [deleted file]
modules/neuron_spi/src/unipi_misc.c [deleted file]
modules/neuron_spi/src/unipi_misc.h [deleted file]
modules/neuron_spi/src/unipi_platform.c [deleted file]
modules/neuron_spi/src/unipi_platform.h [deleted file]
modules/neuron_spi/src/unipi_spi.c [deleted file]
modules/neuron_spi/src/unipi_spi.h [deleted file]
modules/neuron_spi/src/unipi_sysfs.c [deleted file]
modules/neuron_spi/src/unipi_sysfs.h [deleted file]
modules/neuron_spi/src/unipi_uart.c [deleted file]
modules/neuron_spi/src/unipi_uart.h [deleted file]
modules/unipi/Makefile [new file with mode: 0644]
modules/unipi/bin [new file with mode: 0644]
modules/unipi/src/unipi_common.h [new file with mode: 0644]
modules/unipi/src/unipi_gpio.c [new file with mode: 0644]
modules/unipi/src/unipi_gpio.h [new file with mode: 0644]
modules/unipi/src/unipi_iio.c [new file with mode: 0644]
modules/unipi/src/unipi_iio.h [new file with mode: 0644]
modules/unipi/src/unipi_misc.c [new file with mode: 0644]
modules/unipi/src/unipi_misc.h [new file with mode: 0644]
modules/unipi/src/unipi_platform.c [new file with mode: 0644]
modules/unipi/src/unipi_platform.h [new file with mode: 0644]
modules/unipi/src/unipi_spi.c [new file with mode: 0644]
modules/unipi/src/unipi_spi.h [new file with mode: 0644]
modules/unipi/src/unipi_sysfs.c [new file with mode: 0644]
modules/unipi/src/unipi_sysfs.h [new file with mode: 0644]
modules/unipi/src/unipi_uart.c [new file with mode: 0644]
modules/unipi/src/unipi_uart.h [new file with mode: 0644]

diff --git a/modules/neuron_spi/Makefile b/modules/neuron_spi/Makefile
deleted file mode 100644 (file)
index 321946c..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-# Note: Compiling kernel modules requires creating symlinks, which is not possible on certain 
-# filesystems (notably VirtualBox vmfs); therefore we allow using /run/ through the 'symlink' target,
-# if necessary.
-SYMLINK_DIR_PATH = /run/kernel/neuron_spi
-LINUX_DIR_PATH = /root/bokula/linux
-SRC_DIR_PATH = $(PWD)/src
-BIN_DIR_PATH = $(PWD)/bin
-
-MODULE_MAKE_FILE = Makefile
-
-C_SRC_FILES = unipi_spi.c
-C_SRC_FILES += unipi_iio.c
-C_SRC_FILES += unipi_gpio.c
-C_SRC_FILES += unipi_uart.c
-C_SRC_FILES += unipi_sysfs.c
-C_SRC_FILES += unipi_misc.c
-C_SRC_FILES += unipi_platform.c
-
-H_SRC_FILES = unipi_spi.h
-H_SRC_FILES += unipi_iio.h
-H_SRC_FILES += unipi_gpio.h
-H_SRC_FILES += unipi_uart.h
-H_SRC_FILES += unipi_sysfs.h
-H_SRC_FILES += unipi_misc.h
-H_SRC_FILES += unipi_platform.h
-H_SRC_FILES += unipi_common.h
-
-OBJ_FILES = src/unipi_spi.o
-OBJ_FILES += src/unipi_iio.o
-OBJ_FILES += src/unipi_gpio.o
-OBJ_FILES += src/unipi_uart.o
-OBJ_FILES += src/unipi_sysfs.o
-OBJ_FILES += src/unipi_misc.o
-OBJ_FILES += src/unipi_platform.o
-
-KERNEL_MODULE_NAME = unipi
-obj-m += ${KERNEL_MODULE_NAME}.o
-unipi-objs := ${OBJ_FILES}
-
-TARGET_PLC_PATH = tomunipi:/root/
-
-.PHONY: default
-default: symlink ;
-
-all: 
-       make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C ${LINUX_DIR_PATH} M=${PWD} modules
-
-clean: 
-       make -C ${LINUX_DIR_PATH} M=$(PWD) clean
-       rm -f ${BIN_DIR_PATH}/${KERNEL_MODULE_NAME}.ko
-
-transfer: clean symlink
-       scp ${BIN_DIR_PATH}/${KERNEL_MODULE_NAME}.ko ${TARGET_PLC_PATH}
-       
-symlink: clean
-       rm -r -f ${SYMLINK_DIR_PATH}
-       mkdir -p ${SYMLINK_DIR_PATH}/src
-       mkdir -p ${SYMLINK_DIR_PATH}/bin
-       cp ${PWD}/${MODULE_MAKE_FILE} ${SYMLINK_DIR_PATH} 
-       for f in ${C_SRC_FILES}; do\
-               ln -s ${SRC_DIR_PATH}/$$f ${SYMLINK_DIR_PATH}/src ;\
-               done
-       for f in ${H_SRC_FILES}; do\
-               ln -s ${SRC_DIR_PATH}/$$f ${SYMLINK_DIR_PATH}/src ;\
-               done
-       cd ${SYMLINK_DIR_PATH}; make all
-       mv ${SYMLINK_DIR_PATH}/${KERNEL_MODULE_NAME}.ko ${BIN_DIR_PATH}
-       rm -r -f ${SYMLINK_DIR_PATH}
diff --git a/modules/neuron_spi/src/unipi_common.h b/modules/neuron_spi/src/unipi_common.h
deleted file mode 100644 (file)
index f7646a3..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_COMMON_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_COMMON_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-/***************
- * Definitions *
- ***************/
-
-#define NEURONSPI_SCHED_REQUIRED 0 // Older kernels do not require sched/types to be specifically imported
-#define NEURONSPI_MAJOR_VERSIONSTRING "Development Beta Version 0.02:12:02:2018"
-
-#define NEURONSPI_MAX_DEVS                             3
-#define NEURONSPI_MAX_UART                             128
-#define NEURONSPI_BUFFER_MAX                   1152
-#define NEURONSPI_HEADER_LENGTH                10
-#define NEURONSPI_FIRST_MESSAGE_LENGTH 6
-#define NEURONSPI_EDGE_DELAY                   10
-#define NEURONSPI_B_PER_WORD                   8
-#define NEURONSPI_DEFAULT_FREQ                 600000
-#define NEURONSPI_COMMON_FREQ                  12000000
-#define NEURONSPI_SLOWER_FREQ                  8000000
-#define NEURONSPI_MAX_TX                               62
-#define NEURONSPI_MAX_BAUD                             115200
-#define NEURONSPI_FIFO_SIZE                            256
-#define NEURONSPI_DETAILED_DEBUG               0
-#define NEURONSPI_LAST_TRANSFER_DELAY  40
-
-#define NEURON_DEVICE_NAME                             "neuronspi"
-#define NEURON_DEVICE_CLASS                    "modbus_spi"
-#define NEURON_DRIVER_NAME                             "NEURONSPI"
-#define PORT_NEURONSPI                                 184
-
-#define STRICT_RESERVING
-#define NEURONSPI_ALWAYS_EXPORT
-
-#define NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(X)  ((((X) + 15) >> 4) << 1)
-
-/********************
- * Module Constants *
- ********************/
-
-#define NEURONSPI_NO_INTERRUPT_MODELS_LEN                              3
-static const u16 NEURONSPI_NO_INTERRUPT_MODELS[NEURONSPI_NO_INTERRUPT_MODELS_LEN] = {
-               0xb10, 0xc10, 0xf10
-};
-
-/*******************
- * Data Structures *
- *******************/
-
-enum neuron_str_attribute_type {
-               NEURON_SATTR_MODEL,
-               NEURON_SATTR_EEPROM,
-               NEURON_SATTR_BOARD_NAME,
-               NEURON_SATTR_GPIO_GROUP_NAME
-};
-
-enum neuron_num_attribute_type {
-               NEURON_NATTR_BOARDCOUNT,
-               NEURON_NATTR_MODE,
-               NEURON_NATTR_CURRENT_VALUE
-};
-
-struct neuronspi_devtype
-{
-       u8      name[10];
-       s32     nr_gpio;
-       s32     nr_uart;
-};
-
-struct neuronspi_port
-{
-       struct uart_port                        port;
-       u8                                                      line;
-       struct kthread_work                     tx_work;
-       struct kthread_work                     rx_work;
-       struct kthread_work                     irq_work;
-       u32                                                     flags;
-       u8                                                      ier_clear;
-       u8                                                      buf[NEURONSPI_FIFO_SIZE];
-       struct neuronspi_uart_data      *parent;
-       u8                                                      dev_index;
-       u8                                                      dev_port;
-       u8                                                      parmrk_enabled;
-       u64                                                     parmrk_frame_delay;
-       s32                                                     baud;
-};
-
-struct neuronspi_uart_data
-{
-       const struct neuronspi_devtype  *devtype;
-       struct kthread_worker                   kworker;
-       struct task_struct                              *kworker_task;
-       struct neuronspi_port                   *p;
-       u8                                                              p_count;
-};
-
-// Instantiated once
-struct neuronspi_char_driver
-{
-       s32 major_number;
-       u8 *message;
-       u16 message_size;
-       u32 open_counter;
-       struct class* driver_class;
-       struct device* dev;
-};
-
-// Instantiated once per SPI device
-struct neuronspi_driver_data
-{
-       struct spi_driver *spi_driver;
-       struct neuronspi_char_driver *char_driver;
-       struct uart_driver *serial_driver;
-       struct neuronspi_uart_data *uart_data;
-       struct neuronspi_led_driver *led_driver;
-       struct neuronspi_di_driver **di_driver;
-       struct neuronspi_do_driver **do_driver;
-       struct neuronspi_ro_driver **ro_driver;
-       struct platform_device *board_device;
-       struct iio_dev *stm_ai_driver;
-       struct iio_dev *stm_ao_driver;
-       struct iio_dev **sec_ai_driver;
-       struct iio_dev **sec_ao_driver;
-       struct kthread_worker primary_worker;
-       struct task_struct *primary_worker_task;
-       struct regmap *reg_map;
-       struct task_struct *poll_thread;
-       struct mutex device_lock;
-       struct neuronspi_board_features *features;
-       struct neuronspi_board_regstart_table *regstart_table;
-       struct spinlock sysfs_regmap_lock;
-       char platform_name[sizeof("io_group0")];
-       u8 *send_buf;
-       u8 *recv_buf;
-       u8 *first_probe_reply;
-       u8 *second_probe_reply;
-       u8 reserved_device;
-       u8 uart_count;
-       u8 uart_read;
-       u8 *uart_buf;
-       u8 slower_model;
-       u8 no_irq;
-       u8 lower_board_id;
-       u8 upper_board_id;
-       u8 combination_id;
-       s32 neuron_index;
-       u16 sysfs_regmap_target;
-       u16 sysfs_counter_target;
-       u32 ideal_frequency;
-};
-
-struct neuronspi_di_driver {
-       struct spi_device* spi;
-       struct gpio_chip gpio_c;
-       struct platform_device *plat_dev;
-       u8 di_index;
-       char name[sizeof("di_0_00")];
-};
-
-struct neuronspi_do_driver
-{
-       struct spi_device* spi;
-       struct gpio_chip gpio_c;
-       struct platform_device *plat_dev;
-       u8 do_index;
-       char name[sizeof("do_0_00")];
-};
-
-struct neuronspi_ro_driver
-{
-       struct spi_device* spi;
-       struct gpio_chip gpio_c;
-       struct platform_device *plat_dev;
-       u8 ro_index;
-       char name[sizeof("ro_0_00")];
-};
-
-struct neuronspi_sec_ai_driver
-{
-       struct iio *devices;
-       u16 dev_count;
-};
-
-struct neuronspi_sec_ao_driver
-{
-       struct iio *devices;
-       u16 dev_count;
-};
-
-struct neuronspi_stm_ai_data
-{
-       u32 mode;
-       struct spi_device *parent;
-};
-
-struct neuronspi_stm_ao_data
-{
-       u32 mode;
-       struct spi_device *parent;
-};
-
-struct neuronspi_sec_ai_data
-{
-       u32 index;
-       u32 mode;
-       struct spi_device *parent;
-};
-
-struct neuronspi_sec_ao_data
-{
-       u32 index;
-       u32 mode;
-       struct spi_device *parent;
-};
-
-// Instantiated once per LED
-struct neuronspi_led_driver
-{
-       struct led_classdev     ldev;
-       struct spi_device       *spi;
-       struct kthread_work     led_work;
-       int                                     id;
-       int                                     brightness;
-       char                            name[sizeof("neuron:green:uled-x1")];
-       spinlock_t                      lock;
-};
-
-struct neuronspi_file_data
-{
-       struct spi_device** spi_device;
-       struct mutex            lock;
-       u8                                      *send_buf;
-       u8                                      *recv_buf;
-       u32                     message_len;
-};
-
-struct neuronspi_direct_acc
-{
-       void __iomem            *vaddr;
-       u32                                     size;
-};
-
-/*********************
- * Data Declarations *
- *********************/
-
-extern struct mutex neuronspi_master_mutex;
-extern struct neuronspi_char_driver neuronspi_cdrv;
-extern struct spinlock* neuronspi_spi_w_spinlock;
-extern struct spi_device* neuronspi_s_dev[NEURONSPI_MAX_DEVS];
-extern struct task_struct *neuronspi_invalidate_thread;
-
-extern u8 neuronspi_spi_w_flag;
-extern u8 neuronspi_probe_count;
-extern int neuronspi_model_id;
-extern spinlock_t neuronspi_probe_spinlock;
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_COMMON_H_ */
diff --git a/modules/neuron_spi/src/unipi_gpio.c b/modules/neuron_spi/src/unipi_gpio.c
deleted file mode 100644 (file)
index e7d9de6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-/************
- * Includes *
- ************/
-
-#include "unipi_gpio.h"
-#include "unipi_spi.h"
-
-/************************
- * Non-static Functions *
- ************************/
-
-int neuronspi_gpio_di_direction_input(struct gpio_chip *chip, unsigned offset) {
-       return 0;
-}
-
-int neuronspi_gpio_di_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
-       return -EINVAL;
-}
-
-int neuronspi_gpio_di_get(struct gpio_chip *chip, unsigned offset) {
-       struct neuronspi_di_driver *n_di = gpiochip_get_data(chip);
-       struct spi_device *spi = n_di->spi;
-       return neuronspi_spi_gpio_di_get(spi, n_di->di_index);
-}
-
-int neuronspi_gpio_do_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
-       return 0;
-}
-
-void neuronspi_gpio_do_set(struct gpio_chip *chip, unsigned offset, int value) {
-       struct neuronspi_do_driver *n_do = gpiochip_get_data(chip);
-       struct spi_device *spi = n_do->spi;
-       neuronspi_spi_gpio_do_set(spi, n_do->do_index, value);
-}
-
-int neuronspi_gpio_ro_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
-       return 0;
-}
-
-void neuronspi_gpio_ro_set(struct gpio_chip *chip, unsigned offset, int value) {
-       struct neuronspi_ro_driver *n_ro = gpiochip_get_data(chip);
-       struct spi_device *spi = n_ro->spi;
-       neuronspi_spi_gpio_ro_set(spi, n_ro->ro_index, value);
-}
-
diff --git a/modules/neuron_spi/src/unipi_gpio.h b/modules/neuron_spi/src/unipi_gpio.h
deleted file mode 100644 (file)
index 508fd78..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_GPIO_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_GPIO_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-#include "unipi_common.h"
-
-/*************************
- * Function Declarations *
- *************************/
-
-int neuronspi_gpio_di_direction_input(struct gpio_chip *chip, unsigned offset);
-int neuronspi_gpio_di_direction_output(struct gpio_chip *chip, unsigned offset, int value);
-int    neuronspi_gpio_di_get(struct gpio_chip *chip, unsigned offset);
-int neuronspi_gpio_do_direction_input(struct gpio_chip *chip, unsigned offset);
-int neuronspi_gpio_do_direction_output(struct gpio_chip *chip, unsigned offset, int value);
-void neuronspi_gpio_do_set(struct gpio_chip *chip, unsigned offset, int value);
-int neuronspi_gpio_ro_direction_input(struct gpio_chip *chip, unsigned offset);
-int neuronspi_gpio_ro_direction_output(struct gpio_chip *chip, unsigned offset, int value);
-void neuronspi_gpio_ro_set(struct gpio_chip *chip, unsigned offset, int value);
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_GPIO_H_ */
diff --git a/modules/neuron_spi/src/unipi_iio.c b/modules/neuron_spi/src/unipi_iio.c
deleted file mode 100644 (file)
index eca3eae..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-/************
- * Includes *
- ************/
-
-#include "unipi_iio.h"
-#include "unipi_spi.h"
-
-/************************
- * Non-static Functions *
- ************************/
-
-int neuronspi_iio_stm_ai_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) {
-       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_mode_reg, &ai_data->mode);
-       switch(ai_data->mode) {
-       case 0: {
-               if (ch->type == IIO_VOLTAGE) {
-                       neuronspi_spi_iio_stm_ai_read_voltage(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_INT;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       case 1: {
-               if (ch->type == IIO_CURRENT) {
-                       neuronspi_spi_iio_stm_ai_read_current(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_INT;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       default: {
-               return -EINVAL;
-               break;
-       }
-       }
-}
-
-int neuronspi_iio_stm_ao_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, &ao_data->mode);
-       switch(ao_data->mode) {
-       case 3: {
-               if (ch->type == IIO_RESISTANCE) {
-                       neuronspi_spi_iio_stm_ao_read_resistance(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_INT;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       default: {
-               return -EINVAL;
-               break;
-       }
-       }
-}
-
-int neuronspi_iio_stm_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int val, int val2, long mask)
-{
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, &ao_data->mode);
-       switch(ao_data->mode) {
-       case 0: {
-               if (ch->type == IIO_VOLTAGE) {
-                       neuronspi_spi_iio_stm_ao_set_voltage(indio_dev, ch, val, val2, mask);
-                       return 0;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       case 1: {
-               if (ch->type == IIO_CURRENT) {
-                       neuronspi_spi_iio_stm_ao_set_current(indio_dev, ch, val, val2, mask);
-                       return 0;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       default: {
-               return -EINVAL;
-               break;
-       }
-       }
-}
-
-int neuronspi_iio_sec_ai_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_mode_reg, &ai_data->mode);
-       switch(ai_data->mode) {
-       case 0: {
-               return -EINVAL;
-               break;
-       }
-       case 1: {
-               if (ch->type == IIO_VOLTAGE) {
-                       neuronspi_spi_iio_sec_ai_read_voltage(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_FRACTIONAL;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       case 2: {
-               if (ch->type == IIO_VOLTAGE) {
-                       neuronspi_spi_iio_sec_ai_read_voltage(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_FRACTIONAL;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       case 3: {
-               if (ch->type == IIO_CURRENT) {
-                       neuronspi_spi_iio_sec_ai_read_current(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_FRACTIONAL;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       case 4: {
-               if (ch->type == IIO_RESISTANCE) {
-                       neuronspi_spi_iio_sec_ai_read_resistance(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_FRACTIONAL;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       case 5: {
-               if (ch->type == IIO_RESISTANCE) {
-                       neuronspi_spi_iio_sec_ai_read_resistance(indio_dev, ch, val, val2, mask);
-                       return IIO_VAL_FRACTIONAL;
-               } else {
-                       return -EINVAL;
-               }
-               break;
-       }
-       default: {
-               return -EINVAL;
-               break;
-       }
-       }
-}
-
-int neuronspi_iio_sec_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int val, int val2, long mask)
-{
-       if (ch->type == IIO_VOLTAGE) {
-               neuronspi_spi_iio_stm_ao_set_voltage(indio_dev, ch, val, val2, mask);
-               return 0;
-       } else {
-               return -EINVAL;
-       }
-}
diff --git a/modules/neuron_spi/src/unipi_iio.h b/modules/neuron_spi/src/unipi_iio.h
deleted file mode 100644 (file)
index c6e96c9..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_IIO_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_IIO_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-#include "unipi_common.h"
-
-/*************************
- * Function Declarations *
- *************************/
-
-int neuronspi_iio_stm_ai_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-int neuronspi_iio_stm_ao_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-int neuronspi_iio_stm_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-int neuronspi_iio_sec_ai_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-int neuronspi_iio_sec_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_IIO_H_ */
diff --git a/modules/neuron_spi/src/unipi_misc.c b/modules/neuron_spi/src/unipi_misc.c
deleted file mode 100644 (file)
index 6efb89c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-/************
- * Includes *
- ************/
-
-#include "unipi_misc.h"
-#include "unipi_spi.h"
-
-/************************
- * Non-static Functions *
- ************************/
-
-void neuronspi_led_proc(struct kthread_work *ws)
-{
-       struct neuronspi_led_driver *led = to_led_driver(ws, led_work);
-       printk("NEURONSPI: BRIGHT id:%d\n", led->id);
-       neuronspi_spi_led_set_brightness(led->spi, led->brightness, led->id);
-}
-
-void neuronspi_led_set_brightness(struct led_classdev *ldev, enum led_brightness brightness)
-{
-       struct neuronspi_led_driver *led = container_of(ldev, struct neuronspi_led_driver, ldev);
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(led->spi);
-       spin_lock(&led->lock);
-       led->brightness = brightness;
-       kthread_queue_work(&n_spi->primary_worker, &led->led_work);
-       spin_unlock(&led->lock);
-}
diff --git a/modules/neuron_spi/src/unipi_misc.h b/modules/neuron_spi/src/unipi_misc.h
deleted file mode 100644 (file)
index ebeb7e2..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_MISC_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_MISC_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-#include "unipi_common.h"
-
-/*************************
- * Function Declarations *
- *************************/
-
-void neuronspi_led_proc(struct kthread_work *ws);
-void neuronspi_led_set_brightness(struct led_classdev *ldev, enum led_brightness brightness);
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_MISC_H_ */
diff --git a/modules/neuron_spi/src/unipi_platform.c b/modules/neuron_spi/src/unipi_platform.c
deleted file mode 100644 (file)
index 08a0ec8..0000000
+++ /dev/null
@@ -1,1801 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-/************
- * Includes *
- ************/
-
-#include "unipi_platform.h"
-#include "unipi_spi.h"
-#include "unipi_common.h"
-
-/***************************
- * Static Data Definitions *
- ***************************/
-
-// B_1000 (S103)
-#define NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK_SIZE 57
-static u32 NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 21,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_AO_BRAIN | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                 // 2
-               NEURONSPI_REGFUN_AI_BRAIN | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,       // 3
-               NEURONSPI_REGFUN_AIO_BRAIN | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 4
-               NEURONSPI_REGFUN_V_REF_INP | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 5
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 6
-               NEURONSPI_REGFUN_TX_QUEUE_LEN | NEURONSPI_REGFLAG_ACC_10HZ,                                                                             // 7
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 16
-               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 17
-               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 18
-               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 19
-               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                   // 20
-               1000, 32, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE  | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1014
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1015
-               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1016
-               NEURONSPI_REGFUN_PWM_PRESCALE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                      // 1017
-               NEURONSPI_REGFUN_PWM_CYCLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                         // 1018
-               NEURONSPI_REGFUN_AO_BRAIN_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                             // 1019
-               NEURONSPI_REGFUN_AO_BRAIN_V_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1020
-               NEURONSPI_REGFUN_AO_BRAIN_V_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1021
-               NEURONSPI_REGFUN_AO_BRAIN_I_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1022
-               NEURONSPI_REGFUN_AO_BRAIN_I_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1023
-               NEURONSPI_REGFUN_AI_BRAIN_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                             // 1024
-               NEURONSPI_REGFUN_AI_BRAIN_V_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1025
-               NEURONSPI_REGFUN_AI_BRAIN_V_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1026
-               NEURONSPI_REGFUN_AI_BRAIN_I_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1027
-               NEURONSPI_REGFUN_AI_BRAIN_I_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1028
-               NEURONSPI_REGFUN_AIO_BRAIN_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,  // 1029
-               NEURONSPI_REGFUN_AIO_BRAIN_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,  // 1030
-               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC                                                                              // 1031
-};
-
-#define NEURONSPI_BOARD_B1000_HW_FEATURES {    \
-               .do_count =                                       4,    \
-               .ro_count =                                       0,    \
-               .ds_count =                                       4,    \
-               .di_count =                                       4,    \
-               .led_count =                              4,    \
-               .stm_ai_count =                           1,    \
-               .stm_ao_count =                           1,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              1,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              4,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            1,    \
-}
-
-#define NEURONSPI_BOARD_B1000_HW_DEFINITION { \
-               .combination_board_id =         0, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_B1000_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .block_count =                          NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK_SIZE, \
-               .name_length =                          6, \
-               .combination_name =                     "B_1000", \
-               .features =                                     NEURONSPI_BOARD_B1000_HW_FEATURES, \
-               .blocks =                                       NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_B1000_HW_COMBINATION[] = {NEURONSPI_BOARD_B1000_HW_DEFINITION};
-
-// E-8Di8Ro (M103)
-#define NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK_SIZE 44
-static u32 NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 19,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               1000, 17, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1018
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1019
-               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1020
-};
-
-#define NEURONSPI_BOARD_E8DI8RO_HW_FEATURES {  \
-               .do_count =                                       0,    \
-               .ro_count =                                       8,    \
-               .ds_count =                                       8,    \
-               .di_count =                                       8,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION { \
-               .combination_board_id =         1, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E8DI8RO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .block_count =                          NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK_SIZE, \
-               .name_length =                          8, \
-               .combination_name =                     "E_8Di8Ro", \
-               .blocks =                                       NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E8DI8RO_HW_FEATURES     \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION};
-
-// E-14Ro
-#define NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK_SIZE 15
-static u32 NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 1,   // Register block beginning and size
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
-               1000, 10,
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
-};
-
-#define NEURONSPI_BOARD_E14RO_HW_FEATURES {    \
-               .do_count =                                       0,    \
-               .ro_count =                                       14,   \
-               .ds_count =                                       0,    \
-               .di_count =                                       0,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E14RO_HW_DEFINITION { \
-               .combination_board_id =         2, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .block_count =                          NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK_SIZE, \
-               .name_length =                          6, \
-               .combination_name =                     "E_14Ro", \
-               .blocks =                                       NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK, \
-               .features =                             NEURONSPI_BOARD_E14RO_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E14RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E14RO_HW_DEFINITION};
-
-// E-16Di
-#define NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK_SIZE 15
-static u32 NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 1,   // Register block beginning and size
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
-               1000, 10,
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
-};
-
-#define NEURONSPI_BOARD_E16DI_HW_FEATURES {    \
-               .do_count =                                       0,    \
-               .ro_count =                                       0,    \
-               .ds_count =                                       0,    \
-               .di_count =                                       16,   \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E16DI_HW_DEFINITION { \
-               .combination_board_id =         3, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .block_count =                          NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK_SIZE, \
-               .name_length =                          6, \
-               .combination_name =                     "E_16Di", \
-               .blocks =                                       NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK, \
-               .features =                             NEURONSPI_BOARD_E16DI_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E16DI_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DI_HW_DEFINITION};
-
-// E-8Di8Ro_P-11DiR485 (xS10)
-#define NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK_SIZE 47
-static u32 NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 20,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                    // 19
-               1000, 23, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DS_ENABLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1018
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1019
-               NEURONSPI_REGFUN_DS_TOGGLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1020
-               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1021
-               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1022
-};
-
-#define NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_FEATURES { \
-               .do_count =                                       0,    \
-               .ro_count =                                       8,    \
-               .ds_count =                                       8,    \
-               .di_count =                                       8,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               1,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            1,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION { \
-               .combination_board_id =         4, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E8DI8RO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P11DIR485_ID, \
-               .block_count =                          NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK_SIZE, \
-               .name_length =                          19, \
-               .combination_name =                     "E_8Di8Ro_P_11DiR485", \
-               .blocks =                                       NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_COMBINATION[] = {NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION};
-
-// E-14Ro_P-11DiR485 (xS40)
-#define NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK_SIZE 71
-static u32 NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 36,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
-               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_1HZ,                                                                    // 35
-               1000, 31, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
-               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1026
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1027
-               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1028
-               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1029
-               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1030
-};
-
-#define NEURONSPI_BOARD_E14ROP11DIR485_HW_FEATURES {   \
-               .do_count =                                       0,    \
-               .ro_count =                                       14,   \
-               .ds_count =                                       8,    \
-               .di_count =                                       8,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               1,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            1,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION { \
-               .combination_board_id =         5, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P11DIR485_ID, \
-               .name_length =                          17, \
-               .combination_name =                     "E_14Ro_P_11DiR485", \
-               .block_count =                          NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E14ROP11DIR485_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E14ROP11DIR485_HW_COMBINATION[] = {NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION};
-
-// E-16Di_P-11DiR485 (xS30)
-#define NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK_SIZE 92
-static u32 NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 52,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC,                                                                               // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 35
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 36
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 37
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 38
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 39
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 40
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 41
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 42
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 43
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 44
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 45
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 46
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 47
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 48
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 49
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 50
-               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                    // 51
-               1000, 36, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1026
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1027
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1028
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1029
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1030
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1031
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1032
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1033
-               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1034
-               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1035
-};
-
-#define NEURONSPI_BOARD_E16DIP11DIR485_HW_FEATURES {   \
-               .do_count =                                       0,    \
-               .ro_count =                                       0,    \
-               .ds_count =                                       0,    \
-               .di_count =                                       23,   \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               1,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            1,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION { \
-               .combination_board_id =         6, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P11DIR485_ID, \
-               .name_length =                          17, \
-               .combination_name =                     "E_16Di_P_11DiR485", \
-               .block_count =                          NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E16DIP11DIR485_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E16DIP11DIR485_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION};
-
-// E-14Ro_U-14Ro (M403)
-#define NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK_SIZE 17
-static u32 NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 3,   // Register block beginning and size
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               1000, 10, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-};
-
-#define NEURONSPI_BOARD_E14ROU14RO_HW_FEATURES {       \
-               .do_count =                                       0,    \
-               .ro_count =                                       28,   \
-               .ds_count =                                       0,    \
-               .di_count =                                       0,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            1,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION { \
-               .combination_board_id =         7, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14RO_ID, \
-               .name_length =                          13, \
-               .combination_name =                     "E_14Ro_U_14Ro", \
-               .block_count =                          NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK, \
-               .features =                             NEURONSPI_BOARD_E14ROU14RO_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION};
-
-// E-16Di_U-14Ro (M203)
-#define NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK_SIZE 68
-static u32 NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 35,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
-               1000, 29, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
-               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1026
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1027
-               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1028
-};
-
-#define NEURONSPI_BOARD_E16DIU14RO_HW_FEATURES {       \
-               .do_count =                                       0,    \
-               .ro_count =                                       14,   \
-               .ds_count =                                       14,   \
-               .di_count =                                       16,   \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION { \
-               .combination_board_id =         8, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14RO_ID, \
-               .name_length =                          13, \
-               .combination_name =                     "E_16Di_U_14Ro", \
-               .block_count =                          NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E16DIU14RO_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION};
-
-// E-14Ro_U-14Di (L503)
-#define NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK_SIZE 62
-static u32 NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 31,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
-               1000, 27, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
-               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1024
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1025
-               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ                                                                                  // 1026
-};
-
-#define NEURONSPI_BOARD_E14ROU14DI_HW_FEATURES {       \
-               .do_count =                                       0,    \
-               .ro_count =                                       14,   \
-               .ds_count =                                       14,   \
-               .di_count =                                       14,   \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION { \
-               .combination_board_id =         9, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14DI_ID, \
-               .name_length =                          13, \
-               .combination_name =                     "E_14Ro_U_14Di", \
-               .block_count =                          NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E14ROU14DI_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14DI_HW_COMBINATION[] = {NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION};
-
-
-// E-16Di_U-14Di (M303)
-#define NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK_SIZE 107
-static u32 NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 63,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 35
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 36
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 37
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 38
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 39
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 40
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 41
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 42
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 43
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 44
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 45
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 46
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 47
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 48
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 49
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 50
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 51
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 52
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 53
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 54
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 55
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 56
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 57
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 58
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 59
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 60
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 61
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 62
-               1000, 40, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1026
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1027
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1028
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1029
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1030
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1031
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1032
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1033
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1034
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1035
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1036
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1037
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1038
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1039
-};
-
-#define NEURONSPI_BOARD_E16DIU14DI_HW_FEATURES {       \
-               .do_count =                                       0,    \
-               .ro_count =                                       0,    \
-               .ds_count =                                       0,    \
-               .di_count =                                       30,   \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           0,    \
-               .sec_ao_count =                           0,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION { \
-               .combination_board_id =         10, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14DI_ID, \
-               .name_length =                          13, \
-               .combination_name =                     "E_16Di_U_14Di", \
-               .block_count =                          NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E16DIU14DI_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14DI_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION};
-
-// E-4Ai4Ao
-#define NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK_SIZE 15
-static u32 NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 1,   // Register block beginning and size
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ | NEURONSPI_REGFLAG_SYS_READ_ONLY,                  // 0
-               1000, 10, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-};
-
-#define NEURONSPI_BOARD_E4AI4AO_HW_FEATURES {  \
-               .do_count =                                       0,    \
-               .ro_count =                                       0,    \
-               .ds_count =                                       0,    \
-               .di_count =                                       0,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           4,    \
-               .sec_ao_count =                           4,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               0,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            0,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-
-#define NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION { \
-               .combination_board_id =         11, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .name_length =                          8, \
-               .combination_name =                     "E_4Ai4Ao", \
-               .block_count =                          NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E4AI4AO_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION};
-
-// E-4Ai4Ao_P-6Di5Ro (xS50)
-#define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK_SIZE 56
-static u32 NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 27,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                        // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                            // 1
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 2
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 3
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 4
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 5
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 6
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 7
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 8
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 9
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 10
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 11
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 12
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 13
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                       // 14
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 15
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 16
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 17
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 18
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 19
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 20
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 21
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 22
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 23
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 24
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 25
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 26
-               1000, 25, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
-               NEURONSPI_REGFUN_DS_ENABLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1016
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1017
-               NEURONSPI_REGFUN_DS_TOGGLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1018
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1019
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1020
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1021
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1022
-               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1023
-               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1024
-};
-
-#define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_FEATURES {   \
-               .do_count =                                       0,    \
-               .ro_count =                                       6,    \
-               .ds_count =                                       5,    \
-               .di_count =                                       5,    \
-               .led_count =                              0,    \
-               .stm_ai_count =                           0,    \
-               .stm_ao_count =                           0,    \
-               .sec_ai_count =                           4,    \
-               .sec_ao_count =                           4,    \
-               .uart_master_count =              0,    \
-               .uart_slave_count =               1,    \
-               .pwm_channel_count =              0,    \
-               .wd_count =                               1,    \
-               .extension_sys_count =            1,    \
-               .light_count =                            0,    \
-               .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION { \
-               .combination_board_id =         12, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P6DI5RO_ID, \
-               .name_length =                          17, \
-               .combination_name =                     "E_4Ai4Ao_P_6Di5Ro", \
-               .block_count =                          NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION};
-
-// B-485
-#define NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK_SIZE 15
-static u32 NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 1,   // Register block beginning and size
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
-               1000, 10,
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-};
-
-#define NEURONSPI_BOARD_B485_HW_FEATURES {     \
-       .do_count =                                       0,    \
-       .ro_count =                                       0,    \
-       .ds_count =                                       0,    \
-       .di_count =                                       0,    \
-       .led_count =                              0,    \
-       .stm_ai_count =                           0,    \
-       .stm_ao_count =                           0,    \
-       .sec_ai_count =                           4,    \
-       .sec_ao_count =                           4,    \
-       .uart_master_count =              1,    \
-       .uart_slave_count =               0,    \
-       .pwm_channel_count =              0,    \
-       .wd_count =                               1,    \
-       .extension_sys_count =            0,    \
-       .light_count =                            0,    \
-       .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_B485_HW_DEFINITION { \
-               .combination_board_id =         13, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_B485_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .name_length =                          5, \
-               .combination_name =                     "B_485", \
-               .block_count =                          NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_B485_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_B485_HW_COMBINATION[] = {NEURONSPI_BOARD_B485_HW_DEFINITION};
-
-// E-4Light (M613)
-#define NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK_SIZE 35
-static u32 NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 21,  // Register block beginning and size
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 2
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 3
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 4
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 5
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 6
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 7
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 8
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 9
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 10
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 11
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 12
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 13
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 14
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 15
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 16
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 17
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 18
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 19
-               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 20
-               1000, 10,
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
-};
-
-#define NEURONSPI_BOARD_E4LIGHT_HW_FEATURES {  \
-       .do_count =                                       0,    \
-       .ro_count =                                       0,    \
-       .ds_count =                                       0,    \
-       .di_count =                                       0,    \
-       .led_count =                              0,    \
-       .stm_ai_count =                           0,    \
-       .stm_ao_count =                           0,    \
-       .sec_ai_count =                           0,    \
-       .sec_ao_count =                           0,    \
-       .uart_master_count =              0,    \
-       .uart_slave_count =               0,    \
-       .pwm_channel_count =              0,    \
-       .wd_count =                               1,    \
-       .extension_sys_count =            0,    \
-       .light_count =                            4,    \
-       .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION { \
-               .combination_board_id =         14, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4LIGHT_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
-               .name_length =                          8, \
-               .combination_name =                     "E_4Light", \
-               .block_count =                          NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E4LIGHT_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E4LIGHT_HW_COMBINATION[] = {NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION};
-
-// E-4Ai4Ao_U-6Di5Ro (L503)
-#define NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK_SIZE 56
-static u32 NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK_SIZE] = {
-               0, 28,  // Register block beginning and size
-               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                                // 0
-               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                                    // 1
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 2
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 3
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 4
-               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 5
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP,       // 6
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP,       // 7
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 8
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 9
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 10
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 11
-               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 12
-               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 13
-               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,                     // 14
-               NEURONSPI_REGFUN_TX_QUEUE_LEN | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                             // 15
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 16
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 17
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 18
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 19
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 20
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 21
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 22
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 23
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 24
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 25
-               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 26
-               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 27
-               1000, 24, // Register block beginning and size
-               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                                 // 1000
-               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                             // 1001
-               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                             // 1002
-               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                                 // 1003
-               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                   // 1004
-               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1005
-               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1006
-               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 1007
-               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                                   // 1008
-               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                              // 1009
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1010
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1011
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1012
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1013
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1014
-               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1015
-               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                                 // 1016
-               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                               // 1017
-               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                                 // 1018
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1019
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1020
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1021
-               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1022
-               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC                                                                                              // 1023
-};
-
-#define NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_FEATURES {   \
-       .do_count =                                       0,    \
-       .ro_count =                                       5,    \
-       .ds_count =                                       5,    \
-       .di_count =                                       6,    \
-       .led_count =                              0,    \
-       .stm_ai_count =                           0,    \
-       .stm_ao_count =                           0,    \
-       .sec_ai_count =                           4,    \
-       .sec_ao_count =                           4,    \
-       .uart_master_count =              0,    \
-       .uart_slave_count =               0,    \
-       .pwm_channel_count =              0,    \
-       .wd_count =                               1,    \
-       .extension_sys_count =            0,    \
-       .light_count =                            4,    \
-       .owire_count =                            0,    \
-}
-
-#define NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION { \
-               .combination_board_id =         15, \
-               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
-               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U6DI5RO_ID, \
-               .name_length =                          17, \
-               .combination_name =                     "E_4Ai4Ao_U_6Di5Ro", \
-               .block_count =                          NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK_SIZE, \
-               .blocks =                                       NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK, \
-               .features =                                     NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_FEATURES \
-}
-struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION};
-
-/********************
- * Data Definitions *
- ********************/
-
-struct platform_device *neuron_plc_dev;
-
-struct neuronspi_board_combination NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION,  NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION
-};
-
-struct neuronspi_board_combination NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD_SIZE] = {
-               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION, NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION
-};
-
-// Board table
-// Column 4 is the number of 0-indexed registers and column 5 is the number of 1000-indexed ones
-struct neuronspi_board_entry NEURONSPI_BOARDTABLE[NEURONSPI_BOARDTABLE_LEN] = {
-       {.index = 0, .lower_board_id = NEURONSPI_BOARD_LOWER_B1000_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 21,      .config_register_count = 32, .definition = NEURONSPI_BOARD_B1000_HW_COMBINATION},       // B_1000 (S103)
-       {.index = 1, .lower_board_id = NEURONSPI_BOARD_LOWER_E8DI8RO_ID,        .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 19,      .config_register_count = 21, .definition = NEURONSPI_BOARD_E8DI8RO_HW_COMBINATION},     // E-8Di8Ro (M103)
-       {.index = 2, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 1,       .config_register_count = 0,  .definition = NEURONSPI_BOARD_E14RO_HW_COMBINATION},               // E-14Ro
-       {.index = 3, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 1,       .config_register_count = 0,      .definition = NEURONSPI_BOARD_E16DI_HW_COMBINATION},           // E-16Di
-       {.index = 4, .lower_board_id = NEURONSPI_BOARD_LOWER_E8DI8RO_ID,        .upper_board_id = NEURONSPI_BOARD_UPPER_P11DIR485_ID,
-                       .data_register_count = 36,      .config_register_count = 31,  .definition = NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_COMBINATION},   // E-8Di8Ro_P-11DiR485 (xS10)
-       {.index = 5, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_P11DIR485_ID,
-                       .data_register_count = 20,      .config_register_count = 23,  .definition = NEURONSPI_BOARD_E14ROP11DIR485_HW_COMBINATION},     // E-14Ro_P-11DiR485 (xS40)
-       {.index = 6, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_P11DIR485_ID,
-                       .data_register_count = 52,      .config_register_count = 36,  .definition = NEURONSPI_BOARD_E16DIP11DIR485_HW_COMBINATION},     // E-16Di_P-11DiR485 (xS30)
-       {.index = 7, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_U14RO_ID,
-                       .data_register_count = 3,       .config_register_count = 10,  .definition = NEURONSPI_BOARD_E14ROU14RO_HW_COMBINATION}, // E-14Ro_U-14Ro (M403)
-       {.index = 8, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_U14RO_ID,
-                       .data_register_count = 35,      .config_register_count = 29,  .definition = NEURONSPI_BOARD_E16DIU14RO_HW_COMBINATION}, // E-16Di_U-14Ro (M203)
-       {.index = 9, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_U14DI_ID,
-                       .data_register_count = 31,      .config_register_count = 27,  .definition = NEURONSPI_BOARD_E14ROU14DI_HW_COMBINATION}, // E-14Ro_U-14Di (L503)
-       {.index = 10, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,         .upper_board_id = NEURONSPI_BOARD_UPPER_U14DI_ID,
-                       .data_register_count = 63, .config_register_count = 40,   .definition = NEURONSPI_BOARD_E16DIU14DI_HW_COMBINATION},     // E-16Di_U-14Di (M303)
-       {.index = 11, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 1,       .config_register_count = 0,   .definition = NEURONSPI_BOARD_E4AI4AO_HW_COMBINATION},            // E-4Ai4Ao
-       {.index = 12, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_P6DI5RO_ID,
-                       .data_register_count = 27, .config_register_count = 25,   .definition = NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMBINATION}, // E-4Ai4Ao_P-6Di5Ro (xS50)
-       {.index = 13, .lower_board_id = NEURONSPI_BOARD_LOWER_B485_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 1,  .config_register_count = 0,    .definition = NEURONSPI_BOARD_B485_HW_COMBINATION},           // B-485
-       {.index = 14, .lower_board_id = NEURONSPI_BOARD_LOWER_E4LIGHT_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
-                       .data_register_count = 21, .config_register_count = 8,    .definition = NEURONSPI_BOARD_E4LIGHT_HW_COMBINATION},                // E-4Light (M603)
-       {.index = 15, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_U6DI5RO_ID,
-                       .data_register_count = 28, .config_register_count = 24,   .definition = NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION}          // E-4Ai4Ao_U-6Di5Ro (M503)
-};
-
-// Module table
-struct neuronspi_model_definition NEURONSPI_MODELTABLE[NEURONSPI_MODELTABLE_LEN] = {
-               {.eeprom_length = 4, .eeprom_name = "S103", .name_length = 4, .model_name = "S103",
-                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "S103", .name_length = 6, .model_name = "S103-G",
-                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD},
-               {.eeprom_length = 6, .eeprom_name = "S103IQ", .name_length = 7, .model_name = "S103-IQ",
-                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD},
-               {.eeprom_length = 6, .eeprom_name = "S103EO", .name_length = 7, .model_name = "S103-EO",
-                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "M103", .name_length = 4, .model_name = "M103",
-                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "M203", .name_length = 4, .model_name = "M203",
-                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "M303", .name_length = 4, .model_name = "M303",
-                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "M403", .name_length = 4, .model_name = "M403",
-                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "M503", .name_length = 4, .model_name = "M503",
-                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "M603", .name_length = 4, .model_name = "M603",
-                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "L203", .name_length = 4, .model_name = "L203",
-                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "L303", .name_length = 4, .model_name = "L303",
-                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "L403", .name_length = 4, .model_name = "L403",
-                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "L503", .name_length = 4, .model_name = "L503",
-                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD},
-               {.eeprom_length = 4, .eeprom_name = "L513", .name_length = 4, .model_name = "L513",
-                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD}
-};
-
-/************************
- * Non-static Functions *
- ************************/
-
-s32 neuronspi_regmap_invalidate(void *data)
-{
-       int i;
-       int freq_cnt = 0;
-       while (!kthread_should_stop()) {
-               usleep_range(15000,25000);
-               if (freq_cnt == 450001) freq_cnt = 0;
-               for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
-                       if (neuronspi_s_dev[i] != NULL) {
-                               struct neuronspi_driver_data *d_data = spi_get_drvdata(neuronspi_s_dev[i]);
-                               if (d_data->combination_id == 0xFF) {
-                                       continue;
-                               }
-                               neuronspi_regmap_invalidate_device(d_data->reg_map, NEURONSPI_BOARDTABLE[d_data->combination_id].definition, freq_cnt);
-                       }
-               }
-               freq_cnt++;
-       }
-       return 0;
-}
-
-void neuronspi_regmap_invalidate_device(struct regmap *reg_map, struct neuronspi_board_combination *device_def, u32 period_counter)
-{
-       int block_start, block_len, block_counter, current_period, period_len;
-       int i;
-       block_start = -1;
-       block_len = -1;
-       block_counter = 0;
-       period_len = 1;
-
-       for (i = 0; i < device_def->block_count; i++) {
-               if (block_start == -1) {
-                       block_start = device_def->blocks[i];
-                       block_counter = 0;
-               } else if (block_len == -1) {
-                       block_len = device_def->blocks[i];
-               } else if ((block_counter != block_len)) {
-                       current_period = device_def->blocks[i] & 0x00FF0000;
-                       if ((block_counter + 1 != block_len) && ((device_def->blocks[i + 1] & 0x00FF0000) == current_period)) {
-                               period_len++;
-                       } else {
-                               switch (current_period) {
-                               case NEURONSPI_REGFLAG_ACC_AFAP: {
-                                       regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
-                                       break;
-                               }
-                               case NEURONSPI_REGFLAG_ACC_10HZ: {
-                                       if ((period_counter) % 5) {
-                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
-                                       }
-                                       break;
-                               }
-                               case NEURONSPI_REGFLAG_ACC_1HZ: {
-                                       if ((period_counter % 50) == 0) {
-                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
-                                       }
-                                       break;
-                               }
-                               case NEURONSPI_REGFLAG_ACC_6SEC: {
-                                       if ((period_counter % 300) == 0) {
-                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
-                                       }
-                                       break;
-                               }
-                               case NEURONSPI_REGFLAG_ACC_1MIN: {
-                                       if ((period_counter % 3000) == 0) {
-                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
-                                       }
-                                       break;
-                               }
-                               case NEURONSPI_REGFLAG_ACC_15MIN: {
-                                       if ((period_counter % 45000) == 0) {
-                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
-                                       }
-                                       break;
-                               }
-                               default:
-                                       break;
-                               }
-                               period_len = 1;
-                       }
-                       block_counter++;
-               }
-               if (block_counter == block_len) {
-                       block_counter = 0;
-                       block_start = -1;
-                       block_len = -1;
-               }
-       }
-}
-
-int neuronspi_regmap_hw_reg_read(void *context, unsigned int reg, unsigned int *val)
-{
-       struct spi_device *spi = context;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u8 *inp_buf;
-       u8 *outp_buf;
-       int write_length;
-       printk(KERN_INFO "NEURONSPI: RM_REG_READ\n");
-       write_length = neuronspi_spi_compose_single_register_read(reg, &inp_buf, &outp_buf);
-       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
-       memcpy(val, &outp_buf[NEURONSPI_HEADER_LENGTH], sizeof(u16));
-       kfree(inp_buf);
-       kfree(outp_buf);
-       return 0;
-}
-
-int neuronspi_regmap_hw_write(void *context, const void *data, size_t count)
-{
-       BUG_ON(count < 1);
-       return neuronspi_regmap_hw_gather_write(context, data, 1, data + 1, count - 1);
-}
-
-int neuronspi_regmap_hw_reg_write(void *context, unsigned int reg, unsigned int val)
-{
-       struct spi_device *spi = context;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u8 *inp_buf;
-       u8 *outp_buf;
-       int write_length;
-       write_length = neuronspi_spi_compose_single_register_write(reg, &inp_buf, &outp_buf, (val >> 8));
-       printk(KERN_INFO "HW_REG_WRITE l:%d, r:%d, v:%d\n", write_length, reg, (val >> 8));
-       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
-       memcpy(&val, &outp_buf[NEURONSPI_HEADER_LENGTH], sizeof(u16));
-       kfree(inp_buf);
-       kfree(outp_buf);
-       return 0;
-}
-
-int neuronspi_regmap_hw_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size)
-{
-       u16 *mb_reg_buf = (u16*)reg;
-       u32 *mb_val_buf = (u32*)val;
-       struct spi_device *spi = context;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u8 *inp_buf;
-       u8 *outp_buf;
-       int i, write_length;
-       int block_counter = 0;
-       printk(KERN_INFO "HW_REG_GATHER_WRITE:%d, %d, %x, %x\n", val_size, reg_size, mb_reg_buf[0], mb_val_buf[0]);
-       if (reg_size == 1) {
-               neuronspi_regmap_hw_reg_write(context,mb_reg_buf[0],mb_val_buf[0]);
-       } else {
-               for (i = 0; i < reg_size; i++) {
-                       // Swap endianness
-                       cpu_to_be16s((u16*)&(mb_val_buf[i]));
-                       // Check for continuity and read the largest possible continuous block
-                       if (block_counter == (reg_size - 1) || ((mb_reg_buf[i] + 1) != mb_reg_buf[i + 1]))  {
-                               write_length = neuronspi_spi_compose_multiple_register_write(block_counter, mb_reg_buf[i - block_counter], &inp_buf, &outp_buf,
-                                                                                                    (u8*)(&mb_val_buf[i - block_counter]));
-                               neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 125, 1);
-                               block_counter = 0;
-                               kfree(inp_buf);
-                               kfree(outp_buf);
-                       } else {
-                               block_counter++;
-                       }
-               }
-       }
-       return 0;
-}
-
-int neuronspi_create_reg_starts(struct neuronspi_board_regstart_table *out_table, struct neuronspi_board_combination *board) {
-       if (board->features.di_count > 0) {
-               out_table->di_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DI_READ);
-               out_table->di_counter_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DI_COUNTER_UPPER);
-               out_table->di_deboun_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DI_DEBOUNCE);
-               out_table->di_direct_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DS_ENABLE);
-               out_table->di_polar_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DS_POLARITY);
-               out_table->di_toggle_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DS_TOGGLE);
-       }
-       if (board->features.do_count > 0) {
-               out_table->do_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DO_RW);
-               out_table->do_pwm_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_PWM_DUTY);
-               out_table->do_pwm_c_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_PWM_CYCLE);
-               out_table->do_pwm_ps_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_PWM_PRESCALE);
-       }
-       if (board->features.led_count > 0) {
-               out_table->led_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_LED_RW);
-       }
-       if (board->features.light_count > 0) {
-               // TODO: Fill in light bus registers
-       }
-       if (board->features.ro_count > 0) {
-               out_table->ro_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DO_RW);
-       }
-       if (board->features.sec_ai_count > 0) {
-               out_table->sec_ai_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_VER2_READ_LOWER);
-               out_table->sec_ai_mode_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_VER2_MODE);
-       }
-       if (board->features.sec_ao_count > 0) {
-               out_table->sec_ao_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_VER2_RW);
-       }
-       if (board->features.stm_ao_count > 0) {
-               out_table->stm_ao_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN);
-               out_table->stm_ao_mode_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_MODE);
-               out_table->stm_ao_vol_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_V_ERR);
-               out_table->stm_ao_vol_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_V_OFF);
-               out_table->stm_ao_curr_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_I_ERR);
-               out_table->stm_ao_curr_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_I_OFF);
-       }
-       if (board->features.stm_ai_count > 0) {
-               out_table->stm_ai_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN);
-               out_table->stm_ai_mode_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_MODE);
-               out_table->stm_ai_vol_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_V_ERR);
-               out_table->stm_ai_vol_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_V_OFF);
-               out_table->stm_ai_curr_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_I_ERR);
-               out_table->stm_ai_curr_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_I_OFF);
-               out_table->stm_aio_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AIO_BRAIN);
-               out_table->stm_aio_vol_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AIO_BRAIN_ERR);
-               out_table->stm_aio_vol_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AIO_BRAIN_OFF);
-               out_table->vref_inp = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_V_REF_INP);
-       }
-       out_table->uart_queue_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_TX_QUEUE_LEN);
-       out_table->uart_conf_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_RS485_CONFIG);
-       out_table->vref_int = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_V_REF_INT);
-       out_table->wd_timeout_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_MWD_TO);
-       out_table->sys_serial_num = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_SERIAL_NR_LOWER);
-       out_table->sys_sw_ver = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_SW_VER);
-       out_table->sys_hw_ver = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_HW_VER);
-       out_table->sys_hw_flash_ver = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_FLASH_HW_VER);
-       return 0;
-}
-
-s32 neuronspi_find_reg_start(struct neuronspi_board_combination *board, u16 regfun) {
-       int i;
-       int block_start = -1;
-       int block_len = -1;
-       int block_counter = 0;
-       for (i = 0; i < board->block_count; i++) {
-               if (block_start == -1) {
-                       block_start = board->blocks[i];
-               } else if (block_len == -1) {
-                       block_len = board->blocks[i];
-               } else if ((board->blocks[i] & 0xFFFF) == regfun) {
-                       //printk(KERN_INFO "NEURONSPI: Reg Start Fun: %x RegS: %d", regfun, block_start + block_counter);
-                       return block_start + block_counter;
-               } else {
-                       block_counter++;
-               }
-               if (block_counter == block_len) {
-                       block_counter = 0;
-                       block_start = -1;
-                       block_len = -1;
-               }
-       }
-       return -1;
-}
-
-int neuronspi_regmap_hw_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size) {
-       const u16 *mb_reg_buf = reg_buf;
-       u16 *mb_val_buf = val_buf;
-       struct spi_device *spi;
-       struct neuronspi_driver_data *n_spi;
-       u8 *inp_buf;
-       u8 *outp_buf;
-       int i, write_length;
-       int block_counter = 0;
-       if (context == NULL) {
-               return 0;
-       }
-       spi = context;
-       n_spi = spi_get_drvdata(spi);
-       if (n_spi == NULL) {
-               return 0;
-       }
-       for (i = 0; i < (reg_size / 2); i++) {
-               // Check for continuity and read the largest possible continuous block
-               if (block_counter == ((reg_size / 2) - 1) || ((mb_reg_buf[i] + 1) != mb_reg_buf[i + 1])) {
-                       write_length = neuronspi_spi_compose_multiple_register_read(block_counter + 1, mb_reg_buf[i - block_counter], &inp_buf, &outp_buf);
-                       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 125, 1);
-                       memcpy(&mb_val_buf[i - block_counter], &outp_buf[NEURONSPI_HEADER_LENGTH], (block_counter + 1) * 2);
-                       kfree(inp_buf);
-                       kfree(outp_buf);
-                       block_counter = 0;
-               } else {
-                       block_counter++;
-               }
-       }
-       printk(KERN_INFO "NEURONSPI: RM_READ %d %x %d %x\n", reg_size, mb_reg_buf[0], val_size, mb_val_buf[0]);
-       return 0;
-}
-
-s32 neuronspi_find_model_id(u32 probe_count)
-{
-       struct neuronspi_driver_data *n_spi;
-       int i,j, ret = -1;
-       u8 *inv = kzalloc(sizeof(*inv) * NEURONSPI_MODELTABLE_LEN, GFP_KERNEL);
-       for (i = 0; i < probe_count; i++) {
-               if (neuronspi_s_dev[i]) {
-                       n_spi = spi_get_drvdata(neuronspi_s_dev[i]);
-                       for (j = 0; j < NEURONSPI_MODELTABLE_LEN; j++) {
-                               if (i + 1 > NEURONSPI_MODELTABLE[j].combination_count) {
-                                       inv[j] = 1;
-                               } else if (NEURONSPI_MODELTABLE[j].combinations[i].combination_board_id != n_spi->combination_id) {
-                                       inv[j] = 1;
-                               }
-                       }
-               } else {
-                       for (j = 0; j < NEURONSPI_MODELTABLE_LEN; j++) {
-                               if (i + 1 < NEURONSPI_MODELTABLE[j].combination_count) {
-                                       inv[j] = 1;
-                               }
-                       }
-               }
-       }
-       for (i = 0; i < NEURONSPI_MODELTABLE_LEN; i++) {
-               if (inv[i] != 1) {
-                       ret = i;
-                       break;
-               }
-       }
-       kfree(inv);
-       return ret;
-}
-
-
diff --git a/modules/neuron_spi/src/unipi_platform.h b/modules/neuron_spi/src/unipi_platform.h
deleted file mode 100644 (file)
index 8178ebb..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_PLATFORM_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_PLATFORM_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-#include <uapi/linux/iio/types.h>
-
-#include "unipi_common.h"
-
-/*******************
- * Data Structures *
- *******************/
-
-struct neuronspi_board_entry {
-       u16             index;
-       u16             lower_board_id;
-       u16             upper_board_id;
-       u16             data_register_count;
-       u16             config_register_count;
-       struct neuronspi_board_combination *definition;
-};
-
-struct neuronspi_register_block
-{
-       u32     starting_register;
-       u32     register_count;
-       u32             *register_flags;
-};
-
-struct neuronspi_board_features
-{
-       u32             do_count;
-       u32             ro_count;
-       u32             ds_count;
-       u32             di_count;
-       u32             led_count;
-       u32             stm_ai_count;
-       u32             stm_ao_count;
-       u32             sec_ai_count;
-       u32             sec_ao_count;
-       u32             uart_master_count;
-       u32             uart_slave_count;
-       u32             pwm_channel_count;
-       u32             wd_count;
-       u32             extension_sys_count;
-       u32             light_count;
-       u32             owire_count;
-};
-
-struct neuronspi_board_regstart_table
-{
-       u32             do_val_reg;
-       u32             do_val_coil;
-       u32             do_pwm_reg;
-       u32             do_pwm_ps_reg;
-       u32             do_pwm_c_reg;
-       u32             di_val_reg;
-       u32             di_counter_reg;
-       u32             di_direct_reg;
-       u32             di_deboun_reg;
-       u32             di_polar_reg;
-       u32             di_toggle_reg;
-       u32             uart_queue_reg;
-       u32             uart_conf_reg;
-       u32             uart_address_reg;
-       u32             led_val_coil;
-       u32             led_val_reg;
-       u32             wd_val_reg;
-       u32             wd_timeout_reg;
-       u32             wd_nv_sav_coil;
-       u32             wd_reset_coil;
-       u32             reg_start_reg;
-       u32             ro_val_reg;
-       u32             ro_val_coil;
-       u32             vref_inp;
-       u32             vref_int;
-       u32             stm_ao_val_reg;
-       u32             stm_ao_mode_reg;
-       u32             stm_ao_vol_err;
-       u32             stm_ao_vol_off;
-       u32             stm_ao_curr_err;
-       u32             stm_ao_curr_off;
-       u32             stm_ai_val_reg;
-       u32             stm_ai_mode_reg;
-       u32             stm_ai_curr_err;
-       u32             stm_ai_curr_off;
-       u32             stm_ai_vol_err;
-       u32             stm_ai_vol_off;
-       u32             stm_aio_val_reg;
-       u32             stm_aio_vol_err;
-       u32             stm_aio_vol_off;
-       u32             sec_ao_val_reg;
-       u32             sec_ao_mode_reg;
-       u32             sec_ai_val_reg;
-       u32             sec_ai_mode_reg;
-       u32             sys_serial_num;
-       u32             sys_hw_ver;
-       u32             sys_hw_flash_ver;
-       u32             sys_sw_ver;
-};
-
-struct neuronspi_board_combination
-{
-       u32                                                                     combination_board_id;
-       u16                                                                     lower_board_id;
-       u16                                                                     upper_board_id;
-       u32                                                             block_count;
-       size_t                                                          name_length;
-       const char*                                                     combination_name;
-       struct neuronspi_board_features         features;
-       u32                                                                     *blocks;
-};
-
-struct neuronspi_model_definition
-{
-       size_t                                                          eeprom_length;
-       const char*                                             eeprom_name;
-       size_t                                                          name_length;
-       const char*                                                     model_name;
-       u32                                                                     combination_count;
-       struct neuronspi_board_combination      *combinations;
-};
-
-/***************
- * Definitions *
- ***************/
-
-// Lower Boards
-#define NEURONSPI_BOARD_LOWER_B1000_ID         0
-#define NEURONSPI_BOARD_LOWER_E8DI8RO_ID       1
-#define NEURONSPI_BOARD_LOWER_E14RO_ID         2
-#define NEURONSPI_BOARD_LOWER_E16DI_ID         3
-#define NEURONSPI_BOARD_LOWER_E4AI4AO_ID       11
-#define NEURONSPI_BOARD_LOWER_B485_ID          13
-#define NEURONSPI_BOARD_LOWER_E4LIGHT_ID       14
-
-// Upper Boards
-#define NEURONSPI_BOARD_UPPER_NONE_ID          0
-#define NEURONSPI_BOARD_UPPER_P11DIR485_ID     1
-#define NEURONSPI_BOARD_UPPER_U14RO_ID         2
-#define NEURONSPI_BOARD_UPPER_U14DI_ID         3
-#define NEURONSPI_BOARD_UPPER_P6DI5RO_ID       4
-#define NEURONSPI_BOARD_UPPER_U6DI5RO_ID       5
-
-// Register function codes
-// Digital Input Functions
-#define NEURONSPI_FUNGROUP_DI                                  0
-#define NEURONSPI_REGFUN_DI_READ                       0 | NEURONSPI_FUNGROUP_DI << 8
-#define NEURONSPI_REGFUN_DI_COUNTER_LOWER      1 | NEURONSPI_FUNGROUP_DI << 8
-#define NEURONSPI_REGFUN_DI_COUNTER_UPPER      2 | NEURONSPI_FUNGROUP_DI << 8
-#define NEURONSPI_REGFUN_DI_DEBOUNCE           3 | NEURONSPI_FUNGROUP_DI << 8
-#define NEURONSPI_REGFUN_DS_ENABLE                     4 | NEURONSPI_FUNGROUP_DI << 8
-#define NEURONSPI_REGFUN_DS_POLARITY           5 | NEURONSPI_FUNGROUP_DI << 8
-#define NEURONSPI_REGFUN_DS_TOGGLE                     6 | NEURONSPI_FUNGROUP_DI << 8
-
-// Digital Output Functions
-#define NEURONSPI_FUNGROUP_DO                                  1
-#define NEURONSPI_REGFUN_DO_RW                         0 | NEURONSPI_FUNGROUP_DO << 8
-
-// B1000 Analog Output Functions
-#define NEURONSPI_FUNGROUP_AO_BRAIN                            2
-#define NEURONSPI_REGFUN_AO_BRAIN                      0 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
-#define NEURONSPI_REGFUN_AO_BRAIN_MODE         1 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
-#define NEURONSPI_REGFUN_AO_BRAIN_V_ERR                2 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
-#define NEURONSPI_REGFUN_AO_BRAIN_V_OFF                3 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
-#define NEURONSPI_REGFUN_AO_BRAIN_I_ERR        4 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
-#define NEURONSPI_REGFUN_AO_BRAIN_I_OFF        5 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
-
-// B1000 Analog Input Functions
-#define NEURONSPI_FUNGROUP_AI_BRAIN                            3
-#define NEURONSPI_REGFUN_AI_BRAIN                      0 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AIO_BRAIN                     1 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AI_BRAIN_MODE         2 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AI_BRAIN_V_ERR                3 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AI_BRAIN_V_OFF                4 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AI_BRAIN_I_ERR                5 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AI_BRAIN_I_OFF                6 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AIO_BRAIN_ERR         7 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-#define NEURONSPI_REGFUN_AIO_BRAIN_OFF         8 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
-
-// System Functions
-#define NEURONSPI_FUNGROUP_SYSTEM                              4
-#define NEURONSPI_REGFUN_V_REF_INT                     0 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_V_REF_INP                     1 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_LED_RW                                2 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_SW_VER                        3 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_DIDO_COUNT                    4 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_UAIO_COUNT                    5 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_HW_VER                                6 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_FLASH_HW_VER          7 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_SERIAL_NR_LOWER       8 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_SERIAL_NR_UPPER       9 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_INTERRUPTS                    10 | NEURONSPI_FUNGROUP_SYSTEM << 8
-#define NEURONSPI_REGFUN_NONE_TEST                     11 | NEURONSPI_FUNGROUP_SYSTEM << 8
-
-// Watchdog Functions
-#define NEURONSPI_FUNGROUP_MWD                                 5
-#define NEURONSPI_REGFUN_MWD_TO                                0 | NEURONSPI_FUNGROUP_MWD << 8
-#define NEURONSPI_REGFUN_MWD_STATUS                    1 | NEURONSPI_FUNGROUP_MWD << 8
-
-// PWM Functions
-#define NEURONSPI_FUNGROUP_PWM                                 6
-#define NEURONSPI_REGFUN_PWM_DUTY                      0 | NEURONSPI_FUNGROUP_PWM << 8
-#define NEURONSPI_REGFUN_PWM_PRESCALE          1 | NEURONSPI_FUNGROUP_PWM << 8
-#define NEURONSPI_REGFUN_PWM_CYCLE                     2 | NEURONSPI_FUNGROUP_PWM << 8
-
-// UART Functions
-#define NEURONSPI_FUNGROUP_RS485                               7
-#define NEURONSPI_REGFUN_TX_QUEUE_LEN          0 | NEURONSPI_FUNGROUP_RS485 << 8
-#define NEURONSPI_REGFUN_RS485_CONFIG          1 | NEURONSPI_FUNGROUP_RS485 << 8
-#define NEURONSPI_REGFUN_RS485_ADDRESS         2 | NEURONSPI_FUNGROUP_RS485 << 8
-
-// Secondary Analog Output Functions
-#define NEURONSPI_FUNGROUP_AO_VER2                             8
-#define NEURONSPI_REGFUN_AO_VER2_RW                    0 | NEURONSPI_FUNGROUP_AO_VER2 << 8
-
-// Secondary Analog Input Functions
-#define NEURONSPI_FUNGROUP_AI_VER2                             9
-#define NEURONSPI_REGFUN_AI_VER2_READ_LOWER    0 | NEURONSPI_FUNGROUP_AI_VER2 << 8
-#define NEURONSPI_REGFUN_AI_VER2_READ_UPPER    0 | NEURONSPI_FUNGROUP_AI_VER2 << 8
-#define NEURONSPI_REGFUN_AI_VER2_MODE          1 | NEURONSPI_FUNGROUP_AI_VER2 << 8
-
-// Register access flags
-#define NEURONSPI_REGFLAG_ACC_NEVER    0
-#define NEURONSPI_REGFLAG_ACC_AFAP     0x1 << 16
-#define NEURONSPI_REGFLAG_ACC_10HZ     0x2 << 16
-#define NEURONSPI_REGFLAG_ACC_1HZ   0x3 << 16
-#define NEURONSPI_REGFLAG_ACC_6SEC  0x4 << 16
-#define NEURONSPI_REGFLAG_ACC_1MIN  0x5 << 16
-#define NEURONSPI_REGFLAG_ACC_15MIN 0x6 << 16
-#define NEURONSPI_REGFLAG_ACC_ONCE     0x7 << 16
-
-// Register system flags
-#define NEURONSPI_REGFLAG_SYS_READ_ONLY        0x10 << 24
-
-// IIO Modes
-#define NEURONSPI_IIO_AI_STM_MODE_VOLTAGE 0x0
-#define NEURONSPI_IIO_AI_STM_MODE_CURRENT 0x1
-#define NEURONSPI_IIO_AI_STM_MODE_RESISTANCE 0x3
-
-/*********************
- * Data Declarations *
- *********************/
-
-extern struct platform_device *neuron_plc_dev;
-
-// Board Definitions
-extern struct neuronspi_board_combination NEURONSPI_BOARD_B1000_HW_COMBINATION[];                              // B_1000 (S103)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8RO_HW_COMBINATION[];                    // E-8Di8Ro (M103)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E14RO_HW_COMBINATION[];                              // E-14Ro
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DI_HW_COMBINATION[];                              // E-16Di
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_COMBINATION[];   // E-8Di8Ro_P-11DiR485 (xS10)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E14ROP11DIR485_HW_COMBINATION[];             // E-14Ro_P-11DiR485 (xS40)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DIP11DIR485_HW_COMBINATION[];             // E-16Di_P-11DiR485 (xS30)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14RO_HW_COMBINATION[];                 // E-14Ro_U-14Ro (M403)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14RO_HW_COMBINATION[];                 // E-16Di_U-14Ro (M203)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14DI_HW_COMBINATION[];                 // E-14Ro_U-14Di (L503)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14DI_HW_COMBINATION[];                 // E-16Di_U-14Di (M303)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AO_HW_COMBINATION[];                            // E-4Ai4Ao
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMBINATION[];             // E-4Ai4Ao_P-6Di5Ro (xS50)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_B485_HW_COMBINATION[];                               // B-485
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E4LIGHT_HW_COMBINATION[];                            // E-4Light (M613)
-extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION[];             // E-4Ai4Ao_U-6Di5Ro (L503)
-
-// Model Definitions
-#define NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE 1
-extern struct neuronspi_board_combination NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD_SIZE 1
-extern struct neuronspi_board_combination NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD_SIZE 1
-extern struct neuronspi_board_combination NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD_SIZE 1
-extern struct neuronspi_board_combination NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD_SIZE 2
-extern struct neuronspi_board_combination NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD_SIZE 2
-extern struct neuronspi_board_combination NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD_SIZE 2
-extern struct neuronspi_board_combination NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD_SIZE 2
-extern struct neuronspi_board_combination NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD_SIZE 2
-extern struct neuronspi_board_combination NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD_SIZE 2
-extern struct neuronspi_board_combination NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD_SIZE 3
-extern struct neuronspi_board_combination NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD_SIZE 3
-extern struct neuronspi_board_combination NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD_SIZE 3
-extern struct neuronspi_board_combination NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD_SIZE 3
-extern struct neuronspi_board_combination NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD_SIZE];
-#define NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD_SIZE 3
-extern struct neuronspi_board_combination NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD[];
-
-// Board table
-#define NEURONSPI_BOARDTABLE_LEN               16
-extern struct neuronspi_board_entry NEURONSPI_BOARDTABLE[];
-
-// Module table
-#define NEURONSPI_MODELTABLE_LEN               15
-extern struct neuronspi_model_definition NEURONSPI_MODELTABLE[];
-
-/*************************
- * Function Declarations *
- *************************/
-
-int neuronspi_regmap_hw_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size);
-int neuronspi_regmap_hw_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size);
-int neuronspi_regmap_hw_reg_read(void *context, unsigned int reg, unsigned int *val);
-int neuronspi_regmap_hw_reg_write(void *context, unsigned int reg, unsigned int val);
-int neuronspi_regmap_hw_write(void *context, const void *data, size_t count);
-void neuronspi_regmap_invalidate_device(struct regmap *reg_map, struct neuronspi_board_combination *device_def, u32 period_counter);
-s32 neuronspi_regmap_invalidate(void *data);
-int neuronspi_create_reg_starts(struct neuronspi_board_regstart_table *out_table, struct neuronspi_board_combination *board);
-s32 neuronspi_find_reg_start(struct neuronspi_board_combination *board, u16 regfun);
-s32 neuronspi_find_model_id(u32 probe_count);
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_PLATFORM_H_ */
diff --git a/modules/neuron_spi/src/unipi_spi.c b/modules/neuron_spi/src/unipi_spi.c
deleted file mode 100644 (file)
index d58c5c4..0000000
+++ /dev/null
@@ -1,1587 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2017 UniPi Tech
-nologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-/************
- * Includes *
- ************/
-
-#include "unipi_common.h"
-#include "unipi_sysfs.h"
-#include "unipi_uart.h"
-#include "unipi_platform.h"
-#include "unipi_gpio.h"
-#include "unipi_iio.h"
-#include "unipi_misc.h"
-#include "unipi_spi.h"
-
-/********************
- * Data Definitions *
- ********************/
-
-MODULE_DEVICE_TABLE(of, neuronspi_id_match);
-
-struct spi_driver neuronspi_spi_driver =
-{
-       .driver =
-       {
-               .name                   = NEURON_DRIVER_NAME,
-               .of_match_table = of_match_ptr(neuronspi_id_match)
-       },
-       .probe                          = neuronspi_spi_probe,
-       .remove                         = neuronspi_spi_remove,
-};
-
-struct file_operations file_ops =
-{
-       .open                           = neuronspi_open,
-       .read                           = neuronspi_read,
-       .write                          = neuronspi_write,
-       .release                        = neuronspi_release,
-       .owner                          = THIS_MODULE
-};
-
-struct neuronspi_char_driver neuronspi_cdrv =
-{
-       .dev = NULL
-};
-
-struct mutex neuronspi_master_mutex;
-struct spinlock* neuronspi_spi_w_spinlock;
-u8 neuronspi_spi_w_flag = 1;
-u8 neuronspi_probe_count = 0;
-int neuronspi_model_id = -1;
-spinlock_t neuronspi_probe_spinlock;
-struct spi_device* neuronspi_s_dev[NEURONSPI_MAX_DEVS];
-struct task_struct *neuronspi_invalidate_thread;
-
-/************************
- * Non-static Functions *
- ************************/
-
-int neuronspi_open (struct inode *inode_p, struct file *file_p)
-{
-       struct neuronspi_file_data *f_internal_data;
-       if (neuronspi_s_dev == NULL || file_p == NULL || inode_p == NULL) {
-               return -1;
-       }
-       neuronspi_cdrv.open_counter += 1;
-       f_internal_data = kzalloc(sizeof(*f_internal_data), GFP_KERNEL);
-       f_internal_data->recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
-       f_internal_data->send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
-       f_internal_data->spi_device = neuronspi_s_dev;
-       mutex_init(&f_internal_data->lock);
-       file_p->private_data = f_internal_data;
-       return 0;
-}
-
-int neuronspi_release (struct inode *inode_p, struct file *file_p)
-{
-       struct neuronspi_file_data *f_internal_data;
-       if (file_p == NULL) {
-               return -1;
-       }
-       f_internal_data = (struct neuronspi_file_data*)file_p->private_data;
-       f_internal_data->spi_device = NULL;
-       kfree(f_internal_data->recv_buf);
-       f_internal_data->recv_buf = NULL;
-       kfree(f_internal_data->send_buf);
-       f_internal_data->send_buf = NULL;
-       kfree(f_internal_data);
-       file_p->private_data = NULL;
-       neuronspi_cdrv.open_counter -= 1;
-       return 0;
-}
-
-ssize_t neuronspi_read (struct file *file_p, char *buffer, size_t len, loff_t *offset)
-{
-
-       s32 result = 0;
-       u8 device_index = 0;
-       u32 frequency = NEURONSPI_COMMON_FREQ;
-       struct neuronspi_file_data* private_data;
-       struct spi_device* spi_driver_data;
-       struct neuronspi_driver_data* driver_data;
-       // Sanity checking
-       if (neuronspi_cdrv.open_counter == 0) {
-               neuronspi_cdrv.open_counter = 1;
-       }
-       if (buffer == NULL) return -7; // Invalid read buffer
-    if (len == 0) return result; // Empty read
-    if (len > 4095) return -EMSGSIZE;
-    if (file_p == NULL) {
-       printk(KERN_DEBUG "NEURONSPI: File Pointer is NULL\n");
-       return -8;
-    }
-    if (file_p->private_data == NULL) {
-       printk(KERN_DEBUG "NEURONSPI: No Private Data\n");
-       return -1;      // No private data
-    }
-    private_data = (struct neuronspi_file_data*) file_p->private_data;
-    if (private_data == NULL) return -4;
-    device_index = private_data->send_buf[0];
-    spi_driver_data = private_data->spi_device[device_index];  // Get private (driver) data from FP
-    if (spi_driver_data == NULL) return -2;
-    driver_data = spi_get_drvdata(spi_driver_data);
-    if (driver_data == NULL) return -2;
-    if (driver_data->spi_driver == NULL) return -2;    // Invalid private data
-    if (driver_data->first_probe_reply[0] == 0) return -3; // No device present
-    if (driver_data->slower_model) {
-       frequency = NEURONSPI_SLOWER_FREQ;
-    }
-    mutex_lock(&(private_data->lock));
-    if (private_data->recv_buf == NULL) {
-       mutex_unlock(&(private_data->lock));
-       return -10;
-    }
-#if NEURONSPI_DETAILED_DEBUG > 0
-    printk(KERN_INFO "NEURONSPI: Device read %d DEV:%s%d DRV:%s%d\n", private_data->message_len, (spi_driver_data->dev.of_node->name),
-               (spi_driver_data->chip_select), (driver_data->spi_driver->driver.name), (device_index));
-#endif
-    if ((((s32)len) == private_data->message_len + 10)) {
-       memcpy(buffer, private_data->recv_buf, len);
-       result = len;
-    } else if (private_data->message_len == 0) {
-       mutex_unlock(&(private_data->lock));
-       return -9;
-    } else if (len <= private_data->message_len) {
-       result = simple_read_from_buffer(buffer, len, offset, private_data->recv_buf, len);
-    } else {
-       mutex_unlock(&(private_data->lock));
-       return -9;
-    }
-    memset(private_data->recv_buf, 0, NEURONSPI_BUFFER_MAX);
-       mutex_unlock(&(private_data->lock));
-       return result;
-}
-
-
-
-ssize_t neuronspi_write (struct file *file_p, const char *buffer, size_t len, loff_t *w_offset)
-{
-       u8 device_index = 0;
-       s32 result = 0;
-       u32 frequency = NEURONSPI_COMMON_FREQ;
-       s32 transmit_len = len - NEURONSPI_HEADER_LENGTH;
-       s32 send_header = 0;
-       s32 delay = 25;
-       struct neuronspi_file_data* private_data;
-       struct spi_device* spi_driver_data;
-       struct neuronspi_driver_data* driver_data;
-       // Sanity checking
-       if (neuronspi_cdrv.open_counter == 0) {
-               neuronspi_cdrv.open_counter = 1;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: LENGTH:%d\n", len);
-#endif
-       if (buffer == NULL) {
-               return 0; // Void write
-       }
-    if (len == 0) {
-       return result; // Empty write
-    }
-    if (len > 4095) return -EMSGSIZE;
-    if (file_p == NULL) {
-       return -12;
-    }
-    if (file_p->private_data == NULL) {
-       printk(KERN_DEBUG "NEURONSPI: No Private Data\n");
-       return -1;      // No private data
-    }
-    // Read packet header and initialise private data (dependent on each other)
-    device_index = buffer[0];
-    if (device_index > NEURONSPI_MAX_DEVS - 1) return -2;
-    private_data = (struct neuronspi_file_data*) file_p->private_data;
-    spi_driver_data = private_data->spi_device[device_index];  // Get private (driver) data from FP
-    if (spi_driver_data == NULL) return -2;
-    driver_data = spi_get_drvdata(spi_driver_data);
-    if (driver_data == NULL) return -2;
-    if (driver_data->spi_driver == NULL) return -2;    // Invalid private data
-    if (driver_data->first_probe_reply[0] == 0) return -3; // Device not present
-    send_header = buffer[3];
-    if (buffer[4]) {   // Frequency setting
-       frequency = (buffer[4] << 8 | buffer[5]) * 1000;
-    }
-    if (buffer[6]) {   // Delay setting
-       delay = buffer[6];
-    }
-    if (buffer[7]) {   // Device reservation
-       if (buffer[7] == 255) { // Unlock device
-               driver_data->reserved_device = 0;
-       } else if ((driver_data->reserved_device) && buffer[7] != driver_data->reserved_device) {
-               return -4;                              // Another device reserved
-       } else if (!driver_data->reserved_device) {
-               driver_data->reserved_device = buffer[7];       // Reserve the device
-       }
-#ifdef STRICT_RESERVING
-    } else if (driver_data->reserved_device) {
-       return -5;                      // Device reserved
-    }
-    if (driver_data->slower_model) {
-       frequency = NEURONSPI_SLOWER_FREQ;
-    }
-#else
-       } else if (device_index == (driver_data->reserved_device - 1)) {
-               return -5;                      // Device reserved
-       }
-       if (driver_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-#endif
-    mutex_lock(&(private_data->lock));
-    memset(private_data->send_buf, 0, NEURONSPI_BUFFER_MAX );
-    memcpy(private_data->send_buf, buffer, len);
-    memset(private_data->recv_buf, 0, NEURONSPI_BUFFER_MAX );
-    private_data->message_len = transmit_len;
-    spin_lock(neuronspi_spi_w_spinlock);
-    neuronspi_spi_w_flag = 1;
-    spin_unlock(neuronspi_spi_w_spinlock);
-    neuronspi_spi_send_message(spi_driver_data, &private_data->send_buf[NEURONSPI_HEADER_LENGTH], private_data->recv_buf,
-               transmit_len, frequency, delay, send_header);
-    mutex_unlock(&private_data->lock);
-    return len;
-}
-
-s32 neuronspi_spi_uart_write(struct spi_device *spi, u8 *send_buf, u8 length, u8 uart_index)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       s32 transmit_len, i;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
-       u16 crc1, crc2;
-       u32 frequency = NEURONSPI_COMMON_FREQ;
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: UART SPI Write, dev:%d, len:%d\n", uart_index, length);
-#endif
-       if (length == 0) {
-               return -1;
-       }
-       if (length == 1) {
-               transmit_len = 6;
-               message_buf = kzalloc(transmit_len, GFP_KERNEL);
-               memcpy(message_buf, NEURONSPI_SPI_UART_SHORT_MESSAGE, NEURONSPI_SPI_UART_SHORT_MESSAGE_LEN);
-               message_buf[1] = send_buf[0];
-               message_buf[3] = uart_index;
-               crc1 = neuronspi_spi_crc(message_buf, 4, 0);
-               memcpy(&message_buf[4], &crc1, 2);
-       } else {
-               transmit_len = 6 + length + 2;
-               message_buf = kzalloc(transmit_len, GFP_KERNEL);
-               memcpy(message_buf, NEURONSPI_SPI_UART_LONG_MESSAGE, NEURONSPI_SPI_UART_LONG_MESSAGE_LEN);
-               message_buf[1] = length;
-               message_buf[3] = uart_index;
-               crc1 = neuronspi_spi_crc(message_buf, 4, 0);
-               memcpy(&message_buf[4], &crc1, 2);
-               for (i = 0; i < length; i++) {
-                       message_buf[6 + i] = send_buf[i];
-               }
-               crc2 = neuronspi_spi_crc(&message_buf[6], length, crc1);
-               memcpy(&message_buf[6+length], &crc2, 2);
-       }
-       recv_buf = kzalloc(transmit_len, GFP_KERNEL);
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi, message_buf, recv_buf, transmit_len, frequency, 65, 1);
-       }
-       kfree(message_buf);
-       kfree(recv_buf);
-       return 0;
-}
-
-
-void neuronspi_spi_uart_read(struct spi_device* spi, u8 *send_buf, u8 *recv_buf, s32 len, u8 uart_index)
-{
-       s32 transmit_len;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
-       u16 crc1, crc2;
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: UART SPI Read, cs:%d, len:%d\n", uart_index, len);
-#endif
-       if (len <= 2) {
-               memcpy(send_buf, NEURONSPI_SPI_UART_READ_MESSAGE, NEURONSPI_SPI_UART_READ_MESSAGE_LEN);
-               transmit_len = NEURONSPI_SPI_UART_READ_MESSAGE_LEN;
-       } else {
-               memcpy(send_buf, NEURONSPI_SPI_UART_READ_MESSAGE, NEURONSPI_SPI_UART_READ_MESSAGE_LEN);
-               if (len < 100) {
-                       len = (len * 2) + 1;
-               } else {
-                       len = 201;
-               }
-               transmit_len = 5 + len + 6;     // Header (-1 for the byte there) + 4 bytes in second part + 2 bytes of CRC
-               send_buf[1] = len + 3;  // Length of second part (len + 4 - 1)
-
-               crc1 = neuronspi_spi_crc(send_buf, 4, 0);
-               memcpy(&send_buf[4], &crc1, 2);
-               send_buf[7] = len;
-               crc2 = neuronspi_spi_crc(&send_buf[6], len + 3, crc1);
-               memcpy(&send_buf[len + 9], &crc2, 2);
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_INFO "NEURONSPI: UART Device Read len:%d %100ph\n", transmit_len, send_buf);
-#endif
-       }
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi, send_buf, recv_buf, transmit_len, frequency, 65, 1);
-       }
-}
-
-void neuronspi_spi_set_irqs(struct spi_device* spi_dev, u16 to)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       u16 crc1, crc2;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: SPI IRQ Set, Dev-CS:%d, to:%d\n", spi_dev->chip_select, to);
-#endif
-       message_buf = kzalloc(NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN, GFP_KERNEL);
-       recv_buf = kzalloc(NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN, GFP_KERNEL);
-       memcpy(message_buf, NEURONSPI_SPI_IRQ_SET_MESSAGE, NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN);
-       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
-       memcpy(&message_buf[4], &crc1, 2);
-       crc2 = neuronspi_spi_crc(&message_buf[6], NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN - 8, crc1);
-       memcpy(&message_buf[NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN - 2], &crc2, 2);
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN, frequency, 65, 1);
-       }
-       kfree(message_buf);
-       kfree(recv_buf);
-}
-
-void neuronspi_spi_uart_set_cflag(struct spi_device* spi_dev, u8 port, u32 to)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       u16 crc1, crc2;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: SPI TERMIOS Set, Dev-CS:%d, to:%x\n", spi_dev->chip_select, to);
-#endif
-       message_buf = kzalloc(NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
-       recv_buf = kzalloc(NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
-       memcpy(message_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN);
-       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
-       memcpy(&message_buf[4], &crc1, 2);
-       memcpy(&message_buf[10], &to, 4);
-       crc2 = neuronspi_spi_crc(&message_buf[6], NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN - 8, crc1);
-       memcpy(&message_buf[NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN - 2], &crc2, 2);
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, frequency, 65, 1);
-       }
-       kfree(message_buf);
-       kfree(recv_buf);
-}
-
-void neuronspi_spi_uart_set_ldisc(struct spi_device* spi_dev, u8 port, u8 to)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 1
-       printk(KERN_INFO "NEURONSPI: SPI TERMIOS Set, Dev-CS:%d, to:%x\n", spi_dev->chip_select, to);
-#endif
-       neuronspi_spi_compose_single_register_write(503, &message_buf, &recv_buf, to);
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, frequency, 35, 1);
-       }
-       kfree(message_buf);
-       kfree(recv_buf);
-}
-
-u8 neuronspi_spi_uart_get_ldisc(struct spi_device* spi_dev, u8 port)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       u8 outp;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-       neuronspi_spi_compose_single_register_read(503, &message_buf, &recv_buf);
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, frequency, 35, 1);
-       }
-       outp = recv_buf[MODBUS_FIRST_DATA_BYTE + 1];
-#if NEURONSPI_DETAILED_DEBUG > 1
-       printk(KERN_INFO "NEURONSPI: SPI TERMIOS GET, Dev-CS:%d, to:%x\n", spi_dev->chip_select, outp);
-#endif
-       kfree(message_buf);
-       kfree(recv_buf);
-       return outp;
-}
-
-
-/*
- * NOTE: This function uses 64-bit fixed-point arithmetic,
- * which necessitates using the do_div macro to avoid unnecessary long/long division.
- */
-void neuronspi_spi_iio_sec_ai_read_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 sec_ai_val_l = 0;
-       u32 sec_ai_val_h = 0;
-       u32 sec_ai_val_m = 0;
-       u8 sec_ai_exp = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &sec_ai_val_h);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + 1 + (2 * ai_data->index), &sec_ai_val_l);
-       sec_ai_val_m = ((((u32)sec_ai_val_h) << 25) | (((u32)sec_ai_val_l) << 9)) >> 16;
-       sec_ai_exp = (sec_ai_val_h & 0x7F80) >> 7;
-       *val = sec_ai_val_m | 0x00010000;
-       if (142 - ((int)sec_ai_exp) <= 0) {
-               *val = (*val << (((int)sec_ai_exp) - 142)) * 1000;
-               *val2 = 1;
-       } else {
-               *val = *val * 1000;
-               *val2 = 2 << (142 - sec_ai_exp);
-       }
-
-}
-
-void neuronspi_spi_iio_sec_ai_read_current(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 sec_ai_val_l = 0;
-       u32 sec_ai_val_h = 0;
-       u32 sec_ai_val_m = 0;
-       u8 sec_ai_exp = 0;
-
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &sec_ai_val_h);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + 1 + (2 * ai_data->index), &sec_ai_val_l);
-       sec_ai_val_m = ((((u32)sec_ai_val_h) << 25) | (((u32)sec_ai_val_l) << 9)) >> 16;
-       sec_ai_exp = (sec_ai_val_h & 0x7F80) >> 7;
-       *val = sec_ai_val_m | 0x00010000;
-       if (142 - ((int)sec_ai_exp) <= 0) {
-               *val2 = 1;
-               *val = *val << (((int)sec_ai_exp) - 142);
-       } else {
-               *val2 = 2 << (142 - sec_ai_exp);
-       }
-}
-
-void neuronspi_spi_iio_sec_ai_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 sec_ai_val_l = 0;
-       u32 sec_ai_val_h = 0;
-       u32 sec_ai_val_m = 0;
-       u8 sec_ai_exp = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &sec_ai_val_h);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + 1 + (2 * ai_data->index), &sec_ai_val_l);
-       sec_ai_val_m = ((((u32)sec_ai_val_h) << 25) | (((u32)sec_ai_val_l) << 9)) >> 16;
-       sec_ai_exp = (sec_ai_val_h & 0x7F80) >> 7;
-       *val = sec_ai_val_m | 0x00010000;
-       if (142 - ((int)sec_ai_exp) <= 0) {
-               *val2 = 1;
-               *val = *val << (((int)sec_ai_exp) - 142);
-       } else {
-               *val2 = 2 << (142 - sec_ai_exp);
-       }
-}
-
-void neuronspi_spi_iio_sec_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
-{
-       struct neuronspi_sec_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 sec_true_val = (val * 2) / 5;
-       if (val > 10000) val = 10000;
-       regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_val_reg + ao_data->index, sec_true_val);
-}
-
-/*
- * NOTE: This function uses 64-bit fixed-point arithmetic,
- * which necessitates using the do_div macro to avoid unnecessary long/long division.
- */
-void neuronspi_spi_iio_stm_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_stm_ai_data *ai_data = iio_priv(iio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 stm_ai_val = 0;
-       u32 stm_v_int_ref = 0;
-       u32 stm_v_inp_ref = 0;
-       u32 stm_v_err = 0;
-       u32 stm_v_off = 0;
-       u64 stm_true_val = 0;
-       u64 stm_true_ref = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_val_reg, &stm_ai_val);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_vol_err, &stm_v_err);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_vol_off, &stm_v_off);
-       stm_true_ref = ((u64)stm_v_int_ref) * 99000;
-       stm_v_inp_ref = stm_v_inp_ref * 10000;
-       stm_true_val = stm_true_ref * ((u64)(stm_ai_val * 1000));
-       do_div(stm_true_val, stm_v_inp_ref);
-       do_div(stm_true_val, 4096);
-       stm_true_val *= (10000 + stm_v_err);
-       stm_true_val += stm_v_off;
-       do_div(stm_true_val, 10000);
-       *val = stm_true_val;
-}
-
-void neuronspi_spi_iio_stm_ai_read_current(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 stm_ai_val = 0;
-       u32 stm_v_int_ref = 0;
-       u32 stm_v_inp_ref = 0;
-       u32 stm_i_err = 0;
-       u32 stm_i_off = 0;
-       u64 stm_true_val = 0;
-       u64 stm_true_ref = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_val_reg, &stm_ai_val);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_curr_err, &stm_i_err);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_curr_off, &stm_i_off);
-       stm_true_ref = ((u64)stm_v_int_ref) * 330000;
-       stm_v_inp_ref = stm_v_inp_ref * 10000;
-       stm_true_val = stm_true_ref * ((u64)(stm_ai_val * 1000));
-       do_div(stm_true_val, stm_v_inp_ref);
-       do_div(stm_true_val, 4096);
-       stm_true_val *= (10000 + stm_i_err);
-       stm_true_val += stm_i_off;
-       do_div(stm_true_val, 10000);
-       *val = stm_true_val;
-}
-
-void neuronspi_spi_iio_stm_ao_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
-{
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 stm_aio_val = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_aio_val_reg, &stm_aio_val);
-       *val = stm_aio_val;
-}
-
-
-void neuronspi_spi_iio_stm_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
-{
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 stm_v_int_ref = 0;
-       u32 stm_v_inp_ref = 0;
-       u32 stm_v_err = 0;
-       u32 stm_v_off = 0;
-       u64 stm_true_val = val;
-       u64 stm_true_ref = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_vol_err, &stm_v_err);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_vol_off, &stm_v_off);
-       stm_true_ref = ((u64)stm_v_int_ref) * (99000 + stm_v_err) * 1000;
-       stm_v_inp_ref = stm_v_inp_ref * 10000;
-       stm_true_val = ((stm_true_val * 10000) - stm_v_off) * 4095;
-       do_div(stm_true_ref, stm_v_inp_ref);
-       stm_v_inp_ref = stm_true_ref;
-       do_div(stm_true_val, stm_v_inp_ref);
-       do_div(stm_true_val, 10000);
-       if (stm_true_val > 4095) stm_true_val = 4095;
-       regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_val_reg, (unsigned int) stm_true_val);
-}
-
-void neuronspi_spi_iio_stm_ao_set_current(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
-{
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       u32 stm_v_int_ref = 0;
-       u32 stm_v_inp_ref = 0;
-       u32 stm_i_err = 0;
-       u32 stm_i_off = 0;
-       u64 stm_true_val = 0;
-       u64 stm_true_ref = 0;
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_curr_err, &stm_i_err);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_curr_off, &stm_i_off);
-       stm_true_ref = ((u64)stm_v_int_ref) * (330000 + stm_i_err);
-       stm_v_inp_ref = stm_v_inp_ref * 10000;
-       stm_true_val = (stm_true_val * 10000) - stm_i_off;
-       do_div(stm_true_ref, stm_v_inp_ref);
-       do_div(stm_true_ref, 4095);
-       stm_v_inp_ref = stm_true_ref;
-       do_div(stm_true_val, stm_v_inp_ref);
-       if (stm_true_val > 4095) stm_true_val = 4095;
-       regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_val_reg, (unsigned int)stm_true_val);
-}
-
-/*
-static s32 neuronspi_spi_watchdog(void *data)
-{
-       s32 *cycle = (s32 *) data;
-       while (!kthread_should_stop()) {
-               msleep(*cycle);
-               spin_lock(neuronspi_spi_w_spinlock);
-               if (neuronspi_spi_w_flag == 0) {
-                       panic_timeout = -1;
-                       panic("SPI Watchdog Failure\n");
-               } else {
-                       neuronspi_spi_w_flag = 0;
-               }
-               spin_unlock(neuronspi_spi_w_spinlock);
-       }
-       return 0;
-}
-*/
-
-
-
-void neuronspi_spi_send_message(struct spi_device* spi_dev, u8 *send_buf, u8 *recv_buf, s32 len, s32 freq, s32 delay, s32 send_header)
-{
-       s32 i = 0;
-       u16 recv_crc1 = 0;
-       u16 recv_crc2 = 0;
-       u16 packet_crc = 0;
-       s32 trans_count = (len / NEURONSPI_MAX_TX) + 3; // number of transmissions
-       struct spi_message s_msg;
-       struct neuronspi_driver_data *d_data;
-    struct spi_transfer* s_trans;
-       mutex_lock(&neuronspi_master_mutex);
-    s_trans = kzalloc(sizeof(struct spi_transfer) * trans_count, GFP_KERNEL);
-#if NEURONSPI_DETAILED_DEBUG > 1
-    printk(KERN_INFO "NEURONSPI: SPI Master Write, len:%d,\n %100ph\n", len, send_buf);
-#endif
-       if (!send_header) {
-               trans_count -= 1;       // one less transmission as the header is omitted
-       }
-    spi_message_init(&s_msg);
-    for (i = 0; i < trans_count; i++) {
-       memset(&(s_trans[i]), 0, sizeof(s_trans[i]));
-       s_trans[i].delay_usecs = 0;
-       s_trans[i].bits_per_word = 8;
-       s_trans[i].speed_hz = freq;
-       if (i == 0) {
-               s_trans[i].delay_usecs = NEURONSPI_EDGE_DELAY;
-       } else if (i == 1) {
-                   s_trans[i].tx_buf = send_buf;
-                   s_trans[i].rx_buf = recv_buf;
-               if (send_header) {
-                   s_trans[i].delay_usecs = delay;
-                   s_trans[i].len = NEURONSPI_FIRST_MESSAGE_LENGTH;
-               } else {
-                       // If len is more than NEURONSPI_MAX_TX * i, then chunk len is NEURONSPI_MAX_TX, otherwise it's the remainder
-                       s_trans[i].len = (len - (NEURONSPI_MAX_TX * i)) > 0 ? NEURONSPI_MAX_TX : len;
-               }
-       } else if (i == trans_count - 1) {
-               if (send_header) {
-                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
-                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
-                       s_trans[i].len = ((NEURONSPI_MAX_TX * (i - 1)) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 2)));
-               } else {
-                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_MAX_TX * (i - 1)]);
-                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_MAX_TX * (i - 1)]);
-                       s_trans[i].len = ((NEURONSPI_MAX_TX * i) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 1)));
-               }
-               s_trans[i].delay_usecs = NEURONSPI_LAST_TRANSFER_DELAY;
-               // If len is more than NEURONSPI_MAX_TX * i (+ optionally header), then chunk len is NEURONSPI_MAX_TX (+ optionally header),
-               // otherwise it's the remainder
-       } else {
-               if (send_header) {
-                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
-                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
-                       s_trans[i].len = ((NEURONSPI_MAX_TX * (i - 1)) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 2)));
-               } else {
-                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_MAX_TX * (i - 1)]);
-                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_MAX_TX * (i - 1)]);
-                       s_trans[i].len = ((NEURONSPI_MAX_TX * i) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 1)));
-               }
-               // If len is more than NEURONSPI_MAX_TX * i (+ optionally header), then chunk len is NEURONSPI_MAX_TX (+ optionally header),
-               // otherwise it's the remainder
-       }
-       spi_message_add_tail(&(s_trans[i]), &s_msg);
-    }
-    spi_sync(spi_dev, &s_msg);
-    for (i = 0; i < trans_count; i++) {
-       spi_transfer_del(&(s_trans[i]));
-    }
-#if NEURONSPI_DETAILED_DEBUG > 1
-    printk(KERN_INFO "NEURONSPI: SPI Master Read - %d:\n\t%100ph\n\t%100ph\n\t%100ph\n\t%100ph\n", len,recv_buf, &recv_buf[64],
-               &recv_buf[128], &recv_buf[192]);
-#endif
-    d_data = spi_get_drvdata(spi_dev);
-    if (d_data == NULL || (d_data != NULL && !d_data->reserved_device)) {
-               recv_crc1 = neuronspi_spi_crc(recv_buf, 4, 0);
-               memcpy(&packet_crc, &recv_buf[4], 2);
-#if NEURONSPI_DETAILED_DEBUG > 1
-               printk(KERN_INFO "NEURONSPI: SPI CRC1: %x\t COMPUTED CRC1:%x\n", packet_crc, recv_crc1);
-#endif
-               if (recv_crc1 == packet_crc) {
-               // Signal the UART to issue character reads
-#if NEURONSPI_DETAILED_DEBUG > 1
-               printk(KERN_INFO "NEURONSPI: SPI CRC1 Correct");
-#endif
-                       if (d_data && recv_buf[0] == 0x41) {
-                               d_data->uart_buf[0] = recv_buf[3];
-#if NEURONSPI_DETAILED_DEBUG > 0
-                               printk(KERN_INFO "NEURONSPI: Reading UART data for device %d\n", d_data->neuron_index);
-#endif
-                               for (i = 0; i < d_data->uart_data->p_count; i++) {
-                                       if (d_data->uart_data->p[i].dev_index == d_data->neuron_index) {
-                                               neuronspi_uart_handle_rx(&d_data->uart_data->p[i], 1, 1);
-                                       }
-                               }
-                               if (!(d_data->uart_read) && (d_data->uart_count)) {
-                                       d_data->uart_read = recv_buf[2];
-                                       for (i = 0; i < d_data->uart_data->p_count; i++) {
-#if NEURONSPI_DETAILED_DEBUG > 0
-                                       printk(KERN_INFO "NEURONSPI: UART Buffer:%d, UART Local Port Count:%d, UART Global Port Count:%d\n", d_data->uart_read,
-                                                       d_data->uart_count,  d_data->uart_data->p_count);
-#endif
-                                               if (d_data->uart_data->p[i].dev_index == d_data->neuron_index && !d_data->reserved_device) {
-                                                       kthread_queue_work(&d_data->uart_data->kworker, &d_data->uart_data->p[i].rx_work);
-                                               }
-                                       }
-                               }
-                       }
-               }
-#if NEURONSPI_DETAILED_DEBUG > 0
-               else {
-                       printk(KERN_INFO "NEURONSPI: SPI CRC1 Not Correct");
-               }
-#endif
-               recv_crc2 = neuronspi_spi_crc(&recv_buf[6], len - 8, recv_crc1);
-               memcpy(&packet_crc, &recv_buf[len - 2], 2);
-#if NEURONSPI_DETAILED_DEBUG > 1
-               printk(KERN_INFO "NEURONSPI: SPI CRC2: %x\t COMPUTED CRC2:%x\n", packet_crc, recv_crc2);
-#endif
-               if (recv_crc2 != packet_crc) {
-#if NEURONSPI_DETAILED_DEBUG > 0
-                       printk(KERN_INFO "NEURONSPI: SPI CRC2 Not Correct");
-#endif
-                       recv_buf[0] = 0;
-               }
-    }
-
-    mutex_unlock(&neuronspi_master_mutex);
-    kfree(s_trans);
-}
-
-
-
-irqreturn_t neuronspi_spi_irq(s32 irq, void *dev_id)
-{
-       s32 i;
-       struct spi_device *spi;
-       struct neuronspi_driver_data *d_data;
-       struct neuronspi_uart_data *u_data;
-       spi = (struct spi_device *)dev_id;
-       d_data = spi_get_drvdata(spi);
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: SPI IRQ\n");
-#endif
-       if (d_data->uart_count) {
-               u_data = d_data->uart_data;
-               for (i = 0; i < u_data->p_count; i++) {
-                       if (u_data->p[i].dev_index == d_data->neuron_index) {
-                               kthread_queue_work(&u_data->kworker, &u_data->p[i].irq_work);
-                       }
-
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-void neuronspi_spi_led_set_brightness(struct spi_device* spi_dev, enum led_brightness brightness, int id)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       u16 crc1;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: SPI LED Set, Dev-CS:%d, led id:%d\n", spi_dev->chip_select, id);
-#endif
-       message_buf = kzalloc(NEURONSPI_SPI_LED_SET_MESSAGE_LEN, GFP_KERNEL);
-       recv_buf = kzalloc(NEURONSPI_SPI_LED_SET_MESSAGE_LEN, GFP_KERNEL);
-       memcpy(message_buf, NEURONSPI_SPI_LED_SET_MESSAGE, NEURONSPI_SPI_LED_SET_MESSAGE_LEN);
-       message_buf[2] += id;
-       if (brightness > 0) {
-               message_buf[1] = 0x01;
-       } else {
-               message_buf[1] = 0x00;
-       }
-       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
-       memcpy(&message_buf[4], &crc1, 2);
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_LED_SET_MESSAGE_LEN, frequency, 25, 0);
-       }
-       printk(KERN_INFO "NEURONSPI: Brightness set to %d on led %d\n", brightness, id);
-       kfree(message_buf);
-       kfree(recv_buf);
-}
-
-int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id)
-{
-       u8 *recv_buf;
-       bool ret = 0;
-       u32 offset = id / 16;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       recv_buf = kzalloc(4, GFP_KERNEL);
-       printk(KERN_INFO "NEURONSPI: REGMAP TEST: %d\n", regmap_read(d_data->reg_map, d_data->regstart_table->di_val_reg + offset, (void*)recv_buf));
-       if (*recv_buf & (0x1 << offset)) {
-               ret = 1;
-       }
-       kfree(recv_buf);
-       printk(KERN_INFO "NEURONSPI: GPIO DI %d get %d\n", id, ret);
-       return ret;
-}
-
-int neuronspi_spi_gpio_do_set(struct spi_device* spi_dev, u32 id, int value)
-{
-       u32 current_value = 0;
-       bool ret = 0;
-       u32 offset = id / 16;
-       u16 off_val = value << (id % 16);
-       u16 mask = ~(1 << (id % 16));
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       regmap_read(d_data->reg_map, d_data->regstart_table->do_val_reg + offset, &current_value);
-       current_value&= mask;
-       current_value|= off_val;
-       regmap_write(d_data->reg_map, d_data->regstart_table->do_val_reg + offset, current_value);
-       printk(KERN_INFO "NEURONSPI: GPIO DO %d set %d\n", id, value);
-       return ret;
-}
-
-int neuronspi_spi_gpio_ro_set(struct spi_device* spi_dev, u32 id, int value)
-{
-       u32 current_value = 0;
-       bool ret = 0;
-       u32 offset = id / 16;
-       u16 off_val = value << (id % 16);
-       u16 mask = ~(1 << (id % 16));
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       regmap_read(d_data->reg_map, d_data->regstart_table->ro_val_reg + offset, &current_value);
-       current_value&= mask;
-       current_value|= off_val;
-       regmap_write(d_data->reg_map, d_data->regstart_table->ro_val_reg + offset, current_value);
-       printk(KERN_INFO "NEURONSPI: GPIO RO %d set %d\n", id, value);
-       return ret;
-}
-
-
-
-s32 neuronspi_spi_probe(struct spi_device *spi)
-{
-       const struct neuronspi_devtype *devtype;
-       struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
-
-       struct neuronspi_driver_data *n_spi;
-
-       s32 ret, i, no_irq = 0;
-       u8 uart_count = 0;
-       n_spi = kzalloc(sizeof *n_spi, GFP_KERNEL);
-       spin_lock(&neuronspi_probe_spinlock);
-       neuronspi_probe_count++;
-       spin_unlock(&neuronspi_probe_spinlock);
-       if (!n_spi)
-               return -ENOMEM;
-       printk(KERN_INFO "NEURONSPI: Neuronspi Probe Started\n");
-       if (n_spi == NULL || spi == NULL) {
-               return -8;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: Chip Max Hz-%d\n",spi->master->max_speed_hz);
-#endif
-       /* Setup SPI bus */
-       spi->bits_per_word      = 8;
-       spi->mode               = spi->mode ? spi->mode : SPI_MODE_0;
-       spi->max_speed_hz       = spi->max_speed_hz ? spi->max_speed_hz : 12000000;
-       ret = spi_setup(spi);
-       n_spi->neuron_index = spi->chip_select - 1;
-       n_spi->reserved_device = 0;
-
-       if (neuron_plc_dev == NULL) {
-               neuron_plc_dev = platform_device_alloc("unipi_plc", -1);
-               neuron_plc_dev->dev.groups = neuron_plc_attr_groups;
-               platform_device_add(neuron_plc_dev);
-       }
-
-       if (ret)
-               return ret;
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: Chip Max Hz-%d %d\n", spi->master->max_speed_hz, spi->max_speed_hz);
-#endif
-       if (spi->dev.of_node) {
-               const struct of_device_id *of_id =
-                       of_match_device(neuronspi_id_match, &spi->dev);
-               if (!of_id) {
-                       printk(KERN_DEBUG "NEURONSPI: Probe %s does not match a device!\n", *(&spi->dev.of_node->full_name));
-                       return -ENODEV;
-               }
-               of_property_read_u32_array(spi->dev.of_node, "neuron-board-index", &(n_spi->neuron_index), 1);
-               //print_device_tree_node(spi->dev.of_node->parent, 0);
-               devtype = (struct neuronspi_devtype *)of_id->data;
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_INFO "DEVICE TREE NODE FOUND %d\n", n_spi->neuron_index);
-#endif
-       } else {
-               const struct spi_device_id *id_entry = spi_get_device_id(spi);
-               devtype = (struct neuronspi_devtype *)id_entry->driver_data;
-       }
-
-
-       kthread_init_worker(&n_spi->primary_worker);
-
-       n_spi->primary_worker_task = kthread_run(kthread_worker_fn, &n_spi->primary_worker, "neuronspi");
-       if (IS_ERR(n_spi->primary_worker_task )) {
-               ret = PTR_ERR(n_spi->primary_worker_task);
-               return ret;
-       }
-       sched_setscheduler(n_spi->primary_worker_task, SCHED_FIFO, &sched_param);
-
-
-       // We perform an initial probe of registers 1000-1004 to identify the device, using a premade message
-       n_spi->recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
-       n_spi->send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
-       n_spi->first_probe_reply = kzalloc(NEURONSPI_PROBE_MESSAGE_LEN, GFP_KERNEL);    // allocate space for initial probe
-       n_spi->second_probe_reply = kzalloc(NEURONSPI_PROBE_MESSAGE_LEN, GFP_KERNEL); // allocate space for uart probe
-       n_spi->lower_board_id = 0xFF;
-       n_spi->upper_board_id = 0xFF;
-       n_spi->combination_id = 0xFF;
-       n_spi->spi_driver = &neuronspi_spi_driver;
-
-       memcpy(n_spi->send_buf, &NEURONSPI_PROBE_MESSAGE, NEURONSPI_PROBE_MESSAGE_LEN);
-       neuronspi_spi_send_message(spi, n_spi->send_buf, n_spi->first_probe_reply, NEURONSPI_PROBE_MESSAGE_LEN, NEURONSPI_DEFAULT_FREQ, 25, 1);
-
-       // Throw away the first message - the associated SPI Master is sometimes not properly initialised at this point
-       i = 0;
-       do {
-               memcpy(n_spi->send_buf, &NEURONSPI_PROBE_MESSAGE, NEURONSPI_PROBE_MESSAGE_LEN);
-               memset(n_spi->first_probe_reply, 0, NEURONSPI_PROBE_MESSAGE_LEN);
-               neuronspi_spi_send_message(spi, n_spi->send_buf, n_spi->first_probe_reply, NEURONSPI_PROBE_MESSAGE_LEN, NEURONSPI_DEFAULT_FREQ, 25, 1);
-               i++;
-               if (i > 1000) { // Sanity check to prevent looping if we get constant UART/0x41 messages
-                       ret = -4;
-                       kfree(n_spi);
-                       printk(KERN_INFO "NEURONSPI: Probe did not detect a valid Neuron device on CS %d\n", spi->chip_select);
-                       return ret;
-               }
-       } while (n_spi->first_probe_reply[0] == 0x41);  // UART messages should be ignored
-
-       if (n_spi->first_probe_reply[0] != 0) {         // CRC error sets the first byte to 0
-               uart_count = n_spi->first_probe_reply[14] & 0x0f;
-               for (i = 0; i < NEURONSPI_BOARDTABLE_LEN; i++) {
-                       if (n_spi->first_probe_reply[19] == NEURONSPI_BOARDTABLE[i].lower_board_id) {
-                               if (n_spi->combination_id == 0xFF && NEURONSPI_BOARDTABLE[i].upper_board_id == 0) {
-                                       n_spi->combination_id = NEURONSPI_BOARDTABLE[i].index;
-                               }
-                               if (n_spi->lower_board_id == 0xFF) {
-                                       n_spi->lower_board_id = n_spi->first_probe_reply[17];
-                               }
-                               if (n_spi->first_probe_reply[17] == NEURONSPI_BOARDTABLE[i].index) {
-                                       n_spi->combination_id = n_spi->first_probe_reply[17];
-                                       n_spi->upper_board_id = NEURONSPI_BOARDTABLE[i].upper_board_id;
-                               }
-                       }
-               }
-       } else {
-               ret = -5;
-               kfree(n_spi);
-               printk(KERN_INFO "NEURONSPI: Probe did not detect a valid Neuron device on CS %d\n", spi->chip_select);
-               return ret;
-       }
-
-       if (n_spi->lower_board_id != 0xFF && n_spi->combination_id != 0xFF) {
-               n_spi->features = kzalloc(sizeof(struct neuronspi_board_features), GFP_KERNEL);
-               n_spi->features = &(NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->features);
-       } else {
-               n_spi->features = NULL;
-       }
-
-       n_spi->ideal_frequency = NEURONSPI_COMMON_FREQ;
-       for (i = 0; i < NEURONSPI_SLOWER_MODELS_LEN; i++) {
-               if (NEURONSPI_SLOWER_MODELS[i] == (n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18])) {
-                       n_spi->slower_model = 1;
-                       n_spi->ideal_frequency = NEURONSPI_SLOWER_FREQ;
-               }
-       }
-       if (n_spi->lower_board_id != 0xFF && n_spi->combination_id != 0xFF) {
-               printk(KERN_INFO "NEURONSPI: Probe detected Neuron Board %s (L:%x U:%x C:%x) Index: %d Fw: v%d.%d on CS %d, \
-Uart count: %d - reg1000: %x, reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
-                               NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name,
-                               n_spi->lower_board_id, n_spi->upper_board_id, n_spi->combination_id,  n_spi->neuron_index,
-                               n_spi->first_probe_reply[11],  n_spi->first_probe_reply[10], spi->chip_select, uart_count,
-                               n_spi->first_probe_reply[11] << 8 | n_spi->first_probe_reply[10],
-                               n_spi->first_probe_reply[13] << 8 | n_spi->first_probe_reply[12], n_spi->first_probe_reply[15] << 8 | n_spi->first_probe_reply[14],
-                               n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16], n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18]);
-       } else if (n_spi->lower_board_id != 0xFF) {
-               printk(KERN_INFO "NEURONSPI: Probe detected Neuron Board L:%x C:??? Index: %d Fw: v%d.%d on CS %d, Uart count: %d - reg1000: %x, \
-reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
-                               n_spi->lower_board_id, n_spi->neuron_index, n_spi->first_probe_reply[11],  n_spi->first_probe_reply[10],
-                               spi->chip_select, uart_count, n_spi->first_probe_reply[11] << 8 | n_spi->first_probe_reply[10],
-                               n_spi->first_probe_reply[13] << 8 | n_spi->first_probe_reply[12], n_spi->first_probe_reply[15] << 8 | n_spi->first_probe_reply[14],
-                               n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16], n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18]);
-       } else {
-               printk(KERN_INFO "NEURONSPI: Probe detected Neuron Board L:??? C:??? Index: %d Fw: v%d.%d on CS %d, Uart count: %d - reg1000: %x, \
-reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
-                               n_spi->neuron_index, n_spi->first_probe_reply[11],  n_spi->first_probe_reply[10], spi->chip_select, uart_count,
-                               n_spi->first_probe_reply[11] << 8 | n_spi->first_probe_reply[10], n_spi->first_probe_reply[13] << 8 | n_spi->first_probe_reply[12],
-                               n_spi->first_probe_reply[15] << 8 | n_spi->first_probe_reply[14], n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16],
-                               n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18]);
-       }
-       printk(KERN_INFO "NEURONSPI: Neuron device %s on CS %d uses SPI communication freq. %d Hz\n",
-                       NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name,
-                       spi->chip_select, n_spi->ideal_frequency);
-
-       n_spi->reg_map = regmap_init(&(spi->dev), &neuronspi_regmap_bus, spi, &neuronspi_regmap_config_default);
-       spin_lock_init(&n_spi->sysfs_regmap_lock);
-       if (n_spi->features) {
-               n_spi->regstart_table = kzalloc(sizeof(struct neuronspi_board_regstart_table), 1);
-               neuronspi_create_reg_starts(n_spi->regstart_table, NEURONSPI_BOARDTABLE[n_spi->combination_id].definition);
-       } else {
-               n_spi->regstart_table = NULL;
-       }
-
-
-       // Check for user-configurable LED devices
-       if (n_spi->features && n_spi->features->led_count > 0) {
-               printk(KERN_INFO "NEURONSPI: LED model %s with %d LEDs detected at CS: %d\n",
-                               NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name,
-                               n_spi->features->led_count, spi->chip_select);
-               n_spi->led_driver = kzalloc(sizeof(struct neuronspi_led_driver) * n_spi->features->led_count, GFP_KERNEL);
-               for (i = 0; i < n_spi->features->led_count; i++) {
-                       kthread_init_work(&(n_spi->led_driver[i].led_work), neuronspi_led_proc);
-               }
-       }
-
-
-       if (uart_count && neuronspi_uart == NULL) {     // Register UART if not registered
-               neuronspi_uart = kzalloc(sizeof(struct uart_driver), GFP_KERNEL);
-               neuronspi_uart->owner           = THIS_MODULE;
-               neuronspi_uart->dev_name        = "ttyNS";
-               neuronspi_uart->driver_name = "ttyNS";
-               neuronspi_uart->nr      = NEURONSPI_MAX_UART;
-               ret = uart_register_driver(neuronspi_uart);
-               if (ret) {
-                       printk(KERN_ERR "NEURONSPI:Failed to register the neuronspi uart driver, ERR:%d\n", ret);
-               } else {
-#if NEURONSPI_DETAILED_DEBUG > 0
-                       printk(KERN_DEBUG "NEURONSPI: UART driver registered successfully!\n");
-#endif
-               }
-               if (neuronspi_uart_glob_data != NULL) {
-                       printk(KERN_ERR "NEURONSPI:Uart data already allocated!\n");
-               } else {
-                       neuronspi_uart_glob_data = kzalloc(sizeof(struct neuronspi_uart_data), GFP_KERNEL);
-#if NEURONSPI_DETAILED_DEBUG > 0
-                       printk(KERN_DEBUG "NEURONSPI: UART driver data allocated successfully!\n");
-#endif
-               }
-
-       }
-       if (neuronspi_uart_glob_data != NULL) {
-               n_spi->uart_data = neuronspi_uart_glob_data;
-       }
-       n_spi->char_driver = &neuronspi_cdrv;
-       if (uart_count) {
-               n_spi->serial_driver = neuronspi_uart;
-       } else {
-               n_spi->serial_driver = NULL;
-       }
-       n_spi->uart_count = uart_count;
-
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: CHIP SELECT %d\n", spi->chip_select);
-#endif
-       spin_lock(&neuronspi_probe_spinlock);
-       neuronspi_s_dev[n_spi->neuron_index] = spi;
-       spi_set_drvdata(neuronspi_s_dev[n_spi->neuron_index], n_spi);
-       if (neuronspi_probe_count == NEURONSPI_MAX_DEVS) {
-               printk(KERN_INFO "NEURONSPI: MAXPROBECOUNT\n");
-               neuronspi_model_id = neuronspi_find_model_id(neuronspi_probe_count);
-       }
-       spin_unlock(&neuronspi_probe_spinlock);
-       if (neuronspi_model_id != -1) {
-               printk(KERN_INFO "NEURONSPI: Detected Neuron board combination corresponding to %s\n", NEURONSPI_MODELTABLE[neuronspi_model_id].model_name);
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: SPI IRQ: %d", spi->irq);
-#endif
-       strcpy(n_spi->platform_name, "io_group0");
-       n_spi->platform_name[8] = n_spi->neuron_index + '1';
-       n_spi->board_device = platform_device_alloc(n_spi->platform_name, -1);
-       n_spi->board_device->dev.parent = &(neuron_plc_dev->dev);
-       n_spi->board_device->dev.groups = neuron_board_attr_groups;
-       n_spi->board_device->dev.driver = &neuronspi_spi_driver.driver;
-       platform_device_add(n_spi->board_device);
-       platform_set_drvdata(n_spi->board_device, n_spi);
-
-       if (!(neuronspi_cdrv.major_number)) { // Register character device if it doesn't exist
-               ret = char_register_driver();
-               if (ret) {
-                       printk(KERN_ERR "NEURONSPI: Failed to register the neuronspi character driver, ERR:%d\n", ret);
-               }
-       }
-
-       if (n_spi->features) {
-               if (n_spi->features->led_count) {
-                       for (i = 0; i < n_spi->features->led_count; i++) {
-                               strcpy(n_spi->led_driver[i].name, "neuron:green:uled-x1");
-                               n_spi->led_driver[i].name[19] = i + '1';
-                               // Initialise the rest of the structure
-                               n_spi->led_driver[i].id = i;
-                               n_spi->led_driver[i].brightness = LED_OFF;
-                               n_spi->led_driver[i].spi = spi;
-                               spin_lock_init(&n_spi->led_driver[i].lock);
-                               n_spi->led_driver[i].ldev.name = n_spi->led_driver[i].name;
-                               n_spi->led_driver[i].ldev.brightness = n_spi->led_driver[i].brightness;
-                               n_spi->led_driver[i].ldev.brightness_set = neuronspi_led_set_brightness;
-                               led_classdev_register(&(n_spi->board_device->dev), &(n_spi->led_driver[i].ldev));
-                       }
-               }
-#ifdef CONFIG_GPIOLIB
-
-               if (n_spi->features->di_count) {
-                       n_spi->di_driver = kzalloc(sizeof(struct neuronspi_di_driver*) * n_spi->features->di_count, GFP_KERNEL);
-                       for (i = 0; i < n_spi->features->di_count; i++) {
-                               n_spi->di_driver[i] = kzalloc(sizeof(struct neuronspi_di_driver), GFP_KERNEL);
-                               strcpy(n_spi->di_driver[i]->name, "di_0_00");
-                               n_spi->di_driver[i]->name[3] = n_spi->neuron_index + '1';
-                               n_spi->di_driver[i]->name[5] = ((i + 1) / 10) + '0';
-                               n_spi->di_driver[i]->name[6] = ((i + 1) % 10) + '0';
-                               n_spi->di_driver[i]->di_index = i;
-                               n_spi->di_driver[i]->spi = spi;
-                               n_spi->di_driver[i]->plat_dev = platform_device_alloc(n_spi->di_driver[i]->name, -1);
-                               n_spi->di_driver[i]->plat_dev->dev.parent = &(n_spi->board_device->dev);
-                               n_spi->di_driver[i]->plat_dev->dev.groups = neuron_gpio_di_attr_groups;
-                               n_spi->di_driver[i]->plat_dev->dev.driver = &neuronspi_spi_driver.driver;
-                               platform_device_add(n_spi->di_driver[i]->plat_dev);
-                               platform_set_drvdata(n_spi->di_driver[i]->plat_dev, n_spi->di_driver[i]);
-                               n_spi->di_driver[i]->gpio_c.owner = THIS_MODULE;
-                               n_spi->di_driver[i]->gpio_c.parent = &(n_spi->di_driver[i]->plat_dev->dev);
-                               n_spi->di_driver[i]->gpio_c.label = "neuron_di";
-                               n_spi->di_driver[i]->gpio_c.can_sleep = 1;
-                               n_spi->di_driver[i]->gpio_c.ngpio = 1;
-                               n_spi->di_driver[i]->gpio_c.base = -1;
-                               n_spi->di_driver[i]->gpio_c.direction_input = neuronspi_gpio_di_direction_input;
-                               n_spi->di_driver[i]->gpio_c.get = neuronspi_gpio_di_get;
-                               gpiochip_add_data(&n_spi->di_driver[i]->gpio_c, n_spi->di_driver[i]);
-                       }
-               }
-
-               if (n_spi->features->do_count) {
-                       n_spi->do_driver = kzalloc(sizeof(struct neuronspi_do_driver*) * n_spi->features->do_count, GFP_KERNEL);
-                       for (i = 0; i < n_spi->features->do_count; i++) {
-                               n_spi->do_driver[i] = kzalloc(sizeof(struct neuronspi_do_driver), GFP_KERNEL);
-                               strcpy(n_spi->do_driver[i]->name, "do_0_00");
-                               n_spi->do_driver[i]->name[3] = n_spi->neuron_index + '1';
-                               n_spi->do_driver[i]->name[5] = ((i + 1) / 10) + '0';
-                               n_spi->do_driver[i]->name[6] = ((i + 1) % 10) + '0';
-                               n_spi->do_driver[i]->do_index = i;
-                               n_spi->do_driver[i]->spi = spi;
-                               n_spi->do_driver[i]->plat_dev = platform_device_alloc(n_spi->do_driver[i]->name, -1);
-                               n_spi->do_driver[i]->plat_dev->dev.parent = &(n_spi->board_device->dev);
-                               n_spi->do_driver[i]->plat_dev->dev.groups = neuron_gpio_do_attr_groups;
-                               n_spi->do_driver[i]->plat_dev->dev.driver = &neuronspi_spi_driver.driver;
-                               platform_device_add(n_spi->do_driver[i]->plat_dev);
-                               platform_set_drvdata(n_spi->do_driver[i]->plat_dev, n_spi->do_driver[i]);
-                               n_spi->do_driver[i]->gpio_c.owner = THIS_MODULE;
-                               n_spi->do_driver[i]->gpio_c.parent = &(n_spi->do_driver[i]->plat_dev->dev);
-                               n_spi->do_driver[i]->gpio_c.label = "neuron_do";
-                               n_spi->do_driver[i]->gpio_c.can_sleep = 1;
-                               n_spi->do_driver[i]->gpio_c.ngpio = n_spi->features->do_count;
-                               n_spi->do_driver[i]->gpio_c.base = -1;
-                               n_spi->do_driver[i]->gpio_c.direction_output = neuronspi_gpio_do_direction_output;
-                               n_spi->do_driver[i]->gpio_c.set = neuronspi_gpio_do_set;
-                               gpiochip_add_data(&n_spi->do_driver[i]->gpio_c, n_spi->do_driver[i]);
-                       }
-               }
-
-               if (n_spi->features->ro_count) {
-                       n_spi->ro_driver = kzalloc(sizeof(struct neuronspi_ro_driver*) * n_spi->features->ro_count, GFP_KERNEL);
-                       for (i = 0; i < n_spi->features->ro_count; i++) {
-                               n_spi->ro_driver[i] = kzalloc(sizeof(struct neuronspi_ro_driver), GFP_KERNEL);
-                               strcpy(n_spi->ro_driver[i]->name, "ro_0_00");
-                               n_spi->ro_driver[i]->name[3] = n_spi->neuron_index + '1';
-                               n_spi->ro_driver[i]->name[5] = ((i + 1) / 10) + '0';
-                               n_spi->ro_driver[i]->name[6] = ((i + 1) % 10) + '0';
-                               n_spi->ro_driver[i]->ro_index = i;
-                               n_spi->ro_driver[i]->spi = spi;
-                               n_spi->ro_driver[i]->plat_dev = platform_device_alloc(n_spi->ro_driver[i]->name, -1);
-                               n_spi->ro_driver[i]->plat_dev->dev.parent = &(n_spi->board_device->dev);
-                               n_spi->ro_driver[i]->plat_dev->dev.groups = neuron_gpio_ro_attr_groups;
-                               n_spi->ro_driver[i]->plat_dev->dev.driver = &neuronspi_spi_driver.driver;
-                               platform_device_add(n_spi->ro_driver[i]->plat_dev);
-                               platform_set_drvdata(n_spi->ro_driver[i]->plat_dev, n_spi->ro_driver[i]);
-                               n_spi->ro_driver[i]->gpio_c.owner = THIS_MODULE;
-                               n_spi->ro_driver[i]->gpio_c.parent = &(n_spi->ro_driver[i]->plat_dev->dev);
-                               n_spi->ro_driver[i]->gpio_c.label = "neuron_ro";
-                               n_spi->ro_driver[i]->gpio_c.can_sleep = 1;
-                               n_spi->ro_driver[i]->gpio_c.ngpio = n_spi->features->ro_count;
-                               n_spi->ro_driver[i]->gpio_c.base = -1;
-                               n_spi->ro_driver[i]->gpio_c.direction_output = neuronspi_gpio_ro_direction_output;
-                               n_spi->ro_driver[i]->gpio_c.set = neuronspi_gpio_ro_set;
-                               gpiochip_add_data(&n_spi->ro_driver[i]->gpio_c, n_spi->ro_driver[i]);
-                       }
-               }
-
-#endif
-               if (n_spi->features->stm_ai_count) {
-                       n_spi->stm_ai_driver = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_stm_ai_data));
-                       ((struct neuronspi_stm_ai_data*)iio_priv(n_spi->stm_ai_driver))->parent = spi;
-                       n_spi->stm_ai_driver->modes = INDIO_DIRECT_MODE;
-                       n_spi->stm_ai_driver->currentmode = INDIO_DIRECT_MODE;
-                       n_spi->stm_ai_driver->name = "ai_type_a";
-                       n_spi->stm_ai_driver->dev.parent = &(n_spi->board_device->dev);
-                       dev_set_name(&n_spi->stm_ai_driver->dev, "ai_%d_1",     (int)n_spi->neuron_index + 1);
-                       n_spi->stm_ai_driver->num_channels = 2;
-                       n_spi->stm_ai_driver->channels = neuronspi_stm_ai_chan_spec;
-                       n_spi->stm_ai_driver->info = &neuronspi_stm_ai_info;
-                       iio_device_register(n_spi->stm_ai_driver);
-               }
-               if (n_spi->features->stm_ao_count) {
-                       n_spi->stm_ao_driver = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_stm_ai_data));
-                       ((struct neuronspi_stm_ao_data*)iio_priv(n_spi->stm_ao_driver))->parent = spi;
-                       n_spi->stm_ao_driver->modes = INDIO_DIRECT_MODE;
-                       n_spi->stm_ao_driver->currentmode = INDIO_DIRECT_MODE;
-                       n_spi->stm_ao_driver->name = "ao_type_a";
-                       n_spi->stm_ao_driver->dev.parent = &(n_spi->board_device->dev);
-                       dev_set_name(&n_spi->stm_ao_driver->dev, "ao_%d_1",     (int)n_spi->neuron_index + 1);
-                       n_spi->stm_ao_driver->num_channels = 3;
-                       n_spi->stm_ao_driver->channels = neuronspi_stm_ao_chan_spec;
-                       n_spi->stm_ao_driver->info = &neuronspi_stm_ao_info;
-                       iio_device_register(n_spi->stm_ao_driver);
-               }
-               if (n_spi->features->sec_ai_count) {
-                       n_spi->sec_ai_driver = kzalloc(sizeof(struct neuronspi_sec_ai_data*) * n_spi->features->sec_ai_count, GFP_KERNEL);
-                       for (i = 0; i < n_spi->features->sec_ai_count; i++) {
-                               n_spi->sec_ai_driver[i] = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_sec_ai_data));
-                               ((struct neuronspi_sec_ai_data*)iio_priv(n_spi->sec_ai_driver[i]))->parent = spi;
-                               n_spi->sec_ai_driver[i]->modes = INDIO_DIRECT_MODE;
-                               n_spi->sec_ai_driver[i]->currentmode = INDIO_DIRECT_MODE;
-                               n_spi->sec_ai_driver[i]->name = "ai_type_b";
-                               n_spi->sec_ai_driver[i]->dev.parent = &(n_spi->board_device->dev);
-                               dev_set_name(&n_spi->sec_ai_driver[i]->dev, "ai_%d_%d", (int)n_spi->neuron_index + 1, (int)i + 1);
-                               n_spi->sec_ai_driver[i]->num_channels = 3;
-                               n_spi->sec_ai_driver[i]->channels = neuronspi_sec_ai_chan_spec;
-                               n_spi->sec_ai_driver[i]->info = &neuronspi_sec_ai_info;
-                               iio_device_register(n_spi->sec_ai_driver[i]);
-                       }
-               }
-               if (n_spi->features->sec_ao_count) {
-                       n_spi->sec_ao_driver = kzalloc(sizeof(struct neuronspi_sec_ao_data*) * n_spi->features->sec_ao_count, GFP_KERNEL);
-                       for (i = 0; i < n_spi->features->sec_ao_count; i++) {
-                               n_spi->sec_ao_driver[i] = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_sec_ao_data));
-                               ((struct neuronspi_sec_ao_data*)iio_priv(n_spi->sec_ao_driver[i]))->parent = spi;
-                               n_spi->sec_ao_driver[i]->modes = INDIO_DIRECT_MODE;
-                               n_spi->sec_ao_driver[i]->currentmode = INDIO_DIRECT_MODE;
-                               n_spi->sec_ao_driver[i]->name = "ao_type_b";
-                               n_spi->sec_ao_driver[i]->dev.parent = &(n_spi->board_device->dev);
-                               dev_set_name(&n_spi->sec_ao_driver[i]->dev, "ao_%d_%d", (int)n_spi->neuron_index + 1, (int)i + 1);
-                               n_spi->sec_ao_driver[i]->num_channels = 1;
-                               n_spi->sec_ao_driver[i]->channels = neuronspi_sec_ao_chan_spec;
-                               n_spi->sec_ao_driver[i]->info = &neuronspi_sec_ao_info;
-                               iio_device_register(n_spi->sec_ao_driver[i]);
-                       }
-               }
-       }
-
-       if (uart_count) {
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_DEBUG "NEURONSPI: UART registration 1\n");
-#endif
-               n_spi->uart_buf = kzalloc(NEURONSPI_FIFO_SIZE, GFP_KERNEL);
-               neuronspi_uart_probe(spi, n_spi->neuron_index);
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_DEBUG "NEURONSPI: UART PROBE MCTRL:%d\n", neuronspi_spi_uart_get_cflag(spi, 0));
-#endif
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: UART registration\n");
-#endif
-       neuronspi_spi_set_irqs(spi, 0x5);
-       for (i = 0; i < NEURONSPI_NO_INTERRUPT_MODELS_LEN; i++) {
-               if (NEURONSPI_NO_INTERRUPT_MODELS[i] == (n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16])) {
-                       no_irq = 1;
-               }
-       }
-
-       n_spi->poll_thread = NULL;
-       if (!no_irq) {
-               n_spi->no_irq = 0;
-               ret = devm_request_irq(&(spi->dev), spi->irq, neuronspi_spi_irq, 0x81, dev_name(&(spi->dev)), spi);
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_DEBUG "NEURONSPI: IRQ registration, ret:%d\n", ret);
-#endif
-       } else {
-               n_spi->no_irq = 1;
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_DEBUG "NEURONSPI: NO IRQ ON THIS MODEL !!\n");
-#endif
-       }
-
-       return ret;
-}
-
-u32 neuronspi_spi_uart_get_cflag(struct spi_device* spi_dev, u8 port)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       u16 crc1, crc2, ret;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
-       s32 frequency = NEURONSPI_COMMON_FREQ;
-       if (d_data->slower_model) {
-               frequency = NEURONSPI_SLOWER_FREQ;
-       }
-       message_buf = kzalloc(NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
-       recv_buf = kzalloc(NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
-       memcpy(message_buf, NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE, NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN);
-       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
-       memcpy(&message_buf[4], &crc1, 2);
-       crc2 = neuronspi_spi_crc(&message_buf[6], NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN - 8, crc1);
-       memcpy(&message_buf[NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN - 2], &crc2, 2);
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN, frequency, 65, 1);
-       }
-       ret = ((u32*)recv_buf)[5];
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: SPI TERMIOS Get, Dev-CS:%d, val:%x\n", spi_dev->chip_select, ret);
-#endif
-       kfree(message_buf);
-       kfree(recv_buf);
-       return ret;
-}
-
-s32 neuronspi_spi_remove(struct spi_device *spi)
-{
-       int i;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       if (n_spi) {
-               if (n_spi->led_driver) {
-                       for (i = 0; i < n_spi->features->led_count; i++) {
-                               led_classdev_unregister(&(n_spi->led_driver[i].ldev));
-                       }
-                       kthread_flush_worker(&n_spi->primary_worker);
-                       kfree(n_spi->led_driver);
-                       n_spi->led_driver = NULL;
-               }
-               printk(KERN_INFO "NEURONSPI: LED DRIVER UNREGISTERED\n");
-               if (n_spi->di_driver) {
-                       for (i = 0; i < n_spi->features->di_count; i++) {
-                               gpiochip_remove(&n_spi->di_driver[i]->gpio_c);
-                               platform_set_drvdata(n_spi->di_driver[i]->plat_dev, 0);
-                               platform_device_unregister(n_spi->di_driver[i]->plat_dev);
-                               kfree(n_spi->di_driver[i]);
-                       }
-                       kfree(n_spi->di_driver);
-               }
-               if (n_spi->do_driver) {
-                       for (i = 0; i < n_spi->features->do_count; i++) {
-                               gpiochip_remove(&n_spi->do_driver[i]->gpio_c);
-                               platform_set_drvdata(n_spi->do_driver[i]->plat_dev, 0);
-                               platform_device_unregister(n_spi->do_driver[i]->plat_dev);
-                               kfree(n_spi->do_driver[i]);
-                       }
-                       kfree(n_spi->do_driver);
-               }
-               if (n_spi->ro_driver) {
-                       for (i = 0; i < n_spi->features->ro_count; i++) {
-                               gpiochip_remove(&n_spi->ro_driver[i]->gpio_c);
-                               platform_set_drvdata(n_spi->ro_driver[i]->plat_dev, 0);
-                               platform_device_unregister(n_spi->ro_driver[i]->plat_dev);
-                               kfree(n_spi->ro_driver[i]);
-                       }
-                       kfree(n_spi->ro_driver);
-               }
-               printk(KERN_INFO "NEURONSPI: GPIO DRIVER UNREGISTERED\n");
-               if (n_spi->stm_ai_driver) {
-                       iio_device_unregister(n_spi->stm_ai_driver);
-               }
-               if (n_spi->stm_ao_driver) {
-                       iio_device_unregister(n_spi->stm_ao_driver);
-               }
-               if (n_spi->sec_ai_driver) {
-                       for (i = 0; i < n_spi->features->sec_ai_count; i++) {
-                               iio_device_unregister(n_spi->sec_ai_driver[i]);
-                       }
-                       kfree(n_spi->sec_ai_driver);
-                       n_spi->sec_ai_driver = NULL;
-               }
-               if (n_spi->sec_ao_driver) {
-                       for (i = 0; i < n_spi->features->sec_ao_count; i++) {
-                               iio_device_unregister(n_spi->sec_ao_driver[i]);
-                       }
-                       kfree(n_spi->sec_ao_driver);
-                       n_spi->sec_ao_driver = NULL;
-               }
-               printk(KERN_INFO "NEURONSPI: IIO DRIVER UNREGISTERED\n");
-               if (n_spi->send_buf) {
-                       kfree(n_spi->send_buf);
-                       n_spi->send_buf = NULL;
-               }
-               if (n_spi->recv_buf) {
-                       kfree(n_spi->recv_buf);
-                       n_spi->recv_buf = NULL;
-               }
-               if (n_spi->uart_buf) {
-                       kfree(n_spi->uart_buf);
-                       n_spi->uart_buf = NULL;
-               }
-               printk(KERN_INFO "NEURONSPI: SPI/UART DRIVER UNREGISTERED\n");
-               if (n_spi->board_device) {
-                       platform_set_drvdata(n_spi->board_device, 0);
-                       platform_device_unregister(n_spi->board_device);
-               }
-               kfree(n_spi);
-       }
-       return 0;
-}
-
-s32 char_register_driver(void)
-{
-       s32 ret = 0;
-
-       // Character device registration
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: Initialising Character Device\n");
-#endif
-       neuronspi_cdrv.major_number = register_chrdev(0, NEURON_DEVICE_NAME, &file_ops);
-       if (neuronspi_cdrv.major_number < 0){
-          printk(KERN_ALERT "NEURONSPI: failed to register a major number\n");
-          return neuronspi_cdrv.major_number;
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: registered correctly with major number %d\n", neuronspi_cdrv.major_number);
-#endif
-
-       // Character class registration
-       neuronspi_cdrv.driver_class = class_create(THIS_MODULE, NEURON_DEVICE_CLASS);
-       if (IS_ERR(neuronspi_cdrv.driver_class)) {
-               unregister_chrdev(neuronspi_cdrv.major_number, NEURON_DEVICE_NAME);
-               printk(KERN_ALERT "NEURONSPI: Failed to register device class\n");
-               return PTR_ERR(neuronspi_cdrv.driver_class);
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: device class registered correctly\n");
-#endif
-
-       // Device driver registration
-       neuronspi_cdrv.dev = device_create_with_groups(neuronspi_cdrv.driver_class, &(neuron_plc_dev->dev), MKDEV(neuronspi_cdrv.major_number, 0), NULL, neuron_plc_attr_groups, NEURON_DEVICE_NAME);
-       if (IS_ERR(neuronspi_cdrv.dev)) {
-               class_destroy(neuronspi_cdrv.driver_class);
-               unregister_chrdev(neuronspi_cdrv.major_number, NEURON_DEVICE_NAME);
-               printk(KERN_ALERT "NEURONSPI: Failed to create the device\n");
-               return PTR_ERR(neuronspi_cdrv.dev);
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: device class created correctly\n");
-#endif
-       return ret;
-}
-
-s32 char_unregister_driver(void)
-{
-       device_destroy(neuronspi_cdrv.driver_class, MKDEV(neuronspi_cdrv.major_number, 0));     // Destroy the device
-       class_unregister(neuronspi_cdrv.driver_class);                                                          // Unregister the class
-       class_destroy(neuronspi_cdrv.driver_class);                                                             // Destroy the class
-       unregister_chrdev(neuronspi_cdrv.major_number, NEURON_DEVICE_NAME);                                     // Unregister the major number
-       printk(KERN_INFO "NEURONSPI: Device unloaded successfully\n");
-       return 0;
-}
-
-/*********************
- * Final definitions *
- *********************/
-
-MODULE_ALIAS("spi:neuronspi");
-
-static s32 __init neuronspi_init(void)
-{
-       s32 ret = 0;
-       neuronspi_spi_w_spinlock = kzalloc(sizeof(struct spinlock), GFP_KERNEL);
-       spin_lock_init(neuronspi_spi_w_spinlock);
-       mutex_init(&neuronspi_master_mutex);
-       memset(&neuronspi_s_dev, 0, sizeof(neuronspi_s_dev));
-       ret = spi_register_driver(&neuronspi_spi_driver);
-       if (ret < 0) {
-               printk(KERN_ERR "NEURONSPI: Failed to init neuronspi spi --> %d\n", ret);
-               return ret;
-       } else {
-#ifdef NEURONSPI_MAJOR_VERSIONSTRING
-               printk(KERN_INFO "NEURONSPI: SPI Driver Registered, Major Version: %s\n", NEURONSPI_MAJOR_VERSIONSTRING);
-#else
-               printk(KERN_INFO "NEURONSPI: SPI Driver Registered\n");
-#endif
-       }
-       neuronspi_invalidate_thread = kthread_create(neuronspi_regmap_invalidate, NULL, "neuronspi_inv");
-       if (neuronspi_invalidate_thread != NULL) {
-               wake_up_process(neuronspi_invalidate_thread);
-       }
-       return ret;
-}
-__attribute__((unused)) module_init(neuronspi_init);
-
-static void __exit neuronspi_exit(void)
-{
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: Open Counter is %d\n", neuronspi_cdrv.open_counter);
-#endif
-       if (neuronspi_invalidate_thread) {
-               kthread_stop(neuronspi_invalidate_thread);
-       }
-       char_unregister_driver();
-       if (neuronspi_uart) {
-               neuronspi_uart_remove(neuronspi_uart_glob_data);
-               uart_unregister_driver(neuronspi_uart);
-               kfree(neuronspi_uart);
-               kfree(neuronspi_uart_glob_data);
-       }
-       spi_unregister_driver(&neuronspi_spi_driver);
-       if (neuron_plc_dev) {
-               platform_device_unregister(neuron_plc_dev);
-       }
-       kfree(neuronspi_spi_w_spinlock);
-       printk(KERN_INFO "NEURONSPI: SPI Driver Unregistered\n");
-}
-__attribute__((unused)) module_exit(neuronspi_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Tomas Knot <knot@faster.cz>");
-MODULE_DESCRIPTION("UniPi Neuron driver");
diff --git a/modules/neuron_spi/src/unipi_spi.h b/modules/neuron_spi/src/unipi_spi.h
deleted file mode 100644 (file)
index 75e795f..0000000
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2017 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_SPI_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_SPI_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-#include "unipi_common.h"
-#include "unipi_platform.h"
-#include "unipi_sysfs.h"
-#include "unipi_iio.h"
-
-/********************
- * Module Constants *
- ********************/
-
-#define NEURONSPI_SLOWER_MODELS_LEN                                    3
-static const u16 NEURONSPI_SLOWER_MODELS[NEURONSPI_SLOWER_MODELS_LEN] = {
-               0xb10, 0xc10, 0xf10
-};
-
-#define NEURONSPI_PROBE_MESSAGE_LEN                                            22
-static const u8 NEURONSPI_PROBE_MESSAGE[NEURONSPI_PROBE_MESSAGE_LEN] = {
-               0x04, 0x0e, 0xe8, 0x03, 0xa0, 0xdd,
-               0x04, 0x00, 0xe8, 0x03, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00,     0x12, 0x16
-};
-
-#define NEURONSPI_UART_PROBE_MESSAGE_LEN                               6
-static const u8 NEURONSPI_UART_PROBE_MESSAGE[NEURONSPI_UART_PROBE_MESSAGE_LEN] = {
-               0xfa, 0x00, 0x55, 0x0e, 0xb6, 0x0a
-};
-
-#define NEURONSPI_SPI_UART_SHORT_MESSAGE_LEN                   6
-static const u8 NEURONSPI_SPI_UART_SHORT_MESSAGE[NEURONSPI_SPI_UART_SHORT_MESSAGE_LEN] = {
-               0x41, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-#define NEURONSPI_SPI_UART_LONG_MESSAGE_LEN                            8
-static const u8 NEURONSPI_SPI_UART_LONG_MESSAGE[NEURONSPI_SPI_UART_LONG_MESSAGE_LEN] = {
-               0x64, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00
-};
-
-#define NEURONSPI_SPI_UART_READ_MESSAGE_LEN                            14
-static const u8 NEURONSPI_SPI_UART_READ_MESSAGE[NEURONSPI_SPI_UART_READ_MESSAGE_LEN] = {
-               0x65, 0x06, 0x00, 0x00, 0x44, 0x69,
-               0x65, 0x03, 0x00, 0x00, 0x00, 0x05,
-               0x6a, 0x0c
-};
-
-#define NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN                              14
-static const u8 NEURONSPI_SPI_IRQ_SET_MESSAGE[NEURONSPI_SPI_UART_READ_MESSAGE_LEN] = {
-               0x06, 0x06, 0xef, 0x03, 0x00, 0x00,
-               0x06, 0x01, 0xef, 0x03, 0x05, 0x00,
-               0x00, 0x00
-};
-
-#define NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN               16
-static const u8 NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE[NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN] = {
-               0x04, 0x08, 0xf4, 0x01, 0x00, 0x00,
-               0x04, 0x02, 0xf4, 0x01, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00
-};
-
-#define NEURONSPI_SPI_UART_GET_LDISC_MESSAGE_LEN               16
-static const u8 NEURONSPI_SPI_UART_GET_LDISC_MESSAGE[NEURONSPI_SPI_UART_GET_LDISC_MESSAGE_LEN] = {
-               0x04, 0x08, 0xf6, 0x01, 0x00, 0x00,
-               0x04, 0x02, 0xf6, 0x01, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00
-};
-
-#define NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN               16
-static const u8 NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE[NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN] = {
-               0x06, 0x08, 0xf4, 0x01, 0x00, 0x00,
-               0x06, 0x02, 0xf4, 0x01, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00
-};
-
-#define NEURONSPI_SPI_LED_SET_MESSAGE_LEN                              6
-static const u8 NEURONSPI_SPI_LED_SET_MESSAGE[NEURONSPI_SPI_LED_SET_MESSAGE_LEN] = {
-               0x05, 0x00, 0x08, 0x00, 0x00, 0x00
-};
-
-#define NEURONSPI_CRC16TABLE_LEN                                               256
-static const u16 NEURONSPI_CRC16TABLE[NEURONSPI_CRC16TABLE_LEN] = {
-    0,  1408,  3968,  2560,  7040,  7680,  5120,  4480, 13184, 13824, 15360,
-14720, 10240, 11648, 10112,  8704, 25472, 26112, 27648, 27008, 30720, 32128,
-30592, 29184, 20480, 21888, 24448, 23040, 19328, 19968, 17408, 16768, 50048,
-50688, 52224, 51584, 55296, 56704, 55168, 53760, 61440, 62848, 65408, 64000,
-60288, 60928, 58368, 57728, 40960, 42368, 44928, 43520, 48000, 48640, 46080,
-45440, 37760, 38400, 39936, 39296, 34816, 36224, 34688, 33280, 33665, 34305,
-35841, 35201, 38913, 40321, 38785, 37377, 45057, 46465, 49025, 47617, 43905,
-44545, 41985, 41345, 57345, 58753, 61313, 59905, 64385, 65025, 62465, 61825,
-54145, 54785, 56321, 55681, 51201, 52609, 51073, 49665, 16385, 17793, 20353,
-18945, 23425, 24065, 21505, 20865, 29569, 30209, 31745, 31105, 26625, 28033,
-26497, 25089,  9089,  9729, 11265, 10625, 14337, 15745, 14209, 12801,  4097,
- 5505,  8065,  6657,  2945,  3585,  1025,   385,   899,  1539,  3075,  2435,
- 6147,  7555,  6019,  4611, 12291, 13699, 16259, 14851, 11139, 11779,  9219,
- 8579, 24579, 25987, 28547, 27139, 31619, 32259, 29699, 29059, 21379, 22019,
-23555, 22915, 18435, 19843, 18307, 16899, 49155, 50563, 53123, 51715, 56195,
-56835, 54275, 53635, 62339, 62979, 64515, 63875, 59395, 60803, 59267, 57859,
-41859, 42499, 44035, 43395, 47107, 48515, 46979, 45571, 36867, 38275, 40835,
-39427, 35715, 36355, 33795, 33155, 32770, 34178, 36738, 35330, 39810, 40450,
-37890, 37250, 45954, 46594, 48130, 47490, 43010, 44418, 42882, 41474, 58242,
-58882, 60418, 59778, 63490, 64898, 63362, 61954, 53250, 54658, 57218, 55810,
-52098, 52738, 50178, 49538, 17282, 17922, 19458, 18818, 22530, 23938, 22402,
-20994, 28674, 30082, 32642, 31234, 27522, 28162, 25602, 24962,  8194,  9602,
-12162, 10754, 15234, 15874, 13314, 12674,  4994,  5634,  7170,  6530,  2050,
- 3458,  1922,   514
-};
-
-static const struct of_device_id neuronspi_id_match[] = {
-               {.compatible = "unipi,neuron"},
-               {.compatible = NEURON_DEVICE_NAME},
-               {}
-};
-
-/***************
- * Definitions *
- ***************/
-
-#define NEURON_INT_RX_NOT_EMPTY                        0x1
-#define NEURON_INT_TX_FINISHED                         0x2
-#define NEURON_INT_RX_MODBUS                           0x4
-#define NEURON_INT_DI_CHANGED                          0x8
-#define NEURON_INT_ID_MASK                             0x0f
-#define NEURON_INT_NO_INT_BIT                          0x0f
-
-#define NEURONSPI_RECONF_MD                                    (1 << 0)
-#define NEURONSPI_RECONF_IER                           (1 << 1)
-#define NEURONSPI_RECONF_RS485                         (1 << 2)
-
-#define MODBUS_FIRST_DATA_BYTE                         10
-
-#define MODBUS_MAX_READ_BITS                2000
-#define MODBUS_MAX_WRITE_BITS               1968
-#define MODBUS_MAX_READ_REGISTERS           125
-#define MODBUS_MAX_WRITE_REGISTERS          123
-#define MODBUS_MAX_WR_WRITE_REGISTERS       121
-#define MODBUS_MAX_WR_READ_REGISTERS        125
-
-/*************************
- * Function Declarations *
- *************************/
-
-int neuronspi_open (struct inode *, struct file *);
-int neuronspi_release (struct inode *, struct file *);
-ssize_t neuronspi_read (struct file *, char *, size_t, loff_t *);
-ssize_t neuronspi_write (struct file *, const char *, size_t, loff_t *);
-s32 char_register_driver(void);
-s32 char_unregister_driver(void);
-irqreturn_t neuronspi_spi_irq(s32 irq, void *dev_id);
-s32 neuronspi_spi_probe(struct spi_device *spi);
-s32 neuronspi_spi_remove(struct spi_device *spi);
-void neuronspi_spi_send_message(struct spi_device *spi_dev, u8 *send_buf, u8 *recv_buf, s32 len, s32 freq, s32 delay, s32 send_header);
-s32 neuronspi_spi_uart_write(struct spi_device *spi, u8 *send_buf, u8 length, u8 uart_index);
-void neuronspi_spi_uart_read(struct spi_device* spi_dev, u8 *send_buf, u8 *recv_buf, s32 len, u8 uart_index);
-void neuronspi_spi_set_irqs(struct spi_device* spi_dev, u16 to);
-void neuronspi_spi_led_set_brightness(struct spi_device* spi_dev, enum led_brightness brightness, int id);
-void neuronspi_spi_iio_stm_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_stm_ai_read_current(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_stm_ao_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_stm_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-void neuronspi_spi_iio_stm_ao_set_current(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-void neuronspi_spi_iio_sec_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_sec_ai_read_current(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_sec_ai_read_resistance(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
-void neuronspi_spi_iio_sec_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
-int neuronspi_spi_gpio_do_set(struct spi_device* spi_dev, u32 id, int value);
-int neuronspi_spi_gpio_ro_set(struct spi_device* spi_dev, u32 id, int value);
-int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id);
-int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id);
-
-/***********************
- * Function structures *
- ***********************/
-
-// Host driver struct
-extern struct spi_driver neuronspi_spi_driver;
-extern struct file_operations file_ops;
-
-static const struct regmap_bus neuronspi_regmap_bus =
-{
-       .fast_io                                        = 1,
-       .write                                          = neuronspi_regmap_hw_write,
-       .gather_write                           = neuronspi_regmap_hw_gather_write,
-       .reg_write                                      = neuronspi_regmap_hw_reg_write,
-       .read                                           = neuronspi_regmap_hw_read,
-       .reg_read                                       = neuronspi_regmap_hw_reg_read,
-       .reg_format_endian_default  = REGMAP_ENDIAN_NATIVE,
-       .val_format_endian_default  = REGMAP_ENDIAN_NATIVE,
-       .max_raw_read                           = 200,                                                          // CRC and other overhead not included
-       .max_raw_write                          = 200,                                                          // CRC and other overhead not included
-};
-
-static const struct regmap_config neuronspi_regmap_config_default =
-{
-               .name                                   = "Neuronspi Regmap",
-               .reg_bits                               = 16,
-               .reg_stride                             = 0,
-               .pad_bits                               = 0,
-               .val_bits                               = 16,
-               .max_register                   = 65535,
-               .cache_type                             = REGCACHE_RBTREE,
-               .use_single_rw                  = 0,
-               .can_multi_write                = 1,
-};
-
-static const struct iio_chan_spec neuronspi_stm_ai_chan_spec[] = {
-       {
-                       .type = IIO_VOLTAGE,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 0
-       },
-       {
-                       .type = IIO_CURRENT,
-                       .indexed = 1,
-                       .channel = 1,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 0
-       }
-};
-
-static const struct iio_chan_spec neuronspi_stm_ao_chan_spec[] = {
-       {
-                       .type = IIO_VOLTAGE,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 1
-       },
-       {
-                       .type = IIO_CURRENT,
-                       .indexed = 1,
-                       .channel = 1,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 1
-       },
-       {
-                       .type = IIO_RESISTANCE,
-                       .indexed = 1,
-                       .channel = 2,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 0
-       }
-};
-
-static const struct iio_chan_spec neuronspi_sec_ai_chan_spec[] = {
-       {
-                       .type = IIO_VOLTAGE,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 0
-       },
-       {
-                       .type = IIO_CURRENT,
-                       .indexed = 1,
-                       .channel = 1,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 0
-       },
-       {
-                       .type = IIO_RESISTANCE,
-                       .indexed = 1,
-                       .channel = 2,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 0
-       }
-};
-
-static const struct iio_chan_spec neuronspi_sec_ao_chan_spec[] = {
-       {
-                       .type = IIO_VOLTAGE,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .output = 1
-       }
-};
-
-static const struct iio_info neuronspi_stm_ai_info = {
-       .read_raw = neuronspi_iio_stm_ai_read_raw,
-       .driver_module = THIS_MODULE,
-       .attrs = &neuron_stm_ai_group,
-};
-
-static const struct iio_info neuronspi_stm_ao_info = {
-       .read_raw = neuronspi_iio_stm_ao_read_raw,
-       .write_raw = neuronspi_iio_stm_ao_write_raw,
-       .driver_module = THIS_MODULE,
-       .attrs = &neuron_stm_ao_group,
-};
-
-static const struct iio_info neuronspi_sec_ai_info = {
-       .read_raw = neuronspi_iio_sec_ai_read_raw,
-       .driver_module = THIS_MODULE,
-       .attrs = &neuron_sec_ai_group,
-};
-
-static const struct iio_info neuronspi_sec_ao_info = {
-       .write_raw = neuronspi_iio_sec_ao_write_raw,
-       .driver_module = THIS_MODULE,
-       .attrs = &neuron_sec_ao_group,
-};
-
-// These defines need to be at the end
-#define to_neuronspi_uart_data(p,e)  ((container_of((p), struct neuronspi_uart_data, e)))
-#define to_neuronspi_port(p,e) ((container_of((p), struct neuronspi_port, e)))
-#define to_led_driver(p,e)     ((container_of((p), struct neuronspi_led_driver, e)))
-#define to_uart_port(p,e)      ((container_of((p), struct uart_port, e)))
-
-
-/*********************
- * In-line Functions *
- *********************/
-
-static __always_inline u16 neuronspi_spi_crc(u8* inputstring, s32 length, u16 initval)
-{
-    s32 i;
-    u16 result = initval;
-    for (i=0; i<length; i++) {
-        result = (result >> 8) ^ NEURONSPI_CRC16TABLE[(result ^ inputstring[i]) & 0xff];
-    }
-    return result;
-}
-
-static __always_inline size_t neuronspi_spi_compose_single_coil_write(u16 start, u8 **buf_inp, u8 **buf_outp, u8 data)
-{
-       u16 crc1;
-       *buf_outp = kzalloc(6, GFP_KERNEL);
-       *buf_inp = kzalloc(6, GFP_KERNEL);
-       (*buf_inp)[0] = 0x05;
-       (*buf_inp)[1] = data;
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       return 6;
-}
-
-static __always_inline size_t neuronspi_spi_compose_single_coil_read(u16 start, u8 **buf_inp, u8 **buf_outp)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(14, GFP_KERNEL);
-       *buf_inp = kzalloc(14, GFP_KERNEL);
-       (*buf_inp)[0] = 0x01;
-       (*buf_inp)[1] = 0x06;
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 6, crc1);
-       memcpy(&(*buf_inp)[12], &crc2, 2);
-       return 14;
-}
-
-static __always_inline size_t neuronspi_spi_compose_multiple_coil_write(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp, u8 *data)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
-       *buf_inp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
-       (*buf_inp)[0] = 0x0F;
-       (*buf_inp)[1] = 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       (*buf_inp)[7] = number;
-       memcpy(&(*buf_inp)[10], data, NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number));
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), crc1);
-       memcpy(&(*buf_inp)[10 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number)], &crc2, 2);
-       return 12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
-}
-
-static __always_inline size_t neuronspi_spi_compose_multiple_coil_read(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
-       *buf_inp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
-       (*buf_inp)[0] = 0x01;
-       (*buf_inp)[1] = 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), crc1);
-       memcpy(&(*buf_inp)[10 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number)], &crc2, 2);
-       return 12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
-}
-
-static __always_inline size_t neuronspi_spi_compose_single_register_write(u16 start, u8 **buf_inp, u8 **buf_outp, u16 data)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(14, GFP_KERNEL);
-       *buf_inp = kzalloc(14, GFP_KERNEL);
-       (*buf_inp)[0] = 0x06;
-       (*buf_inp)[1] = 0x06;
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       printk(KERN_INFO "NEURONSPI: COMPOSE SINGLE WRITE DATA: %x\n", data);
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       (*buf_inp)[7] = 0x01;
-       memcpy(&(*buf_inp)[10], &data, 2);
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 6, crc1);
-       memcpy(&(*buf_inp)[12], &crc2, 2);
-       return 14;
-}
-
-static __always_inline size_t neuronspi_spi_compose_single_register_read(u16 start, u8 **buf_inp, u8 **buf_outp)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(14, GFP_KERNEL);
-       *buf_inp = kzalloc(14, GFP_KERNEL);
-       (*buf_inp)[0] = 0x03;
-       (*buf_inp)[1] = 0x06;
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       (*buf_inp)[7] = 0x01;
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 6, crc1);
-       memcpy(&(*buf_inp)[12], &crc2, 2);
-       return 14;
-}
-
-static __always_inline size_t neuronspi_spi_compose_multiple_register_write(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp, u8 *data)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(12 + (number * 2), GFP_KERNEL);
-       *buf_inp = kzalloc(12 + (number * 2), GFP_KERNEL);
-       (*buf_inp)[0] = 0x10;
-       (*buf_inp)[1] = 4 + (number * 2);
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       (*buf_inp)[7] = number;
-       memcpy(&(*buf_inp)[10], data, number * 2);
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + (number * 2), crc1);
-       memcpy(&(*buf_inp)[10 + (number * 2)], &crc2, 2);
-       return 12 + (number * 2);
-}
-
-static __always_inline size_t neuronspi_spi_compose_multiple_register_read(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp)
-{
-       u16 crc1, crc2;
-       *buf_outp = kzalloc(12 + (number * 2), GFP_KERNEL);
-       *buf_inp = kzalloc(12 + (number * 2), GFP_KERNEL);
-       (*buf_inp)[0] = 0x03;
-       (*buf_inp)[1] = 4 + (number * 2);
-       (*buf_inp)[2] = start & 0xFF;
-       (*buf_inp)[3] = start >> 8;
-       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
-       memcpy(&(*buf_inp)[4], &crc1, 2);
-       memcpy(&(*buf_inp)[6], *buf_inp, 4);
-       (*buf_inp)[7] = number;
-       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + (number * 2), crc1);
-       memcpy(&(*buf_inp)[10 + (number * 2)], &crc2, 2);
-       return 12 + (number * 2);
-}
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_SPI_H_ */
diff --git a/modules/neuron_spi/src/unipi_sysfs.c b/modules/neuron_spi/src/unipi_sysfs.c
deleted file mode 100644 (file)
index e82f957..0000000
+++ /dev/null
@@ -1,1098 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-/************
- * Includes *
- ************/
-
-#include "unipi_sysfs.h"
-
-/************************
- * Static Functions *
- ************************/
-
-static ssize_t neuronspi_show_model(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       if (neuronspi_model_id != -1) {
-               ret = scnprintf(buf, 255, "%s\n", NEURONSPI_MODELTABLE[neuronspi_model_id].model_name);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_show_eeprom(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       if (neuronspi_model_id != -1) {
-               ret = scnprintf(buf, 255, "%s\n", NEURONSPI_MODELTABLE[neuronspi_model_id].eeprom_name);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_serial(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val[2] = {0, 0};
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_serial_num, val);
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_serial_num + 1, &(val[1]));
-               ret = scnprintf(buf, 255, "%d\n", val[0]);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_hw_version(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_hw_ver, &val);
-               ret = scnprintf(buf, 255, "%x.%x\n", (val & 0xF0) >> 4, val & 0xF);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_hw_flash_version(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_hw_flash_ver, &val);
-               ret = scnprintf(buf, 255, "%x.%x\n", (val & 0xF0) >> 4, val & 0xF);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_fw_version(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_sw_ver, &val);
-               ret = scnprintf(buf, 255, "%x.%x%x\n", (val & 0xF00) >> 8, (val & 0xF0) >> 4, val & 0xF);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_uart_queue_length(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->regstart_table->uart_queue_reg) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->uart_queue_reg, &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_uart_config(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->regstart_table->uart_conf_reg) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->uart_conf_reg, &val);
-               ret = scnprintf(buf, 255, "%x\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_store_uart_config(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->regstart_table->uart_conf_reg) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->uart_conf_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_show_watchdog_status(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->wd_val_reg, &val);
-               ret = scnprintf(buf, 255, "%x\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_store_watchdog_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->wd_val_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_show_watchdog_timeout(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->wd_timeout_reg, &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_store_watchdog_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->wd_timeout_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_show_pwm_presc(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_pwm_ps_reg, &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_store_pwm_presc(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_pwm_ps_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_show_pwm_freq(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_pwm_c_reg, &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_store_pwm_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_pwm_c_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_show_pwm_cycle(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_pwm_reg + n_do->do_index, &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_store_pwm_cycle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_pwm_reg + n_do->do_index, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_di_show_counter(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_counter_reg + (2 * n_di->di_index), &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_di_store_counter(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_counter_reg + (2 * n_di->di_index), val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_di_show_debounce(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->features && n_spi->features->di_count > n_di->di_index) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_deboun_reg + n_di->di_index, &val);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_di_store_debounce(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->features && n_spi->features->di_count > n_di->di_index) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_deboun_reg + n_di->di_index, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_di_show_value(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->di_count > n_di->di_index) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_val_reg + (n_di->di_index / 16), &val);
-               val &= 0x1 << (n_di->di_index % 15);
-               val = val >> (n_di->di_index % 15);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_do_show_value(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       int val;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->do_count > n_do->do_index) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_val_reg + (n_do->do_index / 16), &val);
-               val &= 0x1 << (n_do->do_index % 15);
-               val = val >> (n_do->do_index % 15);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_do_store_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       int inp = 0;
-       unsigned int val;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       err = kstrtoint(buf, 0, &inp);
-       if (err < 0) goto err_end;
-       if (inp > 1 || inp < 0) {
-               goto err_end;
-       }
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->do_count > n_do->do_index) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_val_reg + (n_do->do_index / 16), &val);
-               val &= ~(0x1 << (n_do->do_index % 15));
-               val |= inp << (n_do->do_index % 15);
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_val_reg + (n_do->do_index / 16), val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_ro_show_value(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       int val;
-       struct neuronspi_ro_driver *n_ro;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_ro = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_ro->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ro_count > n_ro->ro_index) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->ro_val_reg + (n_ro->ro_index / 16), &val);
-               val &= 0x1 << (n_ro->ro_index % 15);
-               val = val >> (n_ro->ro_index % 15);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_ro_store_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       int inp = 0;
-       unsigned int val;
-       struct neuronspi_ro_driver *n_ro;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_ro = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_ro->spi);
-       err = kstrtoint(buf, 0, &inp);
-       if (err < 0) goto err_end;
-       if (inp > 1 || inp < 0) {
-               goto err_end;
-       }
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ro_count > n_ro->ro_index) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->ro_val_reg + (n_ro->ro_index / 16), &val);
-               val &= ~(0x1 << (n_ro->ro_index % 15));
-               val |= inp << (n_ro->ro_index % 15);
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->ro_val_reg + (n_ro->ro_index / 16), val);
-       }
-err_end:
-       return count;
-}
-
-
-static ssize_t neuronspi_spi_gpio_show_ds_enable(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_direct_reg + (n_di->di_index / 16), &val);
-               val &= 0x1 << (n_di->di_index % 15);
-               val = val >> (n_di->di_index % 15);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_ds_toggle(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_toggle_reg + (n_di->di_index / 16), &val);
-               val &= 0x1 << (n_di->di_index % 15);
-               val = val >> (n_di->di_index % 15);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_ds_polarity(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_polar_reg + (n_di->di_index / 16), &val);
-               val &= 0x1 << (n_di->di_index % 15);
-               val = val >> (n_di->di_index % 15);
-               ret = scnprintf(buf, 255, "%d\n", val);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_store_ds_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       int inp = 0;
-       unsigned int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       err = kstrtoint(buf, 0, &inp);
-       if (err < 0) goto err_end;
-       if (inp > 1 || inp < 0) {
-               goto err_end;
-       }
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_direct_reg + (n_di->di_index / 16), &val);
-               val &= ~(0x1 << (n_di->di_index % 15));
-               val |= inp << (n_di->di_index % 15);
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_direct_reg + (n_di->di_index / 16), val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_store_ds_toggle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       int inp = 0;
-       unsigned int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       err = kstrtoint(buf, 0, &inp);
-       if (err < 0) goto err_end;
-       if (inp > 1 || inp < 0) {
-               goto err_end;
-       }
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_toggle_reg + (n_di->di_index / 16), &val);
-               val &= ~(0x1 << (n_di->di_index % 15));
-               val |= inp << (n_di->di_index % 15);
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_toggle_reg + (n_di->di_index / 16), val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_gpio_store_ds_polarity(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       int inp = 0;
-       unsigned int val;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       err = kstrtoint(buf, 0, &inp);
-       if (err < 0) goto err_end;
-       if (inp > 1 || inp < 0) {
-               goto err_end;
-       }
-       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
-               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_polar_reg + (n_di->di_index / 16), &val);
-               val &= ~(0x1 << (n_di->di_index % 15));
-               val |= inp << (n_di->di_index % 15);
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_polar_reg + (n_di->di_index / 16), val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_show_regmap(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       u32 val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi && n_spi->reg_map) {
-               spin_lock(&n_spi->sysfs_regmap_lock);
-               regmap_read(n_spi->reg_map, n_spi->sysfs_regmap_target, &val);
-               ret = scnprintf(buf, 255, "%x\n", val);
-               spin_unlock(&n_spi->sysfs_regmap_lock);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_store_regmap(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->reg_map && val < 65536) {
-               spin_lock(&n_spi->sysfs_regmap_lock);
-               n_spi->sysfs_regmap_target = val;
-               spin_unlock(&n_spi->sysfs_regmap_lock);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_spi_show_board(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi->combination_id != -1 && n_spi->combination_id < NEURONSPI_BOARDTABLE_LEN) {
-               ret = scnprintf(buf, 255, "%s\n", NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_lboard_id(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi->combination_id != -1 && n_spi->combination_id < NEURONSPI_BOARDTABLE_LEN) {
-               ret = scnprintf(buf, 255, "%d\n", NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->lower_board_id);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_show_uboard_id(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_spi = platform_get_drvdata(plat);
-       if (n_spi->combination_id != -1 && n_spi->combination_id < NEURONSPI_BOARDTABLE_LEN) {
-               ret = scnprintf(buf, 255, "%d\n", NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->upper_board_id);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_do_prefix(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi->features && n_spi->features->do_count > 0 && n_spi->do_driver) {
-               ret = scnprintf(buf, 255, "%s_%d\n", n_spi->do_driver[n_do->do_index]->gpio_c.label, n_spi->neuron_index + 1);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_di_prefix(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi->features && n_spi->features->di_count > 0 && n_spi->di_driver) {
-               ret = scnprintf(buf, 255, "%s_%d\n", n_spi->di_driver[n_di->di_index]->gpio_c.label, n_spi->neuron_index + 1);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_ro_prefix(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_ro_driver *n_ro;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_ro = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_ro->spi);
-       if (n_spi->features && n_spi->features->ro_count > 0 && n_spi->ro_driver) {
-               ret = scnprintf(buf, 255, "%s_%d\n", n_spi->ro_driver[n_ro->ro_index]->gpio_c.label, n_spi->neuron_index + 1);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_do_base(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi->features && n_spi->features->do_count > 0 && n_spi->do_driver) {
-               ret = scnprintf(buf, 255, "%d\n", n_spi->do_driver[n_do->do_index]->gpio_c.base);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_di_base(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi->features && n_spi->features->di_count > 0 && n_spi->di_driver) {
-               ret = scnprintf(buf, 255, "%d\n", n_spi->di_driver[n_di->di_index]->gpio_c.base);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_ro_base(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_ro_driver *n_ro;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_ro = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_ro->spi);
-       if (n_spi->features && n_spi->features->ro_count > 0 && n_spi->ro_driver) {
-               ret = scnprintf(buf, 255, "%d\n", n_spi->ro_driver[n_ro->ro_index]->gpio_c.base);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_do_count(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_do_driver *n_do;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_do = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_do->spi);
-       if (n_spi->features && n_spi->features->do_count > 0 && n_spi->do_driver) {
-               ret = scnprintf(buf, 255, "%d\n", n_spi->do_driver[n_do->do_index]->gpio_c.ngpio);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_di_count(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_di_driver *n_di;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_di = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_di->spi);
-       if (n_spi->features && n_spi->features->di_count > 0 && n_spi->di_driver) {
-               ret = scnprintf(buf, 255, "%d\n", n_spi->di_driver[n_di->di_index]->gpio_c.ngpio);
-       }
-       return ret;
-}
-
-static ssize_t neuronspi_spi_gpio_show_ro_count(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       ssize_t ret = 0;
-       struct neuronspi_ro_driver *n_ro;
-       struct neuronspi_driver_data *n_spi;
-       struct platform_device *plat = to_platform_device(dev);
-       n_ro = platform_get_drvdata(plat);
-       n_spi = spi_get_drvdata(n_ro->spi);
-       if (n_spi->features && n_spi->features->ro_count > 0 && n_spi->ro_driver) {
-               ret = scnprintf(buf, 255, "%d\n", n_spi->ro_driver[n_ro->ro_index]->gpio_c.ngpio);
-       }
-       return ret;
-}
-
-
-static ssize_t neuronspi_iio_show_primary_ai_mode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       int ret = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_mode_reg, &val);
-       ret = scnprintf(buf, 255, "%d\n", val);
-       return ret;
-}
-
-static ssize_t neuronspi_iio_store_primary_ai_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ai_mode_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_iio_show_primary_ao_mode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       int ret = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, &val);
-       ret = scnprintf(buf, 255, "%d\n", val);
-       return ret;
-}
-
-static ssize_t neuronspi_iio_store_primary_ao_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, val);
-       }
-err_end:
-       return count;
-}
-
-static ssize_t neuronspi_iio_show_secondary_ai_mode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       int ret = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_mode_reg + ai_data->index, &val);
-       ret = scnprintf(buf, 255, "%d\n", val);
-       return ret;
-}
-static ssize_t neuronspi_iio_store_secondary_ai_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
-       struct spi_device *spi = ai_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->sec_ai_mode_reg + ai_data->index, val);
-       }
-err_end:
-       return count;
-}
-static ssize_t neuronspi_iio_show_secondary_ao_mode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       int ret = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_sec_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ao_mode_reg + ao_data->index, &val);
-       ret = scnprintf(buf, 255, "%d\n", val);
-       return ret;
-}
-static ssize_t neuronspi_iio_store_secondary_ao_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       ssize_t err = 0;
-       unsigned int val = 0;
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct neuronspi_sec_ao_data *ao_data = iio_priv(indio_dev);
-       struct spi_device *spi = ao_data->parent;
-       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
-       err = kstrtouint(buf, 0, &val);
-       if (err < 0) goto err_end;
-       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
-               regmap_write(n_spi->reg_map, n_spi->regstart_table->sec_ao_mode_reg + ao_data->index, val);
-       }
-err_end:
-       return count;
-}
-
-/**********************************
- * Function Structure Definitions *
- **********************************/
-
-static DEVICE_ATTR(model_name, 0440, neuronspi_show_model, NULL);
-static DEVICE_ATTR(sys_eeprom_name, 0440, neuronspi_show_eeprom, NULL);
-static DEVICE_ATTR(register_read, 0660, neuronspi_show_regmap, neuronspi_store_regmap);
-static DEVICE_ATTR(sys_board_serial, 0440, neuronspi_spi_show_serial, NULL);
-static DEVICE_ATTR(sys_board_name, 0440, neuronspi_spi_show_board, NULL);
-static DEVICE_ATTR(sys_primary_major_id, 0440, neuronspi_spi_show_lboard_id, NULL);
-static DEVICE_ATTR(sys_secondary_major_id, 0440, neuronspi_spi_show_uboard_id, NULL);
-static DEVICE_ATTR(sys_primary_minor_id, 0440, neuronspi_spi_show_hw_version, NULL);
-static DEVICE_ATTR(sys_secondary_minor_id, 0440, neuronspi_spi_show_hw_flash_version, NULL);
-static DEVICE_ATTR(firmware_version, 0440, neuronspi_spi_show_fw_version, NULL);
-static DEVICE_ATTR(watchdog_status, 0660, neuronspi_spi_show_watchdog_status, neuronspi_spi_store_watchdog_status);
-static DEVICE_ATTR(watchdog_timeout, 0660, neuronspi_spi_show_watchdog_timeout, neuronspi_spi_store_watchdog_timeout);
-static DEVICE_ATTR(sys_gpio_do_count, 0440, neuronspi_spi_gpio_show_do_count, NULL);
-static DEVICE_ATTR(sys_gpio_do_prefix, 0440, neuronspi_spi_gpio_show_do_prefix, NULL);
-static DEVICE_ATTR(sys_gpio_do_base, 0440, neuronspi_spi_gpio_show_do_base, NULL);
-static DEVICE_ATTR(sys_gpio_di_count, 0440, neuronspi_spi_gpio_show_di_count, NULL);
-static DEVICE_ATTR(sys_gpio_di_prefix, 0440, neuronspi_spi_gpio_show_di_prefix, NULL);
-static DEVICE_ATTR(ro_value, 0660, neuronspi_spi_gpio_ro_show_value, neuronspi_spi_gpio_ro_store_value);
-static DEVICE_ATTR(do_value, 0660, neuronspi_spi_gpio_do_show_value, neuronspi_spi_gpio_do_store_value);
-static DEVICE_ATTR(counter, 0660, neuronspi_spi_gpio_di_show_counter, neuronspi_spi_gpio_di_store_counter);
-static DEVICE_ATTR(debounce, 0660, neuronspi_spi_gpio_di_show_debounce, neuronspi_spi_gpio_di_store_debounce);
-static DEVICE_ATTR(di_value, 0440, neuronspi_spi_gpio_di_show_value, NULL);
-static DEVICE_ATTR(direct_switch_enable, 0660, neuronspi_spi_gpio_show_ds_enable, neuronspi_spi_gpio_store_ds_enable);
-static DEVICE_ATTR(direct_switch_toggle, 0660, neuronspi_spi_gpio_show_ds_toggle, neuronspi_spi_gpio_store_ds_toggle);
-static DEVICE_ATTR(direct_switch_polarity, 0660, neuronspi_spi_gpio_show_ds_polarity, neuronspi_spi_gpio_store_ds_polarity);
-static DEVICE_ATTR(pwm_frequency_cycle, 0660, neuronspi_spi_gpio_show_pwm_freq, neuronspi_spi_gpio_store_pwm_freq);
-static DEVICE_ATTR(pwm_prescale, 0660, neuronspi_spi_gpio_show_pwm_presc, neuronspi_spi_gpio_store_pwm_presc);
-static DEVICE_ATTR(pwm_duty_cycle, 0660, neuronspi_spi_gpio_show_pwm_cycle, neuronspi_spi_gpio_store_pwm_cycle);
-static DEVICE_ATTR(uart_queue_length, 0440, neuronspi_spi_show_uart_queue_length, NULL);
-static DEVICE_ATTR(uart_config, 0660, neuronspi_spi_show_uart_config, neuronspi_spi_store_uart_config);
-static DEVICE_ATTR(sys_gpio_di_base, 0440, neuronspi_spi_gpio_show_di_base, NULL);
-static DEVICE_ATTR(sys_gpio_ro_count, 0440, neuronspi_spi_gpio_show_ro_count, NULL);
-static DEVICE_ATTR(sys_gpio_ro_prefix, 0440, neuronspi_spi_gpio_show_ro_prefix, NULL);
-static DEVICE_ATTR(sys_gpio_ro_base, 0440, neuronspi_spi_gpio_show_ro_base, NULL);
-static DEVICE_ATTR(mode_ai_type_a, 0660, neuronspi_iio_show_primary_ai_mode, neuronspi_iio_store_primary_ai_mode);
-static DEVICE_ATTR(mode_ao_type_a, 0660, neuronspi_iio_show_primary_ao_mode, neuronspi_iio_store_primary_ao_mode);
-static DEVICE_ATTR(mode_ai_type_b, 0660, neuronspi_iio_show_secondary_ai_mode, neuronspi_iio_store_secondary_ai_mode);
-static DEVICE_ATTR(mode_ao_type_b, 0660, neuronspi_iio_show_secondary_ao_mode, neuronspi_iio_store_secondary_ao_mode);
-
-static struct attribute *neuron_plc_attrs[] = {
-               &dev_attr_model_name.attr,
-               &dev_attr_sys_eeprom_name.attr,
-               NULL,
-};
-
-static struct attribute *neuron_board_attrs[] = {
-               &dev_attr_sys_board_name.attr,
-               &dev_attr_sys_primary_major_id.attr,
-               &dev_attr_sys_secondary_major_id.attr,
-               &dev_attr_sys_primary_minor_id.attr,
-               &dev_attr_sys_secondary_minor_id.attr,
-               &dev_attr_firmware_version.attr,
-               &dev_attr_watchdog_status.attr,
-               &dev_attr_watchdog_timeout.attr,
-               &dev_attr_sys_board_serial.attr,
-               &dev_attr_uart_queue_length.attr,
-               &dev_attr_uart_config.attr,
-               &dev_attr_register_read.attr,
-               NULL,
-};
-
-static struct attribute *neuron_gpio_di_attrs[] = {
-               &dev_attr_sys_gpio_di_count.attr,
-               &dev_attr_sys_gpio_di_prefix.attr,
-               &dev_attr_sys_gpio_di_base.attr,
-               &dev_attr_direct_switch_enable.attr,
-               &dev_attr_direct_switch_toggle.attr,
-               &dev_attr_direct_switch_polarity.attr,
-               &dev_attr_di_value.attr,
-               &dev_attr_counter.attr,
-               &dev_attr_debounce.attr,
-               NULL,
-};
-
-static struct attribute *neuron_gpio_do_attrs[] = {
-               &dev_attr_sys_gpio_do_count.attr,
-               &dev_attr_sys_gpio_do_prefix.attr,
-               &dev_attr_sys_gpio_do_base.attr,
-               &dev_attr_pwm_frequency_cycle.attr,
-               &dev_attr_pwm_prescale.attr,
-               &dev_attr_pwm_duty_cycle.attr,
-               &dev_attr_do_value.attr,
-               NULL,
-};
-
-static struct attribute *neuron_gpio_ro_attrs[] = {
-               &dev_attr_sys_gpio_ro_count.attr,
-               &dev_attr_sys_gpio_ro_prefix.attr,
-               &dev_attr_sys_gpio_ro_base.attr,
-               &dev_attr_ro_value.attr,
-               NULL,
-};
-
-static struct attribute *neuron_stm_ai_attrs[] = {
-               &dev_attr_mode_ai_type_a.attr,
-               NULL,
-};
-
-static struct attribute *neuron_stm_ao_attrs[] = {
-               &dev_attr_mode_ao_type_a.attr,
-               NULL,
-};
-
-static struct attribute *neuron_sec_ai_attrs[] = {
-               &dev_attr_mode_ai_type_b.attr,
-               NULL,
-};
-
-static struct attribute *neuron_sec_ao_attrs[] = {
-               &dev_attr_mode_ao_type_b.attr,
-               NULL,
-};
-
-static struct attribute_group neuron_plc_attr_group = {
-       .attrs = neuron_plc_attrs,
-};
-
-static struct attribute_group neuron_board_attr_group = {
-       .attrs = neuron_board_attrs,
-};
-
-static struct attribute_group neuron_gpio_di_attr_group = {
-       .attrs = neuron_gpio_di_attrs,
-};
-
-static struct attribute_group neuron_gpio_do_attr_group = {
-       .attrs = neuron_gpio_do_attrs,
-};
-
-static struct attribute_group neuron_gpio_ro_attr_group = {
-       .attrs = neuron_gpio_ro_attrs,
-};
-
-const struct attribute_group neuron_stm_ai_group = {
-       .attrs = neuron_stm_ai_attrs,
-};
-
-const struct attribute_group neuron_stm_ao_group = {
-       .attrs = neuron_stm_ao_attrs,
-};
-
-const struct attribute_group neuron_sec_ai_group = {
-       .attrs = neuron_sec_ai_attrs,
-};
-
-const struct attribute_group neuron_sec_ao_group = {
-       .attrs = neuron_sec_ao_attrs,
-};
-
-const struct attribute_group *neuron_plc_attr_groups[] = {
-       &neuron_plc_attr_group,
-       NULL,
-};
-
-const struct attribute_group *neuron_board_attr_groups[] = {
-       &neuron_board_attr_group,
-       NULL,
-};
-
-const struct attribute_group *neuron_gpio_di_attr_groups[] = {
-       &neuron_gpio_di_attr_group,
-       NULL,
-};
-
-const struct attribute_group *neuron_gpio_do_attr_groups[] = {
-       &neuron_gpio_do_attr_group,
-       NULL,
-};
-
-const struct attribute_group *neuron_gpio_ro_attr_groups[] = {
-       &neuron_gpio_ro_attr_group,
-       NULL,
-};
diff --git a/modules/neuron_spi/src/unipi_sysfs.h b/modules/neuron_spi/src/unipi_sysfs.h
deleted file mode 100644 (file)
index 72ae365..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_SYSFS_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_SYSFS_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-#include "unipi_common.h"
-#include "unipi_platform.h"
-
-extern const struct attribute_group neuron_stm_ai_group;
-extern const struct attribute_group neuron_stm_ao_group;
-extern const struct attribute_group neuron_sec_ai_group;
-extern const struct attribute_group neuron_sec_ao_group;
-
-extern const struct attribute_group *neuron_plc_attr_groups[];
-extern const struct attribute_group *neuron_board_attr_groups[];
-extern const struct attribute_group *neuron_gpio_di_attr_groups[];
-extern const struct attribute_group *neuron_gpio_do_attr_groups[];
-extern const struct attribute_group *neuron_gpio_ro_attr_groups[];
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_SYSFS_H_ */
diff --git a/modules/neuron_spi/src/unipi_uart.c b/modules/neuron_spi/src/unipi_uart.c
deleted file mode 100644 (file)
index ed549f0..0000000
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-/************
- * Includes *
- ************/
-
-#include "unipi_uart.h"
-#include "unipi_spi.h"
-
-/********************
- * Data Definitions *
- ********************/
-
-struct neuronspi_uart_data* neuronspi_uart_glob_data;
-unsigned long neuronspi_lines;
-struct uart_driver* neuronspi_uart;
-
-/************************
- * Non-static Functions *
- ************************/
-
-void neuronspi_uart_tx_proc(struct kthread_work *ws)
-{
-       struct neuronspi_port *port = to_neuronspi_port(ws, tx_work);
-
-       if ((port->port.rs485.flags & SER_RS485_ENABLED) &&
-           (port->port.rs485.delay_rts_before_send > 0)) {
-               msleep(port->port.rs485.delay_rts_before_send);
-       }
-
-       neuronspi_uart_handle_tx(port);
-}
-
-u32 neuronspi_uart_tx_empty(struct uart_port *port)
-{
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: UART TX Empty\n");
-#endif
-       return TIOCSER_TEMT;
-}
-
-u32 neuronspi_uart_get_mctrl(struct uart_port *port)
-{
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: UART MCTRL Get\n");
-#endif
-       return TIOCM_DSR | TIOCM_CAR;
-}
-
-int    neuronspi_uart_ioctl (struct uart_port *port, unsigned int ioctl_code, unsigned long ioctl_arg)
-{
-       u8 *inp_buf, *outp_buf;
-       int write_length;
-       struct neuronspi_port *n_port;
-       struct spi_device *spi;
-       struct neuronspi_driver_data *n_spi;
-       n_port = to_neuronspi_port(port, port);
-       spi = neuronspi_s_dev[n_port->dev_index];
-       n_spi = spi_get_drvdata(spi);
-       switch (ioctl_code) {
-       case TIOCSETD: {
-               printk(KERN_INFO "NEURONSPI: IOCTL TIOCSETD (processed via set_termios)\n");
-               return 1;
-       }
-       case 0x5480: {
-               printk(KERN_INFO "NEURONSPI: IOCTL 0x5480\n");
-               write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_TIMEOUT_REGISTER, &inp_buf, &outp_buf, (ioctl_arg * 1000000) / n_port->baud);
-               neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
-               return 1;
-       }
-       case 0x5481: {
-               printk(KERN_INFO "NEURONSPI: IOCTL 0x5481\n");
-               write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_TIMEOUT_REGISTER, &inp_buf, &outp_buf, ioctl_arg);
-               neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
-               return 1;
-       }
-       default: {
-               return 0;
-       }
-       }
-}
-
-void neuronspi_uart_set_parmrk(struct uart_port *port, int to)
-{
-       u8 *inp_buf, *outp_buf;
-       int write_length;
-       struct neuronspi_port *n_port;
-       struct spi_device *spi;
-       struct neuronspi_driver_data *n_spi;
-       n_port = to_neuronspi_port(port, port);
-       spi = neuronspi_s_dev[n_port->dev_index];
-       n_spi = spi_get_drvdata(spi);
-       printk(KERN_INFO "NEURONSPI: SET PARMRK to %d\n", to);
-       write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_IFLAGS_REGISTER, &inp_buf, &outp_buf, to);
-       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
-}
-
-void neuronspi_uart_set_ldisc(struct uart_port *port, struct ktermios *kterm)
-{
-       u8 *inp_buf, *outp_buf;
-       int write_length;
-       struct neuronspi_port *n_port;
-       struct spi_device *spi;
-       struct neuronspi_driver_data *n_spi;
-       n_port = to_neuronspi_port(port, port);
-       spi = neuronspi_s_dev[n_port->dev_index];
-       n_spi = spi_get_drvdata(spi);
-       printk(KERN_INFO "NEURONSPI: PROFIBUS discipline set\n");
-       write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_LDISC_REGISTER, &inp_buf, &outp_buf, kterm->c_line);
-       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
-}
-
-void neuronspi_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
-{
-       struct neuronspi_port *n_port;
-       n_port = to_neuronspi_port(port, port);
-       if (old && old->c_iflag && old->c_iflag != termios->c_iflag) {
-               printk(KERN_INFO "NEURONSPI: c_iflag termios:%d\n", termios->c_iflag);
-       }
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: TERMIOS Set, p:%d, c_cflag:%x\n", port->line, termios->c_cflag);
-#endif
-       neuronspi_spi_uart_set_cflag(neuronspi_s_dev[n_port->dev_index], n_port->dev_port, termios->c_cflag);
-       if (old && termios && (old->c_iflag & PARMRK) != (termios->c_iflag & PARMRK)) {
-               if (termios->c_iflag & PARMRK) {
-                       neuronspi_uart_set_parmrk(port, 1);
-               } else {
-                       neuronspi_uart_set_parmrk(port, 0);
-               }
-       }
-       if (old && termios && old->c_line != termios->c_line) {
-               if (termios->c_line == N_PROFIBUS_FDL) {
-                       printk(KERN_INFO "NEURONSPI: Line Discipline change/n");
-                       neuronspi_uart_set_ldisc(port, termios);
-               }
-       }
-       n_port->baud = uart_get_baud_rate(port, termios, old, 2400, 115200);
-       uart_update_timeout(port, termios->c_cflag, n_port->baud);
-}
-
-s32 neuronspi_uart_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
-{
-       port->rs485 = *rs485;
-       return 0;
-}
-
-const char* neuronspi_uart_type(struct uart_port *port)
-{
-       return port->type == PORT_NEURONSPI ? "NEURONSPI_NAME" : NULL;
-}
-
-s32 neuronspi_uart_request_port(struct uart_port *port)
-{
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: Requested port %d\n", port->line);
-#endif
-       return 0;
-}
-
-void neuronspi_uart_fifo_read(struct uart_port *port, u32 rxlen)
-{
-       struct neuronspi_port *s = to_neuronspi_port(port,port);
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(neuronspi_s_dev[s->dev_index]);
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: FIFO Read len:%d\n", rxlen);
-#endif
-    memcpy(s->buf, d_data->uart_buf, rxlen);
-}
-
-void neuronspi_uart_fifo_write(struct neuronspi_port *port, u8 to_send)
-{
-       s32 i;
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: FIFO Write to_send:%d\n", to_send);
-#endif
-       for (i = 0; i < to_send; i++) {
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_INFO "NEURONSPI: UART Char Send: %x\n", port->buf[i]);
-#endif
-       }
-    neuronspi_spi_uart_write(neuronspi_s_dev[port->dev_index], port->buf, to_send, port->dev_port);
-}
-
-s32 neuronspi_uart_alloc_line(void)
-{
-       s32 i;
-       BUILD_BUG_ON(NEURONSPI_MAX_DEVS > BITS_PER_LONG);
-
-       for (i = 0; i < NEURONSPI_MAX_DEVS; i++)
-               if (!test_and_set_bit(i, &neuronspi_lines))
-                       break;
-
-       return i;
-}
-
-void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir)
-{
-       u32 ch, flag, bytes_read, i;
-       while (rxlen) {
-
-               neuronspi_uart_fifo_read(&port->port, rxlen);
-               bytes_read = rxlen;
-
-               port->port.icount.rx++;
-               flag = TTY_NORMAL;
-
-               for (i = 0; i < bytes_read; ++i) {
-#if NEURONSPI_DETAILED_DEBUG > 0
-                       printk(KERN_INFO "NEURONSPI: UART Insert Char:%x\n", port->buf[i]);
-#endif
-                       ch = port->buf[i];
-                       if (uart_handle_sysrq_char(port, ch))
-                               continue;
-
-                       uart_insert_char(&port->port, 0, 0, ch, flag);
-               }
-               rxlen -= bytes_read;
-       }
-
-       tty_flip_buffer_push(&port->port.state->port);
-}
-
-void neuronspi_uart_handle_tx(struct neuronspi_port *port)
-{
-       u32 txlen, to_send, i;
-       struct spi_device *spi;
-       struct neuronspi_driver_data *d_data;
-       struct circ_buf *xmit;
-
-       spi = neuronspi_s_dev[port->dev_index];
-       d_data = spi_get_drvdata(spi);
-       xmit = &port->port.state->xmit;
-
-       if (unlikely(port->port.x_char)) {
-               neuronspi_spi_uart_write(spi, &port->port.x_char, 1, port->dev_port);
-               port->port.icount.tx++;
-               port->port.x_char = 0;
-               return;
-       }
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->port)) {
-               return;
-       }
-
-       /* Get length of data pending in circular buffer */
-       to_send = uart_circ_chars_pending(xmit);
-       if (likely(to_send)) {
-               /* Limit to size of TX FIFO */
-               txlen = NEURONSPI_FIFO_SIZE;
-               to_send = (to_send > txlen) ? txlen : to_send;
-
-               /* Add data to send */
-               port->port.icount.tx += to_send;
-
-               /* Convert to linear buffer */
-               for (i = 0; i < to_send; ++i) {
-                       port->buf[i] = xmit->buf[xmit->tail];
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               }
-
-               neuronspi_uart_fifo_write(port, to_send);
-       }
-
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
-               uart_write_wakeup(&port->port);
-       }
-}
-
-void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno)
-{
-       struct neuronspi_port *n_port = &uart_data->p[portno];
-       struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
-       u8 *send_buf = kzalloc(NEURONSPI_UART_PROBE_MESSAGE_LEN, GFP_KERNEL);
-       u8 *recv_buf = kzalloc(NEURONSPI_UART_PROBE_MESSAGE_LEN, GFP_KERNEL);
-       memcpy(send_buf, NEURONSPI_UART_PROBE_MESSAGE, NEURONSPI_UART_PROBE_MESSAGE_LEN);
-       neuronspi_spi_send_message(spi, send_buf, recv_buf, NEURONSPI_UART_PROBE_MESSAGE_LEN, NEURONSPI_DEFAULT_FREQ, 25, 1);
-       kfree(send_buf);
-       kfree(recv_buf);
-}
-
-void neuronspi_uart_ist(struct kthread_work *ws)
-{
-       struct neuronspi_port *p = to_neuronspi_port(ws, irq_work);
-       neuronspi_uart_handle_irq(p->parent, p->line);
-}
-
-void neuronspi_uart_config_port(struct uart_port *port, int flags)
-{
-       if (flags & UART_CONFIG_TYPE) {
-               port->type = PORT_NEURONSPI;
-       }
-}
-
-s32 neuronspi_uart_verify_port(struct uart_port *port,
-                                struct serial_struct *s)
-{
-       if ((s->type != PORT_UNKNOWN) && (s->type != PORT_NEURONSPI))
-               return -EINVAL;
-       if (s->irq != port->irq)
-               return -EINVAL;
-
-       return 0;
-}
-
-void neuronspi_uart_pm(struct uart_port *port, u32 state, u32 oldstate)
-{
-       neuronspi_uart_power(port, (state == UART_PM_STATE_ON) ? 1 : 0);
-}
-
-s32 neuronspi_uart_probe(struct spi_device* dev, u8 device_index)
-{
-       struct neuronspi_driver_data* driver_data = spi_get_drvdata(dev);
-       struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
-       s32 i, j, ret, new_uart_count;
-       struct neuronspi_uart_data *uart_data = driver_data->uart_data;
-
-       if (uart_data->p == NULL) {
-               uart_data->p = kzalloc(sizeof(struct neuronspi_port[NEURONSPI_MAX_UART]), GFP_KERNEL);
-               for (i = 0; i < NEURONSPI_MAX_UART; i++) {
-                       uart_data->p[i].parent = uart_data;
-               }
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_DEBUG "NEURONSPI: Allocated port structure for %d potential UART devices\n", NEURONSPI_MAX_UART);
-#endif
-       }
-
-       new_uart_count = driver_data->uart_count + uart_data->p_count;
-
-       // Initialise port data
-       for (i = uart_data->p_count; i < new_uart_count; i++) {
-               uart_data->p[i].dev_index = device_index;
-               uart_data->p[i].dev_port = i - uart_data->p_count;
-               uart_data->p[i].line            = i;
-               uart_data->p[i].port.dev        = &(dev->dev);
-               uart_data->p[i].port.irq        = dev->irq;
-               uart_data->p[i].port.type       = PORT_NEURONSPI;
-               uart_data->p[i].port.fifosize   = NEURONSPI_FIFO_SIZE;
-               uart_data->p[i].port.flags      = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
-               uart_data->p[i].port.iotype     = UPIO_PORT;
-               uart_data->p[i].port.uartclk    = 9600;
-               uart_data->p[i].port.rs485_config = neuronspi_uart_config_rs485;
-               uart_data->p[i].port.ops        = &neuronspi_uart_ops;
-               uart_data->p[i].port.line       = neuronspi_uart_alloc_line();
-               spin_lock_init(&uart_data->p[i].port.lock);
-               if (uart_data->p[i].port.line >= NEURONSPI_MAX_DEVS) {
-                       ret = -ENOMEM;
-               }
-               kthread_init_work(&(uart_data->p[i].tx_work), neuronspi_uart_tx_proc);
-               kthread_init_work(&(uart_data->p[i].rx_work), neuronspi_uart_rx_proc);
-               kthread_init_work(&(uart_data->p[i].irq_work), neuronspi_uart_ist);
-               uart_add_one_port(driver_data->serial_driver, &uart_data->p[i].port);
-               printk(KERN_INFO "NEURONSPI: Added UART port %d\n", i);
-       }
-
-       // For ports on multiple SPI devices renumber the ports to correspond to SPI chip-select numbering
-       if (uart_data->p_count) {
-               // First remove all existing ports
-               for (i = 0; i < new_uart_count; i++) {
-                       uart_remove_one_port(driver_data->serial_driver, &uart_data->p[i].port);
-                       clear_bit(uart_data->p[i].port.line, &neuronspi_lines);
-                       kthread_flush_worker(&uart_data->kworker);
-               }
-               // Now add the ports in the correct order
-               for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
-                       if (neuronspi_s_dev[i] != NULL) {
-                               driver_data = spi_get_drvdata(neuronspi_s_dev[i]);
-#if NEURONSPI_DETAILED_DEBUG > 0
-                               printk(KERN_DEBUG "NEURONSPI: Renumber not NULL %d UC:%d\n", i, driver_data->uart_count);
-#endif
-                               if (driver_data->uart_count) {
-                                       for (j = 0; j < new_uart_count; j++) {
-                                               if (uart_data->p[j].dev_index == i) {
-                                                       uart_data->p[j].port.dev        = &(neuronspi_s_dev[i]->dev);
-                                                       uart_data->p[j].port.irq        = neuronspi_s_dev[i]->irq;
-                                                       uart_data->p[j].port.type       = PORT_NEURONSPI;
-                                                       uart_data->p[j].port.fifosize   = NEURONSPI_FIFO_SIZE;
-                                                       uart_data->p[j].port.flags      = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
-                                                       uart_data->p[j].port.iotype     = UPIO_PORT;
-                                                       uart_data->p[j].port.uartclk    = 9800;
-                                                       uart_data->p[j].port.rs485_config = neuronspi_uart_config_rs485;
-                                                       uart_data->p[j].port.ops        = &neuronspi_uart_ops;
-                                                       uart_data->p[j].port.line       = neuronspi_uart_alloc_line();
-                                                       uart_add_one_port(driver_data->serial_driver, &uart_data->p[j].port);
-#if NEURONSPI_DETAILED_DEBUG > 0
-                                                       printk(KERN_DEBUG "NEURONSPI: Added UART port %d\n", j);
-#endif
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       uart_data->p_count = new_uart_count;
-       if (uart_data->kworker_task == NULL) {
-#if NEURONSPI_DETAILED_DEBUG > 0
-               printk(KERN_DEBUG "NEURONSPI: KWorker Task is NULL\n");
-#endif
-
-               kthread_init_worker(&uart_data->kworker);
-
-               uart_data->kworker_task = kthread_run(kthread_worker_fn, &uart_data->kworker,
-                                                 "neuronspi");
-               if (IS_ERR(uart_data->kworker_task)) {
-                       ret = PTR_ERR(uart_data->kworker_task);
-               }
-               sched_setscheduler(uart_data->kworker_task, SCHED_FIFO, &sched_param);
-       }
-       return ret;
-}
-
-s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data)
-{
-       struct neuronspi_driver_data *d_data;
-       struct spi_device *spi;
-       s32 i;
-
-       for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
-               if (!(neuronspi_s_dev[i] == NULL)) {
-                       spi = neuronspi_s_dev[i];
-                       d_data = spi_get_drvdata(spi);
-                       if (d_data->poll_thread != NULL) {
-                               kthread_stop(d_data->poll_thread);
-                       }
-               }
-       }
-       for (i = 0; i < u_data->p_count; i++) {
-               uart_remove_one_port(neuronspi_uart, &u_data->p[i].port);
-               clear_bit(u_data->p[i].port.line, &neuronspi_lines);
-               neuronspi_uart_power(&u_data->p[i].port, 0);
-       }
-
-       kthread_flush_worker(&u_data->kworker);
-       return 0;
-}
-
-void neuronspi_uart_rx_proc(struct kthread_work *ws)
-{
-       s32 end_flag = 0;
-       s32 read_count = 0;
-       struct neuronspi_port *n_port = to_neuronspi_port(ws, rx_work);
-       struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
-
-       u8 *send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
-       u8 *recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
-
-       mutex_lock(&neuronspi_master_mutex);
-       read_count = d_data->uart_read;
-       mutex_unlock(&neuronspi_master_mutex);
-
-       while (!end_flag) {
-               memset(recv_buf, 0, NEURONSPI_BUFFER_MAX);
-               neuronspi_spi_uart_read(spi, send_buf, recv_buf, read_count, n_port->dev_port);
-               if (recv_buf[6] == 0x65 && recv_buf[7] > 0) {
-                       mutex_lock(&neuronspi_master_mutex);
-                       memcpy(&d_data->uart_buf[0], &recv_buf[10], recv_buf[7]);
-                       neuronspi_uart_handle_rx(n_port, recv_buf[7], 1);
-                       read_count = recv_buf[9];
-                       mutex_unlock(&neuronspi_master_mutex);
-               } else if (recv_buf[0] != 0x41) {
-                       mutex_lock(&neuronspi_master_mutex);
-                       d_data->uart_read = 0;
-                       end_flag = 1;
-                       mutex_unlock(&neuronspi_master_mutex);
-               }
-       }
-       kfree(recv_buf);
-       kfree(send_buf);
-}
-
-void neuronspi_uart_start_tx(struct uart_port *port)
-{
-       struct neuronspi_port *n_port = to_neuronspi_port(port,port);
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_INFO "NEURONSPI: Start TX\n");
-#endif
-       kthread_queue_work(&n_port->parent->kworker, &n_port->tx_work);
-}
-
-s32 neuronspi_uart_poll(void *data)
-{
-       struct neuronspi_driver_data *d_data = (struct neuronspi_driver_data*) data;
-       struct neuronspi_uart_data *u_data;
-       s32 i;
-       while (!kthread_should_stop()) {
-               usleep_range(2000,8000);
-               if (d_data->uart_count) {
-                       u_data = d_data->uart_data;
-                       for (i = 0; i < u_data->p_count; i++) {
-                               if (u_data->p[i].dev_index == d_data->neuron_index) {
-                                       kthread_queue_work(&u_data->kworker, &u_data->p[i].irq_work);
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-
-// Initialise the driver
-s32 neuronspi_uart_startup(struct uart_port *port)
-{
-       struct neuronspi_port *n_port = to_neuronspi_port(port, port);
-       struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
-       neuronspi_spi_set_irqs(spi, 0x5);
-       if (d_data->poll_thread != NULL) {
-               wake_up_process(d_data->poll_thread);
-       } else if (d_data->no_irq) {
-               d_data->poll_thread = kthread_create(neuronspi_uart_poll, (void *)d_data, "UART_poll_thread");
-       }
-       neuronspi_uart_power(port, 1);
-       // TODO: /* Reset FIFOs*/
-#if NEURONSPI_DETAILED_DEBUG > 0
-       printk(KERN_DEBUG "NEURONSPI: UART Startup\n");
-#endif
-       return 0;
-}
-
-void neuronspi_uart_shutdown(struct uart_port *port)
-{
-    neuronspi_uart_power(port, 0);
-}
-
-/*******************
- * Empty functions *
- *******************/
-
-void neuronspi_uart_stop_tx(struct uart_port *port)
-{
-       /* Do Nothing */
-}
-
-void neuronspi_uart_stop_rx(struct uart_port *port)
-{
-       /* Do Nothing */
-}
-void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl)
-{
-       /* Do Nothing */
-}
-void neuronspi_uart_break_ctl(struct uart_port *port, int break_state)
-{
-       /* Do Nothing */
-}
-void neuronspi_uart_power(struct uart_port *port, s32 on)
-{
-    /* Do nothing */
-}
-void neuronspi_uart_null_void(struct uart_port *port)
-{
-       /* Do nothing */
-}
diff --git a/modules/neuron_spi/src/unipi_uart.h b/modules/neuron_spi/src/unipi_uart.h
deleted file mode 100644 (file)
index 81a702d..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
- * Author: Tomas Knot <tomasknot@gmail.com>
- *
- *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
- *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- *
- */
-
-#ifndef MODULES_NEURON_SPI_SRC_UNIPI_UART_H_
-#define MODULES_NEURON_SPI_SRC_UNIPI_UART_H_
-
-/************
- * Includes *
- ************/
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
-#include <linux/iio/iio.h>
-#include <uapi/linux/iio/types.h>
-#include <linux/iio/sysfs.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
-#include <linux/leds.h>
-#include <linux/uaccess.h>
-#include <asm/termbits.h>
-#include <asm/gpio.h>
-
-#include "unipi_common.h"
-#include "unipi_platform.h"
-
-/***************
- * Definitions *
- ***************/
-
-#define NEURONSPI_UART_IFLAGS_REGISTER         502
-#define NEURONSPI_UART_LDISC_REGISTER  503
-#define NEURONSPI_UART_TIMEOUT_REGISTER 504
-
-/*************************
- * Function Declarations *
- *************************/
-
-void neuronspi_uart_start_tx(struct uart_port *port);
-void neuronspi_uart_stop_tx(struct uart_port *port);
-void neuronspi_uart_stop_rx(struct uart_port *port);
-void neuronspi_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old);
-u32 neuronspi_uart_tx_empty(struct uart_port *port);
-void neuronspi_uart_break_ctl(struct uart_port *port, int break_state);
-void neuronspi_uart_shutdown(struct uart_port *port);
-s32 neuronspi_uart_startup(struct uart_port *port);
-s32 neuronspi_uart_request_port(struct uart_port *port);
-s32 neuronspi_uart_alloc_line(void);
-void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl);
-int    neuronspi_uart_ioctl (struct uart_port *port, unsigned int ioctl_code, unsigned long ioctl_arg);
-void neuronspi_uart_set_ldisc(struct uart_port *port, struct ktermios *kterm);
-u32 neuronspi_uart_get_mctrl(struct uart_port *port);
-const char *neuronspi_uart_type(struct uart_port *port);
-void neuronspi_uart_null_void(struct uart_port *port);
-void neuronspi_uart_config_port(struct uart_port *port, int flags);
-s32 neuronspi_uart_verify_port(struct uart_port *port, struct serial_struct *s);
-void neuronspi_uart_pm(struct uart_port *port, u32 state,  u32 oldstate);
-s32 neuronspi_uart_poll(void *data);
-s32 neuronspi_uart_probe(struct spi_device* dev, u8 device_index);
-s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data);
-void neuronspi_uart_power(struct uart_port *port, s32 on);
-s32 neuronspi_uart_config_rs485(struct uart_port *port, struct serial_rs485 *rs485);
-void neuronspi_spi_uart_set_cflag(struct spi_device* spi_dev, u8 port, u32 to);
-u32 neuronspi_spi_uart_get_cflag(struct spi_device* spi_dev, u8 port);
-void neuronspi_uart_fifo_write(struct neuronspi_port *port, u8 to_send);
-void neuronspi_uart_fifo_read(struct uart_port *port, u32 rxlen);
-void neuronspi_uart_rx_proc(struct kthread_work *ws);
-void neuronspi_uart_tx_proc(struct kthread_work *ws);
-void neuronspi_uart_ist(struct kthread_work *ws);
-void neuronspi_uart_handle_tx(struct neuronspi_port *port);
-void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir);
-void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno);
-
-/*********************
- * Data Declarations *
- *********************/
-
-extern struct neuronspi_uart_data* neuronspi_uart_glob_data;
-extern unsigned long neuronspi_lines;
-extern struct uart_driver* neuronspi_uart;
-
-static const struct uart_ops neuronspi_uart_ops =
-{
-       .tx_empty                       = neuronspi_uart_tx_empty,
-       .set_mctrl                      = neuronspi_uart_set_mctrl,
-       .get_mctrl                      = neuronspi_uart_get_mctrl,
-       .stop_tx                        = neuronspi_uart_stop_tx,
-       .start_tx                       = neuronspi_uart_start_tx,
-       .stop_rx                        = neuronspi_uart_stop_rx,
-       .break_ctl                      = neuronspi_uart_break_ctl,
-       .startup                        = neuronspi_uart_startup,
-       .shutdown                       = neuronspi_uart_shutdown,
-       .set_termios            = neuronspi_uart_set_termios,
-       .set_ldisc                      = neuronspi_uart_set_ldisc,
-       .type                           = neuronspi_uart_type,
-       .request_port           = neuronspi_uart_request_port,
-       .release_port           = neuronspi_uart_null_void,
-       .config_port            = neuronspi_uart_config_port,
-       .verify_port            = neuronspi_uart_verify_port,
-       .pm                                     = neuronspi_uart_pm,
-       .ioctl                          = neuronspi_uart_ioctl,
-};
-
-#endif /* MODULES_NEURON_SPI_SRC_UNIPI_UART_H_ */
diff --git a/modules/unipi/Makefile b/modules/unipi/Makefile
new file mode 100644 (file)
index 0000000..321946c
--- /dev/null
@@ -0,0 +1,69 @@
+# Note: Compiling kernel modules requires creating symlinks, which is not possible on certain 
+# filesystems (notably VirtualBox vmfs); therefore we allow using /run/ through the 'symlink' target,
+# if necessary.
+SYMLINK_DIR_PATH = /run/kernel/neuron_spi
+LINUX_DIR_PATH = /root/bokula/linux
+SRC_DIR_PATH = $(PWD)/src
+BIN_DIR_PATH = $(PWD)/bin
+
+MODULE_MAKE_FILE = Makefile
+
+C_SRC_FILES = unipi_spi.c
+C_SRC_FILES += unipi_iio.c
+C_SRC_FILES += unipi_gpio.c
+C_SRC_FILES += unipi_uart.c
+C_SRC_FILES += unipi_sysfs.c
+C_SRC_FILES += unipi_misc.c
+C_SRC_FILES += unipi_platform.c
+
+H_SRC_FILES = unipi_spi.h
+H_SRC_FILES += unipi_iio.h
+H_SRC_FILES += unipi_gpio.h
+H_SRC_FILES += unipi_uart.h
+H_SRC_FILES += unipi_sysfs.h
+H_SRC_FILES += unipi_misc.h
+H_SRC_FILES += unipi_platform.h
+H_SRC_FILES += unipi_common.h
+
+OBJ_FILES = src/unipi_spi.o
+OBJ_FILES += src/unipi_iio.o
+OBJ_FILES += src/unipi_gpio.o
+OBJ_FILES += src/unipi_uart.o
+OBJ_FILES += src/unipi_sysfs.o
+OBJ_FILES += src/unipi_misc.o
+OBJ_FILES += src/unipi_platform.o
+
+KERNEL_MODULE_NAME = unipi
+obj-m += ${KERNEL_MODULE_NAME}.o
+unipi-objs := ${OBJ_FILES}
+
+TARGET_PLC_PATH = tomunipi:/root/
+
+.PHONY: default
+default: symlink ;
+
+all: 
+       make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C ${LINUX_DIR_PATH} M=${PWD} modules
+
+clean: 
+       make -C ${LINUX_DIR_PATH} M=$(PWD) clean
+       rm -f ${BIN_DIR_PATH}/${KERNEL_MODULE_NAME}.ko
+
+transfer: clean symlink
+       scp ${BIN_DIR_PATH}/${KERNEL_MODULE_NAME}.ko ${TARGET_PLC_PATH}
+       
+symlink: clean
+       rm -r -f ${SYMLINK_DIR_PATH}
+       mkdir -p ${SYMLINK_DIR_PATH}/src
+       mkdir -p ${SYMLINK_DIR_PATH}/bin
+       cp ${PWD}/${MODULE_MAKE_FILE} ${SYMLINK_DIR_PATH} 
+       for f in ${C_SRC_FILES}; do\
+               ln -s ${SRC_DIR_PATH}/$$f ${SYMLINK_DIR_PATH}/src ;\
+               done
+       for f in ${H_SRC_FILES}; do\
+               ln -s ${SRC_DIR_PATH}/$$f ${SYMLINK_DIR_PATH}/src ;\
+               done
+       cd ${SYMLINK_DIR_PATH}; make all
+       mv ${SYMLINK_DIR_PATH}/${KERNEL_MODULE_NAME}.ko ${BIN_DIR_PATH}
+       rm -r -f ${SYMLINK_DIR_PATH}
diff --git a/modules/unipi/bin b/modules/unipi/bin
new file mode 100644 (file)
index 0000000..9cdf8fa
Binary files /dev/null and b/modules/unipi/bin differ
diff --git a/modules/unipi/src/unipi_common.h b/modules/unipi/src/unipi_common.h
new file mode 100644 (file)
index 0000000..f7646a3
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_COMMON_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_COMMON_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+/***************
+ * Definitions *
+ ***************/
+
+#define NEURONSPI_SCHED_REQUIRED 0 // Older kernels do not require sched/types to be specifically imported
+#define NEURONSPI_MAJOR_VERSIONSTRING "Development Beta Version 0.02:12:02:2018"
+
+#define NEURONSPI_MAX_DEVS                             3
+#define NEURONSPI_MAX_UART                             128
+#define NEURONSPI_BUFFER_MAX                   1152
+#define NEURONSPI_HEADER_LENGTH                10
+#define NEURONSPI_FIRST_MESSAGE_LENGTH 6
+#define NEURONSPI_EDGE_DELAY                   10
+#define NEURONSPI_B_PER_WORD                   8
+#define NEURONSPI_DEFAULT_FREQ                 600000
+#define NEURONSPI_COMMON_FREQ                  12000000
+#define NEURONSPI_SLOWER_FREQ                  8000000
+#define NEURONSPI_MAX_TX                               62
+#define NEURONSPI_MAX_BAUD                             115200
+#define NEURONSPI_FIFO_SIZE                            256
+#define NEURONSPI_DETAILED_DEBUG               0
+#define NEURONSPI_LAST_TRANSFER_DELAY  40
+
+#define NEURON_DEVICE_NAME                             "neuronspi"
+#define NEURON_DEVICE_CLASS                    "modbus_spi"
+#define NEURON_DRIVER_NAME                             "NEURONSPI"
+#define PORT_NEURONSPI                                 184
+
+#define STRICT_RESERVING
+#define NEURONSPI_ALWAYS_EXPORT
+
+#define NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(X)  ((((X) + 15) >> 4) << 1)
+
+/********************
+ * Module Constants *
+ ********************/
+
+#define NEURONSPI_NO_INTERRUPT_MODELS_LEN                              3
+static const u16 NEURONSPI_NO_INTERRUPT_MODELS[NEURONSPI_NO_INTERRUPT_MODELS_LEN] = {
+               0xb10, 0xc10, 0xf10
+};
+
+/*******************
+ * Data Structures *
+ *******************/
+
+enum neuron_str_attribute_type {
+               NEURON_SATTR_MODEL,
+               NEURON_SATTR_EEPROM,
+               NEURON_SATTR_BOARD_NAME,
+               NEURON_SATTR_GPIO_GROUP_NAME
+};
+
+enum neuron_num_attribute_type {
+               NEURON_NATTR_BOARDCOUNT,
+               NEURON_NATTR_MODE,
+               NEURON_NATTR_CURRENT_VALUE
+};
+
+struct neuronspi_devtype
+{
+       u8      name[10];
+       s32     nr_gpio;
+       s32     nr_uart;
+};
+
+struct neuronspi_port
+{
+       struct uart_port                        port;
+       u8                                                      line;
+       struct kthread_work                     tx_work;
+       struct kthread_work                     rx_work;
+       struct kthread_work                     irq_work;
+       u32                                                     flags;
+       u8                                                      ier_clear;
+       u8                                                      buf[NEURONSPI_FIFO_SIZE];
+       struct neuronspi_uart_data      *parent;
+       u8                                                      dev_index;
+       u8                                                      dev_port;
+       u8                                                      parmrk_enabled;
+       u64                                                     parmrk_frame_delay;
+       s32                                                     baud;
+};
+
+struct neuronspi_uart_data
+{
+       const struct neuronspi_devtype  *devtype;
+       struct kthread_worker                   kworker;
+       struct task_struct                              *kworker_task;
+       struct neuronspi_port                   *p;
+       u8                                                              p_count;
+};
+
+// Instantiated once
+struct neuronspi_char_driver
+{
+       s32 major_number;
+       u8 *message;
+       u16 message_size;
+       u32 open_counter;
+       struct class* driver_class;
+       struct device* dev;
+};
+
+// Instantiated once per SPI device
+struct neuronspi_driver_data
+{
+       struct spi_driver *spi_driver;
+       struct neuronspi_char_driver *char_driver;
+       struct uart_driver *serial_driver;
+       struct neuronspi_uart_data *uart_data;
+       struct neuronspi_led_driver *led_driver;
+       struct neuronspi_di_driver **di_driver;
+       struct neuronspi_do_driver **do_driver;
+       struct neuronspi_ro_driver **ro_driver;
+       struct platform_device *board_device;
+       struct iio_dev *stm_ai_driver;
+       struct iio_dev *stm_ao_driver;
+       struct iio_dev **sec_ai_driver;
+       struct iio_dev **sec_ao_driver;
+       struct kthread_worker primary_worker;
+       struct task_struct *primary_worker_task;
+       struct regmap *reg_map;
+       struct task_struct *poll_thread;
+       struct mutex device_lock;
+       struct neuronspi_board_features *features;
+       struct neuronspi_board_regstart_table *regstart_table;
+       struct spinlock sysfs_regmap_lock;
+       char platform_name[sizeof("io_group0")];
+       u8 *send_buf;
+       u8 *recv_buf;
+       u8 *first_probe_reply;
+       u8 *second_probe_reply;
+       u8 reserved_device;
+       u8 uart_count;
+       u8 uart_read;
+       u8 *uart_buf;
+       u8 slower_model;
+       u8 no_irq;
+       u8 lower_board_id;
+       u8 upper_board_id;
+       u8 combination_id;
+       s32 neuron_index;
+       u16 sysfs_regmap_target;
+       u16 sysfs_counter_target;
+       u32 ideal_frequency;
+};
+
+struct neuronspi_di_driver {
+       struct spi_device* spi;
+       struct gpio_chip gpio_c;
+       struct platform_device *plat_dev;
+       u8 di_index;
+       char name[sizeof("di_0_00")];
+};
+
+struct neuronspi_do_driver
+{
+       struct spi_device* spi;
+       struct gpio_chip gpio_c;
+       struct platform_device *plat_dev;
+       u8 do_index;
+       char name[sizeof("do_0_00")];
+};
+
+struct neuronspi_ro_driver
+{
+       struct spi_device* spi;
+       struct gpio_chip gpio_c;
+       struct platform_device *plat_dev;
+       u8 ro_index;
+       char name[sizeof("ro_0_00")];
+};
+
+struct neuronspi_sec_ai_driver
+{
+       struct iio *devices;
+       u16 dev_count;
+};
+
+struct neuronspi_sec_ao_driver
+{
+       struct iio *devices;
+       u16 dev_count;
+};
+
+struct neuronspi_stm_ai_data
+{
+       u32 mode;
+       struct spi_device *parent;
+};
+
+struct neuronspi_stm_ao_data
+{
+       u32 mode;
+       struct spi_device *parent;
+};
+
+struct neuronspi_sec_ai_data
+{
+       u32 index;
+       u32 mode;
+       struct spi_device *parent;
+};
+
+struct neuronspi_sec_ao_data
+{
+       u32 index;
+       u32 mode;
+       struct spi_device *parent;
+};
+
+// Instantiated once per LED
+struct neuronspi_led_driver
+{
+       struct led_classdev     ldev;
+       struct spi_device       *spi;
+       struct kthread_work     led_work;
+       int                                     id;
+       int                                     brightness;
+       char                            name[sizeof("neuron:green:uled-x1")];
+       spinlock_t                      lock;
+};
+
+struct neuronspi_file_data
+{
+       struct spi_device** spi_device;
+       struct mutex            lock;
+       u8                                      *send_buf;
+       u8                                      *recv_buf;
+       u32                     message_len;
+};
+
+struct neuronspi_direct_acc
+{
+       void __iomem            *vaddr;
+       u32                                     size;
+};
+
+/*********************
+ * Data Declarations *
+ *********************/
+
+extern struct mutex neuronspi_master_mutex;
+extern struct neuronspi_char_driver neuronspi_cdrv;
+extern struct spinlock* neuronspi_spi_w_spinlock;
+extern struct spi_device* neuronspi_s_dev[NEURONSPI_MAX_DEVS];
+extern struct task_struct *neuronspi_invalidate_thread;
+
+extern u8 neuronspi_spi_w_flag;
+extern u8 neuronspi_probe_count;
+extern int neuronspi_model_id;
+extern spinlock_t neuronspi_probe_spinlock;
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_COMMON_H_ */
diff --git a/modules/unipi/src/unipi_gpio.c b/modules/unipi/src/unipi_gpio.c
new file mode 100644 (file)
index 0000000..e7d9de6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+/************
+ * Includes *
+ ************/
+
+#include "unipi_gpio.h"
+#include "unipi_spi.h"
+
+/************************
+ * Non-static Functions *
+ ************************/
+
+int neuronspi_gpio_di_direction_input(struct gpio_chip *chip, unsigned offset) {
+       return 0;
+}
+
+int neuronspi_gpio_di_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
+       return -EINVAL;
+}
+
+int neuronspi_gpio_di_get(struct gpio_chip *chip, unsigned offset) {
+       struct neuronspi_di_driver *n_di = gpiochip_get_data(chip);
+       struct spi_device *spi = n_di->spi;
+       return neuronspi_spi_gpio_di_get(spi, n_di->di_index);
+}
+
+int neuronspi_gpio_do_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
+       return 0;
+}
+
+void neuronspi_gpio_do_set(struct gpio_chip *chip, unsigned offset, int value) {
+       struct neuronspi_do_driver *n_do = gpiochip_get_data(chip);
+       struct spi_device *spi = n_do->spi;
+       neuronspi_spi_gpio_do_set(spi, n_do->do_index, value);
+}
+
+int neuronspi_gpio_ro_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
+       return 0;
+}
+
+void neuronspi_gpio_ro_set(struct gpio_chip *chip, unsigned offset, int value) {
+       struct neuronspi_ro_driver *n_ro = gpiochip_get_data(chip);
+       struct spi_device *spi = n_ro->spi;
+       neuronspi_spi_gpio_ro_set(spi, n_ro->ro_index, value);
+}
+
diff --git a/modules/unipi/src/unipi_gpio.h b/modules/unipi/src/unipi_gpio.h
new file mode 100644 (file)
index 0000000..508fd78
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_GPIO_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_GPIO_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+#include "unipi_common.h"
+
+/*************************
+ * Function Declarations *
+ *************************/
+
+int neuronspi_gpio_di_direction_input(struct gpio_chip *chip, unsigned offset);
+int neuronspi_gpio_di_direction_output(struct gpio_chip *chip, unsigned offset, int value);
+int    neuronspi_gpio_di_get(struct gpio_chip *chip, unsigned offset);
+int neuronspi_gpio_do_direction_input(struct gpio_chip *chip, unsigned offset);
+int neuronspi_gpio_do_direction_output(struct gpio_chip *chip, unsigned offset, int value);
+void neuronspi_gpio_do_set(struct gpio_chip *chip, unsigned offset, int value);
+int neuronspi_gpio_ro_direction_input(struct gpio_chip *chip, unsigned offset);
+int neuronspi_gpio_ro_direction_output(struct gpio_chip *chip, unsigned offset, int value);
+void neuronspi_gpio_ro_set(struct gpio_chip *chip, unsigned offset, int value);
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_GPIO_H_ */
diff --git a/modules/unipi/src/unipi_iio.c b/modules/unipi/src/unipi_iio.c
new file mode 100644 (file)
index 0000000..eca3eae
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+/************
+ * Includes *
+ ************/
+
+#include "unipi_iio.h"
+#include "unipi_spi.h"
+
+/************************
+ * Non-static Functions *
+ ************************/
+
+int neuronspi_iio_stm_ai_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask) {
+       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_mode_reg, &ai_data->mode);
+       switch(ai_data->mode) {
+       case 0: {
+               if (ch->type == IIO_VOLTAGE) {
+                       neuronspi_spi_iio_stm_ai_read_voltage(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_INT;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       case 1: {
+               if (ch->type == IIO_CURRENT) {
+                       neuronspi_spi_iio_stm_ai_read_current(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_INT;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       default: {
+               return -EINVAL;
+               break;
+       }
+       }
+}
+
+int neuronspi_iio_stm_ao_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, &ao_data->mode);
+       switch(ao_data->mode) {
+       case 3: {
+               if (ch->type == IIO_RESISTANCE) {
+                       neuronspi_spi_iio_stm_ao_read_resistance(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_INT;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       default: {
+               return -EINVAL;
+               break;
+       }
+       }
+}
+
+int neuronspi_iio_stm_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int val, int val2, long mask)
+{
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, &ao_data->mode);
+       switch(ao_data->mode) {
+       case 0: {
+               if (ch->type == IIO_VOLTAGE) {
+                       neuronspi_spi_iio_stm_ao_set_voltage(indio_dev, ch, val, val2, mask);
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       case 1: {
+               if (ch->type == IIO_CURRENT) {
+                       neuronspi_spi_iio_stm_ao_set_current(indio_dev, ch, val, val2, mask);
+                       return 0;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       default: {
+               return -EINVAL;
+               break;
+       }
+       }
+}
+
+int neuronspi_iio_sec_ai_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_mode_reg, &ai_data->mode);
+       switch(ai_data->mode) {
+       case 0: {
+               return -EINVAL;
+               break;
+       }
+       case 1: {
+               if (ch->type == IIO_VOLTAGE) {
+                       neuronspi_spi_iio_sec_ai_read_voltage(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_FRACTIONAL;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       case 2: {
+               if (ch->type == IIO_VOLTAGE) {
+                       neuronspi_spi_iio_sec_ai_read_voltage(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_FRACTIONAL;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       case 3: {
+               if (ch->type == IIO_CURRENT) {
+                       neuronspi_spi_iio_sec_ai_read_current(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_FRACTIONAL;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       case 4: {
+               if (ch->type == IIO_RESISTANCE) {
+                       neuronspi_spi_iio_sec_ai_read_resistance(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_FRACTIONAL;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       case 5: {
+               if (ch->type == IIO_RESISTANCE) {
+                       neuronspi_spi_iio_sec_ai_read_resistance(indio_dev, ch, val, val2, mask);
+                       return IIO_VAL_FRACTIONAL;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       }
+       default: {
+               return -EINVAL;
+               break;
+       }
+       }
+}
+
+int neuronspi_iio_sec_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int val, int val2, long mask)
+{
+       if (ch->type == IIO_VOLTAGE) {
+               neuronspi_spi_iio_stm_ao_set_voltage(indio_dev, ch, val, val2, mask);
+               return 0;
+       } else {
+               return -EINVAL;
+       }
+}
diff --git a/modules/unipi/src/unipi_iio.h b/modules/unipi/src/unipi_iio.h
new file mode 100644 (file)
index 0000000..c6e96c9
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_IIO_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_IIO_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+#include "unipi_common.h"
+
+/*************************
+ * Function Declarations *
+ *************************/
+
+int neuronspi_iio_stm_ai_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+int neuronspi_iio_stm_ao_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+int neuronspi_iio_stm_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
+int neuronspi_iio_sec_ai_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+int neuronspi_iio_sec_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_IIO_H_ */
diff --git a/modules/unipi/src/unipi_misc.c b/modules/unipi/src/unipi_misc.c
new file mode 100644 (file)
index 0000000..6efb89c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+/************
+ * Includes *
+ ************/
+
+#include "unipi_misc.h"
+#include "unipi_spi.h"
+
+/************************
+ * Non-static Functions *
+ ************************/
+
+void neuronspi_led_proc(struct kthread_work *ws)
+{
+       struct neuronspi_led_driver *led = to_led_driver(ws, led_work);
+       printk("NEURONSPI: BRIGHT id:%d\n", led->id);
+       neuronspi_spi_led_set_brightness(led->spi, led->brightness, led->id);
+}
+
+void neuronspi_led_set_brightness(struct led_classdev *ldev, enum led_brightness brightness)
+{
+       struct neuronspi_led_driver *led = container_of(ldev, struct neuronspi_led_driver, ldev);
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(led->spi);
+       spin_lock(&led->lock);
+       led->brightness = brightness;
+       kthread_queue_work(&n_spi->primary_worker, &led->led_work);
+       spin_unlock(&led->lock);
+}
diff --git a/modules/unipi/src/unipi_misc.h b/modules/unipi/src/unipi_misc.h
new file mode 100644 (file)
index 0000000..ebeb7e2
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_MISC_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_MISC_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+#include "unipi_common.h"
+
+/*************************
+ * Function Declarations *
+ *************************/
+
+void neuronspi_led_proc(struct kthread_work *ws);
+void neuronspi_led_set_brightness(struct led_classdev *ldev, enum led_brightness brightness);
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_MISC_H_ */
diff --git a/modules/unipi/src/unipi_platform.c b/modules/unipi/src/unipi_platform.c
new file mode 100644 (file)
index 0000000..08a0ec8
--- /dev/null
@@ -0,0 +1,1801 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+/************
+ * Includes *
+ ************/
+
+#include "unipi_platform.h"
+#include "unipi_spi.h"
+#include "unipi_common.h"
+
+/***************************
+ * Static Data Definitions *
+ ***************************/
+
+// B_1000 (S103)
+#define NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK_SIZE 57
+static u32 NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 21,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_AO_BRAIN | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                 // 2
+               NEURONSPI_REGFUN_AI_BRAIN | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,       // 3
+               NEURONSPI_REGFUN_AIO_BRAIN | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 4
+               NEURONSPI_REGFUN_V_REF_INP | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 5
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 6
+               NEURONSPI_REGFUN_TX_QUEUE_LEN | NEURONSPI_REGFLAG_ACC_10HZ,                                                                             // 7
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 16
+               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 17
+               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 18
+               NEURONSPI_REGFUN_PWM_DUTY | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 19
+               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                   // 20
+               1000, 32, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE  | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1014
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1015
+               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1016
+               NEURONSPI_REGFUN_PWM_PRESCALE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                      // 1017
+               NEURONSPI_REGFUN_PWM_CYCLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                         // 1018
+               NEURONSPI_REGFUN_AO_BRAIN_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                             // 1019
+               NEURONSPI_REGFUN_AO_BRAIN_V_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1020
+               NEURONSPI_REGFUN_AO_BRAIN_V_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1021
+               NEURONSPI_REGFUN_AO_BRAIN_I_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1022
+               NEURONSPI_REGFUN_AO_BRAIN_I_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1023
+               NEURONSPI_REGFUN_AI_BRAIN_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                             // 1024
+               NEURONSPI_REGFUN_AI_BRAIN_V_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1025
+               NEURONSPI_REGFUN_AI_BRAIN_V_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1026
+               NEURONSPI_REGFUN_AI_BRAIN_I_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1027
+               NEURONSPI_REGFUN_AI_BRAIN_I_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY, // 1028
+               NEURONSPI_REGFUN_AIO_BRAIN_OFF | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,  // 1029
+               NEURONSPI_REGFUN_AIO_BRAIN_ERR | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,  // 1030
+               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC                                                                              // 1031
+};
+
+#define NEURONSPI_BOARD_B1000_HW_FEATURES {    \
+               .do_count =                                       4,    \
+               .ro_count =                                       0,    \
+               .ds_count =                                       4,    \
+               .di_count =                                       4,    \
+               .led_count =                              4,    \
+               .stm_ai_count =                           1,    \
+               .stm_ao_count =                           1,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              1,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              4,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            1,    \
+}
+
+#define NEURONSPI_BOARD_B1000_HW_DEFINITION { \
+               .combination_board_id =         0, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_B1000_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .block_count =                          NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK_SIZE, \
+               .name_length =                          6, \
+               .combination_name =                     "B_1000", \
+               .features =                                     NEURONSPI_BOARD_B1000_HW_FEATURES, \
+               .blocks =                                       NEURONSPI_BOARD_B1000_HW_DEFINITION_BLOCK \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_B1000_HW_COMBINATION[] = {NEURONSPI_BOARD_B1000_HW_DEFINITION};
+
+// E-8Di8Ro (M103)
+#define NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK_SIZE 44
+static u32 NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 19,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               1000, 17, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1018
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1019
+               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1020
+};
+
+#define NEURONSPI_BOARD_E8DI8RO_HW_FEATURES {  \
+               .do_count =                                       0,    \
+               .ro_count =                                       8,    \
+               .ds_count =                                       8,    \
+               .di_count =                                       8,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION { \
+               .combination_board_id =         1, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E8DI8RO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .block_count =                          NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK_SIZE, \
+               .name_length =                          8, \
+               .combination_name =                     "E_8Di8Ro", \
+               .blocks =                                       NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E8DI8RO_HW_FEATURES     \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION};
+
+// E-14Ro
+#define NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK_SIZE 15
+static u32 NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 1,   // Register block beginning and size
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
+               1000, 10,
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
+};
+
+#define NEURONSPI_BOARD_E14RO_HW_FEATURES {    \
+               .do_count =                                       0,    \
+               .ro_count =                                       14,   \
+               .ds_count =                                       0,    \
+               .di_count =                                       0,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E14RO_HW_DEFINITION { \
+               .combination_board_id =         2, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .block_count =                          NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK_SIZE, \
+               .name_length =                          6, \
+               .combination_name =                     "E_14Ro", \
+               .blocks =                                       NEURONSPI_BOARD_E14RO_HW_DEFINITION_BLOCK, \
+               .features =                             NEURONSPI_BOARD_E14RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E14RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E14RO_HW_DEFINITION};
+
+// E-16Di
+#define NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK_SIZE 15
+static u32 NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 1,   // Register block beginning and size
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
+               1000, 10,
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
+};
+
+#define NEURONSPI_BOARD_E16DI_HW_FEATURES {    \
+               .do_count =                                       0,    \
+               .ro_count =                                       0,    \
+               .ds_count =                                       0,    \
+               .di_count =                                       16,   \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E16DI_HW_DEFINITION { \
+               .combination_board_id =         3, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .block_count =                          NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK_SIZE, \
+               .name_length =                          6, \
+               .combination_name =                     "E_16Di", \
+               .blocks =                                       NEURONSPI_BOARD_E16DI_HW_DEFINITION_BLOCK, \
+               .features =                             NEURONSPI_BOARD_E16DI_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E16DI_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DI_HW_DEFINITION};
+
+// E-8Di8Ro_P-11DiR485 (xS10)
+#define NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK_SIZE 47
+static u32 NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 20,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                    // 19
+               1000, 23, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DS_ENABLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1018
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1019
+               NEURONSPI_REGFUN_DS_TOGGLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1020
+               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1021
+               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1022
+};
+
+#define NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_FEATURES { \
+               .do_count =                                       0,    \
+               .ro_count =                                       8,    \
+               .ds_count =                                       8,    \
+               .di_count =                                       8,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               1,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            1,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION { \
+               .combination_board_id =         4, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E8DI8RO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P11DIR485_ID, \
+               .block_count =                          NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK_SIZE, \
+               .name_length =                          19, \
+               .combination_name =                     "E_8Di8Ro_P_11DiR485", \
+               .blocks =                                       NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_COMBINATION[] = {NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_DEFINITION};
+
+// E-14Ro_P-11DiR485 (xS40)
+#define NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK_SIZE 71
+static u32 NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 36,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
+               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_1HZ,                                                                    // 35
+               1000, 31, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                               // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                   // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                     // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE,                                                                  // 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
+               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1026
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1027
+               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1028
+               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1029
+               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1030
+};
+
+#define NEURONSPI_BOARD_E14ROP11DIR485_HW_FEATURES {   \
+               .do_count =                                       0,    \
+               .ro_count =                                       14,   \
+               .ds_count =                                       8,    \
+               .di_count =                                       8,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               1,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            1,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION { \
+               .combination_board_id =         5, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P11DIR485_ID, \
+               .name_length =                          17, \
+               .combination_name =                     "E_14Ro_P_11DiR485", \
+               .block_count =                          NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E14ROP11DIR485_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E14ROP11DIR485_HW_COMBINATION[] = {NEURONSPI_BOARD_E14ROP11DIR485_HW_DEFINITION};
+
+// E-16Di_P-11DiR485 (xS30)
+#define NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK_SIZE 92
+static u32 NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 52,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC,                                                                               // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 35
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 36
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 37
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 38
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 39
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 40
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 41
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 42
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 43
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 44
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 45
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 46
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 47
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 48
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 49
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 50
+               NEURONSPI_REGFUN_LED_RW | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                    // 51
+               1000, 36, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1026
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1027
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1028
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1029
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1030
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1031
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1032
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1033
+               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1034
+               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1035
+};
+
+#define NEURONSPI_BOARD_E16DIP11DIR485_HW_FEATURES {   \
+               .do_count =                                       0,    \
+               .ro_count =                                       0,    \
+               .ds_count =                                       0,    \
+               .di_count =                                       23,   \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               1,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            1,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION { \
+               .combination_board_id =         6, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P11DIR485_ID, \
+               .name_length =                          17, \
+               .combination_name =                     "E_16Di_P_11DiR485", \
+               .block_count =                          NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E16DIP11DIR485_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E16DIP11DIR485_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DIP11DIR485_HW_DEFINITION};
+
+// E-14Ro_U-14Ro (M403)
+#define NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK_SIZE 17
+static u32 NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 3,   // Register block beginning and size
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               1000, 10, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+};
+
+#define NEURONSPI_BOARD_E14ROU14RO_HW_FEATURES {       \
+               .do_count =                                       0,    \
+               .ro_count =                                       28,   \
+               .ds_count =                                       0,    \
+               .di_count =                                       0,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            1,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION { \
+               .combination_board_id =         7, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14RO_ID, \
+               .name_length =                          13, \
+               .combination_name =                     "E_14Ro_U_14Ro", \
+               .block_count =                          NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION_BLOCK, \
+               .features =                             NEURONSPI_BOARD_E14ROU14RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION};
+
+// E-16Di_U-14Ro (M203)
+#define NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK_SIZE 68
+static u32 NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 35,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
+               1000, 29, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
+               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1026
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1027
+               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1028
+};
+
+#define NEURONSPI_BOARD_E16DIU14RO_HW_FEATURES {       \
+               .do_count =                                       0,    \
+               .ro_count =                                       14,   \
+               .ds_count =                                       14,   \
+               .di_count =                                       16,   \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION { \
+               .combination_board_id =         8, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14RO_ID, \
+               .name_length =                          13, \
+               .combination_name =                     "E_16Di_U_14Ro", \
+               .block_count =                          NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E16DIU14RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION};
+
+// E-14Ro_U-14Di (L503)
+#define NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK_SIZE 62
+static u32 NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 31,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
+               1000, 27, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
+               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                 // 1024
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1025
+               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ                                                                                  // 1026
+};
+
+#define NEURONSPI_BOARD_E14ROU14DI_HW_FEATURES {       \
+               .do_count =                                       0,    \
+               .ro_count =                                       14,   \
+               .ds_count =                                       14,   \
+               .di_count =                                       14,   \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION { \
+               .combination_board_id =         9, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E14RO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14DI_ID, \
+               .name_length =                          13, \
+               .combination_name =                     "E_14Ro_U_14Di", \
+               .block_count =                          NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E14ROU14DI_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14DI_HW_COMBINATION[] = {NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION};
+
+
+// E-16Di_U-14Di (M303)
+#define NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK_SIZE 107
+static u32 NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 63,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                    // 1
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 2
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 3
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 4
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 5
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 6
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 7
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 8
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 9
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 10
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 11
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 12
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 13
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 18
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 19
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 20
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 21
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 22
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 23
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 24
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 25
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 26
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 27
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 28
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 29
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 30
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 31
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 32
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 33
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 34
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 35
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 36
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 37
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 38
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 39
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 40
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 41
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 42
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 43
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 44
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 45
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 46
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 47
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 48
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 49
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 50
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 51
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 52
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 53
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 54
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 55
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 56
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 57
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 58
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 59
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 60
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 61
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                 // 62
+               1000, 40, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1016
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1017
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1018
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1019
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1020
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1021
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1022
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1023
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1024
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1025
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1026
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1027
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1028
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1029
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1030
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1031
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1032
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1033
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1034
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1035
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1036
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1037
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1038
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1039
+};
+
+#define NEURONSPI_BOARD_E16DIU14DI_HW_FEATURES {       \
+               .do_count =                                       0,    \
+               .ro_count =                                       0,    \
+               .ds_count =                                       0,    \
+               .di_count =                                       30,   \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           0,    \
+               .sec_ao_count =                           0,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION { \
+               .combination_board_id =         10, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E16DI_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U14DI_ID, \
+               .name_length =                          13, \
+               .combination_name =                     "E_16Di_U_14Di", \
+               .block_count =                          NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E16DIU14DI_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14DI_HW_COMBINATION[] = {NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION};
+
+// E-4Ai4Ao
+#define NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK_SIZE 15
+static u32 NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 1,   // Register block beginning and size
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ | NEURONSPI_REGFLAG_SYS_READ_ONLY,                  // 0
+               1000, 10, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+};
+
+#define NEURONSPI_BOARD_E4AI4AO_HW_FEATURES {  \
+               .do_count =                                       0,    \
+               .ro_count =                                       0,    \
+               .ds_count =                                       0,    \
+               .di_count =                                       0,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           4,    \
+               .sec_ao_count =                           4,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               0,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            0,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+
+#define NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION { \
+               .combination_board_id =         11, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .name_length =                          8, \
+               .combination_name =                     "E_4Ai4Ao", \
+               .block_count =                          NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E4AI4AO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AO_HW_DEFINITION};
+
+// E-4Ai4Ao_P-6Di5Ro (xS50)
+#define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK_SIZE 56
+static u32 NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 27,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                        // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                            // 1
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 2
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 3
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 4
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                       // 5
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 6
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 7
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 8
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 9
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 10
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 11
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 12
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 13
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                       // 14
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 15
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 16
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 17
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 18
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 19
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 20
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 21
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 22
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 23
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 24
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 25
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                         // 26
+               1000, 25, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                              // 1015
+               NEURONSPI_REGFUN_DS_ENABLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1016
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1017
+               NEURONSPI_REGFUN_DS_TOGGLE   | NEURONSPI_REGFLAG_ACC_1HZ,                                                                               // 1018
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1019
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1020
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1021
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1022
+               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1023
+               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1024
+};
+
+#define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_FEATURES {   \
+               .do_count =                                       0,    \
+               .ro_count =                                       6,    \
+               .ds_count =                                       5,    \
+               .di_count =                                       5,    \
+               .led_count =                              0,    \
+               .stm_ai_count =                           0,    \
+               .stm_ao_count =                           0,    \
+               .sec_ai_count =                           4,    \
+               .sec_ao_count =                           4,    \
+               .uart_master_count =              0,    \
+               .uart_slave_count =               1,    \
+               .pwm_channel_count =              0,    \
+               .wd_count =                               1,    \
+               .extension_sys_count =            1,    \
+               .light_count =                            0,    \
+               .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION { \
+               .combination_board_id =         12, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P6DI5RO_ID, \
+               .name_length =                          17, \
+               .combination_name =                     "E_4Ai4Ao_P_6Di5Ro", \
+               .block_count =                          NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION};
+
+// B-485
+#define NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK_SIZE 15
+static u32 NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 1,   // Register block beginning and size
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
+               1000, 10,
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+};
+
+#define NEURONSPI_BOARD_B485_HW_FEATURES {     \
+       .do_count =                                       0,    \
+       .ro_count =                                       0,    \
+       .ds_count =                                       0,    \
+       .di_count =                                       0,    \
+       .led_count =                              0,    \
+       .stm_ai_count =                           0,    \
+       .stm_ao_count =                           0,    \
+       .sec_ai_count =                           4,    \
+       .sec_ao_count =                           4,    \
+       .uart_master_count =              1,    \
+       .uart_slave_count =               0,    \
+       .pwm_channel_count =              0,    \
+       .wd_count =                               1,    \
+       .extension_sys_count =            0,    \
+       .light_count =                            0,    \
+       .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_B485_HW_DEFINITION { \
+               .combination_board_id =         13, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_B485_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .name_length =                          5, \
+               .combination_name =                     "B_485", \
+               .block_count =                          NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_B485_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_B485_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_B485_HW_COMBINATION[] = {NEURONSPI_BOARD_B485_HW_DEFINITION};
+
+// E-4Light (M613)
+#define NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK_SIZE 35
+static u32 NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 21,  // Register block beginning and size
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 0
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 1
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 2
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 3
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 4
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 5
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 6
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 7
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 8
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 9
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 10
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 11
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 12
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 13
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 14
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 15
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 16
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 17
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 18
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 19
+               NEURONSPI_REGFUN_NONE_TEST | NEURONSPI_REGFLAG_ACC_ONCE,                                                                                // 20
+               1000, 10,
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,// 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,              // 1009
+};
+
+#define NEURONSPI_BOARD_E4LIGHT_HW_FEATURES {  \
+       .do_count =                                       0,    \
+       .ro_count =                                       0,    \
+       .ds_count =                                       0,    \
+       .di_count =                                       0,    \
+       .led_count =                              0,    \
+       .stm_ai_count =                           0,    \
+       .stm_ao_count =                           0,    \
+       .sec_ai_count =                           0,    \
+       .sec_ao_count =                           0,    \
+       .uart_master_count =              0,    \
+       .uart_slave_count =               0,    \
+       .pwm_channel_count =              0,    \
+       .wd_count =                               1,    \
+       .extension_sys_count =            0,    \
+       .light_count =                            4,    \
+       .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION { \
+               .combination_board_id =         14, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4LIGHT_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_NONE_ID, \
+               .name_length =                          8, \
+               .combination_name =                     "E_4Light", \
+               .block_count =                          NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E4LIGHT_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E4LIGHT_HW_COMBINATION[] = {NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION};
+
+// E-4Ai4Ao_U-6Di5Ro (L503)
+#define NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK_SIZE 56
+static u32 NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 28,  // Register block beginning and size
+               NEURONSPI_REGFUN_DI_READ | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,                                // 0
+               NEURONSPI_REGFUN_DO_RW | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                                    // 1
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 2
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 3
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 4
+               NEURONSPI_REGFUN_AO_VER2_RW | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 5
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP,       // 6
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP,       // 7
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 8
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 9
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 10
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 11
+               NEURONSPI_REGFUN_AI_VER2_READ_LOWER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 12
+               NEURONSPI_REGFUN_AI_VER2_READ_UPPER | NEURONSPI_REGFLAG_ACC_AFAP | NEURONSPI_REGFLAG_SYS_READ_ONLY,     // 13
+               NEURONSPI_REGFUN_MWD_STATUS | NEURONSPI_REGFLAG_ACC_6SEC | NEURONSPI_REGFLAG_SYS_READ_ONLY,                     // 14
+               NEURONSPI_REGFUN_TX_QUEUE_LEN | NEURONSPI_REGFLAG_ACC_10HZ,                                                                                             // 15
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 16
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 17
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 18
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 19
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 20
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 21
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 22
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 23
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 24
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 25
+               NEURONSPI_REGFUN_DI_COUNTER_LOWER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 26
+               NEURONSPI_REGFUN_DI_COUNTER_UPPER | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                 // 27
+               1000, 24, // Register block beginning and size
+               NEURONSPI_REGFUN_SW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                                 // 1000
+               NEURONSPI_REGFUN_DIDO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                             // 1001
+               NEURONSPI_REGFUN_UAIO_COUNT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                             // 1002
+               NEURONSPI_REGFUN_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                                 // 1003
+               NEURONSPI_REGFUN_FLASH_HW_VER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                   // 1004
+               NEURONSPI_REGFUN_SERIAL_NR_LOWER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1005
+               NEURONSPI_REGFUN_SERIAL_NR_UPPER | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                // 1006
+               NEURONSPI_REGFUN_INTERRUPTS | NEURONSPI_REGFLAG_ACC_AFAP,                                                                                               // 1007
+               NEURONSPI_REGFUN_MWD_TO | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                                   // 1008
+               NEURONSPI_REGFUN_V_REF_INT | NEURONSPI_REGFLAG_ACC_ONCE | NEURONSPI_REGFLAG_SYS_READ_ONLY,                              // 1009
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1010
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1011
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1012
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1013
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1014
+               NEURONSPI_REGFUN_DI_DEBOUNCE | NEURONSPI_REGFLAG_ACC_6SEC,                                                                                              // 1015
+               NEURONSPI_REGFUN_DS_ENABLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                                 // 1016
+               NEURONSPI_REGFUN_DS_POLARITY | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                               // 1017
+               NEURONSPI_REGFUN_DS_TOGGLE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                                 // 1018
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1019
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1020
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1021
+               NEURONSPI_REGFUN_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1022
+               NEURONSPI_REGFUN_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC                                                                                              // 1023
+};
+
+#define NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_FEATURES {   \
+       .do_count =                                       0,    \
+       .ro_count =                                       5,    \
+       .ds_count =                                       5,    \
+       .di_count =                                       6,    \
+       .led_count =                              0,    \
+       .stm_ai_count =                           0,    \
+       .stm_ao_count =                           0,    \
+       .sec_ai_count =                           4,    \
+       .sec_ao_count =                           4,    \
+       .uart_master_count =              0,    \
+       .uart_slave_count =               0,    \
+       .pwm_channel_count =              0,    \
+       .wd_count =                               1,    \
+       .extension_sys_count =            0,    \
+       .light_count =                            4,    \
+       .owire_count =                            0,    \
+}
+
+#define NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION { \
+               .combination_board_id =         15, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U6DI5RO_ID, \
+               .name_length =                          17, \
+               .combination_name =                     "E_4Ai4Ao_U_6Di5Ro", \
+               .block_count =                          NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION};
+
+/********************
+ * Data Definitions *
+ ********************/
+
+struct platform_device *neuron_plc_dev;
+
+struct neuronspi_board_combination NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E8DI8RO_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E4LIGHT_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14RO_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION, NEURONSPI_BOARD_E16DIU14DI_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14RO_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION,  NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION, NEURONSPI_BOARD_E14ROU14DI_HW_DEFINITION
+};
+
+struct neuronspi_board_combination NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD_SIZE] = {
+               NEURONSPI_BOARD_B1000_HW_DEFINITION, NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION, NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION
+};
+
+// Board table
+// Column 4 is the number of 0-indexed registers and column 5 is the number of 1000-indexed ones
+struct neuronspi_board_entry NEURONSPI_BOARDTABLE[NEURONSPI_BOARDTABLE_LEN] = {
+       {.index = 0, .lower_board_id = NEURONSPI_BOARD_LOWER_B1000_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 21,      .config_register_count = 32, .definition = NEURONSPI_BOARD_B1000_HW_COMBINATION},       // B_1000 (S103)
+       {.index = 1, .lower_board_id = NEURONSPI_BOARD_LOWER_E8DI8RO_ID,        .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 19,      .config_register_count = 21, .definition = NEURONSPI_BOARD_E8DI8RO_HW_COMBINATION},     // E-8Di8Ro (M103)
+       {.index = 2, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 1,       .config_register_count = 0,  .definition = NEURONSPI_BOARD_E14RO_HW_COMBINATION},               // E-14Ro
+       {.index = 3, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 1,       .config_register_count = 0,      .definition = NEURONSPI_BOARD_E16DI_HW_COMBINATION},           // E-16Di
+       {.index = 4, .lower_board_id = NEURONSPI_BOARD_LOWER_E8DI8RO_ID,        .upper_board_id = NEURONSPI_BOARD_UPPER_P11DIR485_ID,
+                       .data_register_count = 36,      .config_register_count = 31,  .definition = NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_COMBINATION},   // E-8Di8Ro_P-11DiR485 (xS10)
+       {.index = 5, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_P11DIR485_ID,
+                       .data_register_count = 20,      .config_register_count = 23,  .definition = NEURONSPI_BOARD_E14ROP11DIR485_HW_COMBINATION},     // E-14Ro_P-11DiR485 (xS40)
+       {.index = 6, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_P11DIR485_ID,
+                       .data_register_count = 52,      .config_register_count = 36,  .definition = NEURONSPI_BOARD_E16DIP11DIR485_HW_COMBINATION},     // E-16Di_P-11DiR485 (xS30)
+       {.index = 7, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_U14RO_ID,
+                       .data_register_count = 3,       .config_register_count = 10,  .definition = NEURONSPI_BOARD_E14ROU14RO_HW_COMBINATION}, // E-14Ro_U-14Ro (M403)
+       {.index = 8, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_U14RO_ID,
+                       .data_register_count = 35,      .config_register_count = 29,  .definition = NEURONSPI_BOARD_E16DIU14RO_HW_COMBINATION}, // E-16Di_U-14Ro (M203)
+       {.index = 9, .lower_board_id = NEURONSPI_BOARD_LOWER_E14RO_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_U14DI_ID,
+                       .data_register_count = 31,      .config_register_count = 27,  .definition = NEURONSPI_BOARD_E14ROU14DI_HW_COMBINATION}, // E-14Ro_U-14Di (L503)
+       {.index = 10, .lower_board_id = NEURONSPI_BOARD_LOWER_E16DI_ID,         .upper_board_id = NEURONSPI_BOARD_UPPER_U14DI_ID,
+                       .data_register_count = 63, .config_register_count = 40,   .definition = NEURONSPI_BOARD_E16DIU14DI_HW_COMBINATION},     // E-16Di_U-14Di (M303)
+       {.index = 11, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 1,       .config_register_count = 0,   .definition = NEURONSPI_BOARD_E4AI4AO_HW_COMBINATION},            // E-4Ai4Ao
+       {.index = 12, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_P6DI5RO_ID,
+                       .data_register_count = 27, .config_register_count = 25,   .definition = NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMBINATION}, // E-4Ai4Ao_P-6Di5Ro (xS50)
+       {.index = 13, .lower_board_id = NEURONSPI_BOARD_LOWER_B485_ID,          .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 1,  .config_register_count = 0,    .definition = NEURONSPI_BOARD_B485_HW_COMBINATION},           // B-485
+       {.index = 14, .lower_board_id = NEURONSPI_BOARD_LOWER_E4LIGHT_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_NONE_ID,
+                       .data_register_count = 21, .config_register_count = 8,    .definition = NEURONSPI_BOARD_E4LIGHT_HW_COMBINATION},                // E-4Light (M603)
+       {.index = 15, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_U6DI5RO_ID,
+                       .data_register_count = 28, .config_register_count = 24,   .definition = NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION}          // E-4Ai4Ao_U-6Di5Ro (M503)
+};
+
+// Module table
+struct neuronspi_model_definition NEURONSPI_MODELTABLE[NEURONSPI_MODELTABLE_LEN] = {
+               {.eeprom_length = 4, .eeprom_name = "S103", .name_length = 4, .model_name = "S103",
+                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "S103", .name_length = 6, .model_name = "S103-G",
+                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD},
+               {.eeprom_length = 6, .eeprom_name = "S103IQ", .name_length = 7, .model_name = "S103-IQ",
+                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD},
+               {.eeprom_length = 6, .eeprom_name = "S103EO", .name_length = 7, .model_name = "S103-EO",
+                               .combination_count = 1, .combinations = NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "M103", .name_length = 4, .model_name = "M103",
+                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "M203", .name_length = 4, .model_name = "M203",
+                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "M303", .name_length = 4, .model_name = "M303",
+                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "M403", .name_length = 4, .model_name = "M403",
+                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "M503", .name_length = 4, .model_name = "M503",
+                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "M603", .name_length = 4, .model_name = "M603",
+                               .combination_count = 2, .combinations = NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "L203", .name_length = 4, .model_name = "L203",
+                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "L303", .name_length = 4, .model_name = "L303",
+                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "L403", .name_length = 4, .model_name = "L403",
+                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "L503", .name_length = 4, .model_name = "L503",
+                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD},
+               {.eeprom_length = 4, .eeprom_name = "L513", .name_length = 4, .model_name = "L513",
+                               .combination_count = 3, .combinations = NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD}
+};
+
+/************************
+ * Non-static Functions *
+ ************************/
+
+s32 neuronspi_regmap_invalidate(void *data)
+{
+       int i;
+       int freq_cnt = 0;
+       while (!kthread_should_stop()) {
+               usleep_range(15000,25000);
+               if (freq_cnt == 450001) freq_cnt = 0;
+               for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
+                       if (neuronspi_s_dev[i] != NULL) {
+                               struct neuronspi_driver_data *d_data = spi_get_drvdata(neuronspi_s_dev[i]);
+                               if (d_data->combination_id == 0xFF) {
+                                       continue;
+                               }
+                               neuronspi_regmap_invalidate_device(d_data->reg_map, NEURONSPI_BOARDTABLE[d_data->combination_id].definition, freq_cnt);
+                       }
+               }
+               freq_cnt++;
+       }
+       return 0;
+}
+
+void neuronspi_regmap_invalidate_device(struct regmap *reg_map, struct neuronspi_board_combination *device_def, u32 period_counter)
+{
+       int block_start, block_len, block_counter, current_period, period_len;
+       int i;
+       block_start = -1;
+       block_len = -1;
+       block_counter = 0;
+       period_len = 1;
+
+       for (i = 0; i < device_def->block_count; i++) {
+               if (block_start == -1) {
+                       block_start = device_def->blocks[i];
+                       block_counter = 0;
+               } else if (block_len == -1) {
+                       block_len = device_def->blocks[i];
+               } else if ((block_counter != block_len)) {
+                       current_period = device_def->blocks[i] & 0x00FF0000;
+                       if ((block_counter + 1 != block_len) && ((device_def->blocks[i + 1] & 0x00FF0000) == current_period)) {
+                               period_len++;
+                       } else {
+                               switch (current_period) {
+                               case NEURONSPI_REGFLAG_ACC_AFAP: {
+                                       regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
+                                       break;
+                               }
+                               case NEURONSPI_REGFLAG_ACC_10HZ: {
+                                       if ((period_counter) % 5) {
+                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
+                                       }
+                                       break;
+                               }
+                               case NEURONSPI_REGFLAG_ACC_1HZ: {
+                                       if ((period_counter % 50) == 0) {
+                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
+                                       }
+                                       break;
+                               }
+                               case NEURONSPI_REGFLAG_ACC_6SEC: {
+                                       if ((period_counter % 300) == 0) {
+                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
+                                       }
+                                       break;
+                               }
+                               case NEURONSPI_REGFLAG_ACC_1MIN: {
+                                       if ((period_counter % 3000) == 0) {
+                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
+                                       }
+                                       break;
+                               }
+                               case NEURONSPI_REGFLAG_ACC_15MIN: {
+                                       if ((period_counter % 45000) == 0) {
+                                               regcache_drop_region(reg_map, block_start + block_counter - period_len + 1, block_start + block_counter);
+                                       }
+                                       break;
+                               }
+                               default:
+                                       break;
+                               }
+                               period_len = 1;
+                       }
+                       block_counter++;
+               }
+               if (block_counter == block_len) {
+                       block_counter = 0;
+                       block_start = -1;
+                       block_len = -1;
+               }
+       }
+}
+
+int neuronspi_regmap_hw_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct spi_device *spi = context;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u8 *inp_buf;
+       u8 *outp_buf;
+       int write_length;
+       printk(KERN_INFO "NEURONSPI: RM_REG_READ\n");
+       write_length = neuronspi_spi_compose_single_register_read(reg, &inp_buf, &outp_buf);
+       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
+       memcpy(val, &outp_buf[NEURONSPI_HEADER_LENGTH], sizeof(u16));
+       kfree(inp_buf);
+       kfree(outp_buf);
+       return 0;
+}
+
+int neuronspi_regmap_hw_write(void *context, const void *data, size_t count)
+{
+       BUG_ON(count < 1);
+       return neuronspi_regmap_hw_gather_write(context, data, 1, data + 1, count - 1);
+}
+
+int neuronspi_regmap_hw_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct spi_device *spi = context;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u8 *inp_buf;
+       u8 *outp_buf;
+       int write_length;
+       write_length = neuronspi_spi_compose_single_register_write(reg, &inp_buf, &outp_buf, (val >> 8));
+       printk(KERN_INFO "HW_REG_WRITE l:%d, r:%d, v:%d\n", write_length, reg, (val >> 8));
+       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
+       memcpy(&val, &outp_buf[NEURONSPI_HEADER_LENGTH], sizeof(u16));
+       kfree(inp_buf);
+       kfree(outp_buf);
+       return 0;
+}
+
+int neuronspi_regmap_hw_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size)
+{
+       u16 *mb_reg_buf = (u16*)reg;
+       u32 *mb_val_buf = (u32*)val;
+       struct spi_device *spi = context;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u8 *inp_buf;
+       u8 *outp_buf;
+       int i, write_length;
+       int block_counter = 0;
+       printk(KERN_INFO "HW_REG_GATHER_WRITE:%d, %d, %x, %x\n", val_size, reg_size, mb_reg_buf[0], mb_val_buf[0]);
+       if (reg_size == 1) {
+               neuronspi_regmap_hw_reg_write(context,mb_reg_buf[0],mb_val_buf[0]);
+       } else {
+               for (i = 0; i < reg_size; i++) {
+                       // Swap endianness
+                       cpu_to_be16s((u16*)&(mb_val_buf[i]));
+                       // Check for continuity and read the largest possible continuous block
+                       if (block_counter == (reg_size - 1) || ((mb_reg_buf[i] + 1) != mb_reg_buf[i + 1]))  {
+                               write_length = neuronspi_spi_compose_multiple_register_write(block_counter, mb_reg_buf[i - block_counter], &inp_buf, &outp_buf,
+                                                                                                    (u8*)(&mb_val_buf[i - block_counter]));
+                               neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 125, 1);
+                               block_counter = 0;
+                               kfree(inp_buf);
+                               kfree(outp_buf);
+                       } else {
+                               block_counter++;
+                       }
+               }
+       }
+       return 0;
+}
+
+int neuronspi_create_reg_starts(struct neuronspi_board_regstart_table *out_table, struct neuronspi_board_combination *board) {
+       if (board->features.di_count > 0) {
+               out_table->di_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DI_READ);
+               out_table->di_counter_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DI_COUNTER_UPPER);
+               out_table->di_deboun_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DI_DEBOUNCE);
+               out_table->di_direct_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DS_ENABLE);
+               out_table->di_polar_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DS_POLARITY);
+               out_table->di_toggle_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DS_TOGGLE);
+       }
+       if (board->features.do_count > 0) {
+               out_table->do_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DO_RW);
+               out_table->do_pwm_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_PWM_DUTY);
+               out_table->do_pwm_c_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_PWM_CYCLE);
+               out_table->do_pwm_ps_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_PWM_PRESCALE);
+       }
+       if (board->features.led_count > 0) {
+               out_table->led_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_LED_RW);
+       }
+       if (board->features.light_count > 0) {
+               // TODO: Fill in light bus registers
+       }
+       if (board->features.ro_count > 0) {
+               out_table->ro_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_DO_RW);
+       }
+       if (board->features.sec_ai_count > 0) {
+               out_table->sec_ai_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_VER2_READ_LOWER);
+               out_table->sec_ai_mode_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_VER2_MODE);
+       }
+       if (board->features.sec_ao_count > 0) {
+               out_table->sec_ao_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_VER2_RW);
+       }
+       if (board->features.stm_ao_count > 0) {
+               out_table->stm_ao_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN);
+               out_table->stm_ao_mode_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_MODE);
+               out_table->stm_ao_vol_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_V_ERR);
+               out_table->stm_ao_vol_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_V_OFF);
+               out_table->stm_ao_curr_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_I_ERR);
+               out_table->stm_ao_curr_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AO_BRAIN_I_OFF);
+       }
+       if (board->features.stm_ai_count > 0) {
+               out_table->stm_ai_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN);
+               out_table->stm_ai_mode_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_MODE);
+               out_table->stm_ai_vol_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_V_ERR);
+               out_table->stm_ai_vol_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_V_OFF);
+               out_table->stm_ai_curr_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_I_ERR);
+               out_table->stm_ai_curr_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AI_BRAIN_I_OFF);
+               out_table->stm_aio_val_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AIO_BRAIN);
+               out_table->stm_aio_vol_err = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AIO_BRAIN_ERR);
+               out_table->stm_aio_vol_off = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_AIO_BRAIN_OFF);
+               out_table->vref_inp = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_V_REF_INP);
+       }
+       out_table->uart_queue_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_TX_QUEUE_LEN);
+       out_table->uart_conf_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_RS485_CONFIG);
+       out_table->vref_int = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_V_REF_INT);
+       out_table->wd_timeout_reg = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_MWD_TO);
+       out_table->sys_serial_num = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_SERIAL_NR_LOWER);
+       out_table->sys_sw_ver = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_SW_VER);
+       out_table->sys_hw_ver = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_HW_VER);
+       out_table->sys_hw_flash_ver = neuronspi_find_reg_start(board, NEURONSPI_REGFUN_FLASH_HW_VER);
+       return 0;
+}
+
+s32 neuronspi_find_reg_start(struct neuronspi_board_combination *board, u16 regfun) {
+       int i;
+       int block_start = -1;
+       int block_len = -1;
+       int block_counter = 0;
+       for (i = 0; i < board->block_count; i++) {
+               if (block_start == -1) {
+                       block_start = board->blocks[i];
+               } else if (block_len == -1) {
+                       block_len = board->blocks[i];
+               } else if ((board->blocks[i] & 0xFFFF) == regfun) {
+                       //printk(KERN_INFO "NEURONSPI: Reg Start Fun: %x RegS: %d", regfun, block_start + block_counter);
+                       return block_start + block_counter;
+               } else {
+                       block_counter++;
+               }
+               if (block_counter == block_len) {
+                       block_counter = 0;
+                       block_start = -1;
+                       block_len = -1;
+               }
+       }
+       return -1;
+}
+
+int neuronspi_regmap_hw_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size) {
+       const u16 *mb_reg_buf = reg_buf;
+       u16 *mb_val_buf = val_buf;
+       struct spi_device *spi;
+       struct neuronspi_driver_data *n_spi;
+       u8 *inp_buf;
+       u8 *outp_buf;
+       int i, write_length;
+       int block_counter = 0;
+       if (context == NULL) {
+               return 0;
+       }
+       spi = context;
+       n_spi = spi_get_drvdata(spi);
+       if (n_spi == NULL) {
+               return 0;
+       }
+       for (i = 0; i < (reg_size / 2); i++) {
+               // Check for continuity and read the largest possible continuous block
+               if (block_counter == ((reg_size / 2) - 1) || ((mb_reg_buf[i] + 1) != mb_reg_buf[i + 1])) {
+                       write_length = neuronspi_spi_compose_multiple_register_read(block_counter + 1, mb_reg_buf[i - block_counter], &inp_buf, &outp_buf);
+                       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 125, 1);
+                       memcpy(&mb_val_buf[i - block_counter], &outp_buf[NEURONSPI_HEADER_LENGTH], (block_counter + 1) * 2);
+                       kfree(inp_buf);
+                       kfree(outp_buf);
+                       block_counter = 0;
+               } else {
+                       block_counter++;
+               }
+       }
+       printk(KERN_INFO "NEURONSPI: RM_READ %d %x %d %x\n", reg_size, mb_reg_buf[0], val_size, mb_val_buf[0]);
+       return 0;
+}
+
+s32 neuronspi_find_model_id(u32 probe_count)
+{
+       struct neuronspi_driver_data *n_spi;
+       int i,j, ret = -1;
+       u8 *inv = kzalloc(sizeof(*inv) * NEURONSPI_MODELTABLE_LEN, GFP_KERNEL);
+       for (i = 0; i < probe_count; i++) {
+               if (neuronspi_s_dev[i]) {
+                       n_spi = spi_get_drvdata(neuronspi_s_dev[i]);
+                       for (j = 0; j < NEURONSPI_MODELTABLE_LEN; j++) {
+                               if (i + 1 > NEURONSPI_MODELTABLE[j].combination_count) {
+                                       inv[j] = 1;
+                               } else if (NEURONSPI_MODELTABLE[j].combinations[i].combination_board_id != n_spi->combination_id) {
+                                       inv[j] = 1;
+                               }
+                       }
+               } else {
+                       for (j = 0; j < NEURONSPI_MODELTABLE_LEN; j++) {
+                               if (i + 1 < NEURONSPI_MODELTABLE[j].combination_count) {
+                                       inv[j] = 1;
+                               }
+                       }
+               }
+       }
+       for (i = 0; i < NEURONSPI_MODELTABLE_LEN; i++) {
+               if (inv[i] != 1) {
+                       ret = i;
+                       break;
+               }
+       }
+       kfree(inv);
+       return ret;
+}
+
+
diff --git a/modules/unipi/src/unipi_platform.h b/modules/unipi/src/unipi_platform.h
new file mode 100644 (file)
index 0000000..8178ebb
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_PLATFORM_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_PLATFORM_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+#include <uapi/linux/iio/types.h>
+
+#include "unipi_common.h"
+
+/*******************
+ * Data Structures *
+ *******************/
+
+struct neuronspi_board_entry {
+       u16             index;
+       u16             lower_board_id;
+       u16             upper_board_id;
+       u16             data_register_count;
+       u16             config_register_count;
+       struct neuronspi_board_combination *definition;
+};
+
+struct neuronspi_register_block
+{
+       u32     starting_register;
+       u32     register_count;
+       u32             *register_flags;
+};
+
+struct neuronspi_board_features
+{
+       u32             do_count;
+       u32             ro_count;
+       u32             ds_count;
+       u32             di_count;
+       u32             led_count;
+       u32             stm_ai_count;
+       u32             stm_ao_count;
+       u32             sec_ai_count;
+       u32             sec_ao_count;
+       u32             uart_master_count;
+       u32             uart_slave_count;
+       u32             pwm_channel_count;
+       u32             wd_count;
+       u32             extension_sys_count;
+       u32             light_count;
+       u32             owire_count;
+};
+
+struct neuronspi_board_regstart_table
+{
+       u32             do_val_reg;
+       u32             do_val_coil;
+       u32             do_pwm_reg;
+       u32             do_pwm_ps_reg;
+       u32             do_pwm_c_reg;
+       u32             di_val_reg;
+       u32             di_counter_reg;
+       u32             di_direct_reg;
+       u32             di_deboun_reg;
+       u32             di_polar_reg;
+       u32             di_toggle_reg;
+       u32             uart_queue_reg;
+       u32             uart_conf_reg;
+       u32             uart_address_reg;
+       u32             led_val_coil;
+       u32             led_val_reg;
+       u32             wd_val_reg;
+       u32             wd_timeout_reg;
+       u32             wd_nv_sav_coil;
+       u32             wd_reset_coil;
+       u32             reg_start_reg;
+       u32             ro_val_reg;
+       u32             ro_val_coil;
+       u32             vref_inp;
+       u32             vref_int;
+       u32             stm_ao_val_reg;
+       u32             stm_ao_mode_reg;
+       u32             stm_ao_vol_err;
+       u32             stm_ao_vol_off;
+       u32             stm_ao_curr_err;
+       u32             stm_ao_curr_off;
+       u32             stm_ai_val_reg;
+       u32             stm_ai_mode_reg;
+       u32             stm_ai_curr_err;
+       u32             stm_ai_curr_off;
+       u32             stm_ai_vol_err;
+       u32             stm_ai_vol_off;
+       u32             stm_aio_val_reg;
+       u32             stm_aio_vol_err;
+       u32             stm_aio_vol_off;
+       u32             sec_ao_val_reg;
+       u32             sec_ao_mode_reg;
+       u32             sec_ai_val_reg;
+       u32             sec_ai_mode_reg;
+       u32             sys_serial_num;
+       u32             sys_hw_ver;
+       u32             sys_hw_flash_ver;
+       u32             sys_sw_ver;
+};
+
+struct neuronspi_board_combination
+{
+       u32                                                                     combination_board_id;
+       u16                                                                     lower_board_id;
+       u16                                                                     upper_board_id;
+       u32                                                             block_count;
+       size_t                                                          name_length;
+       const char*                                                     combination_name;
+       struct neuronspi_board_features         features;
+       u32                                                                     *blocks;
+};
+
+struct neuronspi_model_definition
+{
+       size_t                                                          eeprom_length;
+       const char*                                             eeprom_name;
+       size_t                                                          name_length;
+       const char*                                                     model_name;
+       u32                                                                     combination_count;
+       struct neuronspi_board_combination      *combinations;
+};
+
+/***************
+ * Definitions *
+ ***************/
+
+// Lower Boards
+#define NEURONSPI_BOARD_LOWER_B1000_ID         0
+#define NEURONSPI_BOARD_LOWER_E8DI8RO_ID       1
+#define NEURONSPI_BOARD_LOWER_E14RO_ID         2
+#define NEURONSPI_BOARD_LOWER_E16DI_ID         3
+#define NEURONSPI_BOARD_LOWER_E4AI4AO_ID       11
+#define NEURONSPI_BOARD_LOWER_B485_ID          13
+#define NEURONSPI_BOARD_LOWER_E4LIGHT_ID       14
+
+// Upper Boards
+#define NEURONSPI_BOARD_UPPER_NONE_ID          0
+#define NEURONSPI_BOARD_UPPER_P11DIR485_ID     1
+#define NEURONSPI_BOARD_UPPER_U14RO_ID         2
+#define NEURONSPI_BOARD_UPPER_U14DI_ID         3
+#define NEURONSPI_BOARD_UPPER_P6DI5RO_ID       4
+#define NEURONSPI_BOARD_UPPER_U6DI5RO_ID       5
+
+// Register function codes
+// Digital Input Functions
+#define NEURONSPI_FUNGROUP_DI                                  0
+#define NEURONSPI_REGFUN_DI_READ                       0 | NEURONSPI_FUNGROUP_DI << 8
+#define NEURONSPI_REGFUN_DI_COUNTER_LOWER      1 | NEURONSPI_FUNGROUP_DI << 8
+#define NEURONSPI_REGFUN_DI_COUNTER_UPPER      2 | NEURONSPI_FUNGROUP_DI << 8
+#define NEURONSPI_REGFUN_DI_DEBOUNCE           3 | NEURONSPI_FUNGROUP_DI << 8
+#define NEURONSPI_REGFUN_DS_ENABLE                     4 | NEURONSPI_FUNGROUP_DI << 8
+#define NEURONSPI_REGFUN_DS_POLARITY           5 | NEURONSPI_FUNGROUP_DI << 8
+#define NEURONSPI_REGFUN_DS_TOGGLE                     6 | NEURONSPI_FUNGROUP_DI << 8
+
+// Digital Output Functions
+#define NEURONSPI_FUNGROUP_DO                                  1
+#define NEURONSPI_REGFUN_DO_RW                         0 | NEURONSPI_FUNGROUP_DO << 8
+
+// B1000 Analog Output Functions
+#define NEURONSPI_FUNGROUP_AO_BRAIN                            2
+#define NEURONSPI_REGFUN_AO_BRAIN                      0 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
+#define NEURONSPI_REGFUN_AO_BRAIN_MODE         1 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
+#define NEURONSPI_REGFUN_AO_BRAIN_V_ERR                2 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
+#define NEURONSPI_REGFUN_AO_BRAIN_V_OFF                3 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
+#define NEURONSPI_REGFUN_AO_BRAIN_I_ERR        4 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
+#define NEURONSPI_REGFUN_AO_BRAIN_I_OFF        5 | NEURONSPI_FUNGROUP_AO_BRAIN << 8
+
+// B1000 Analog Input Functions
+#define NEURONSPI_FUNGROUP_AI_BRAIN                            3
+#define NEURONSPI_REGFUN_AI_BRAIN                      0 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AIO_BRAIN                     1 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AI_BRAIN_MODE         2 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AI_BRAIN_V_ERR                3 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AI_BRAIN_V_OFF                4 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AI_BRAIN_I_ERR                5 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AI_BRAIN_I_OFF                6 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AIO_BRAIN_ERR         7 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+#define NEURONSPI_REGFUN_AIO_BRAIN_OFF         8 | NEURONSPI_FUNGROUP_AI_BRAIN << 8
+
+// System Functions
+#define NEURONSPI_FUNGROUP_SYSTEM                              4
+#define NEURONSPI_REGFUN_V_REF_INT                     0 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_V_REF_INP                     1 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_LED_RW                                2 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_SW_VER                        3 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_DIDO_COUNT                    4 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_UAIO_COUNT                    5 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_HW_VER                                6 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_FLASH_HW_VER          7 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_SERIAL_NR_LOWER       8 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_SERIAL_NR_UPPER       9 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_INTERRUPTS                    10 | NEURONSPI_FUNGROUP_SYSTEM << 8
+#define NEURONSPI_REGFUN_NONE_TEST                     11 | NEURONSPI_FUNGROUP_SYSTEM << 8
+
+// Watchdog Functions
+#define NEURONSPI_FUNGROUP_MWD                                 5
+#define NEURONSPI_REGFUN_MWD_TO                                0 | NEURONSPI_FUNGROUP_MWD << 8
+#define NEURONSPI_REGFUN_MWD_STATUS                    1 | NEURONSPI_FUNGROUP_MWD << 8
+
+// PWM Functions
+#define NEURONSPI_FUNGROUP_PWM                                 6
+#define NEURONSPI_REGFUN_PWM_DUTY                      0 | NEURONSPI_FUNGROUP_PWM << 8
+#define NEURONSPI_REGFUN_PWM_PRESCALE          1 | NEURONSPI_FUNGROUP_PWM << 8
+#define NEURONSPI_REGFUN_PWM_CYCLE                     2 | NEURONSPI_FUNGROUP_PWM << 8
+
+// UART Functions
+#define NEURONSPI_FUNGROUP_RS485                               7
+#define NEURONSPI_REGFUN_TX_QUEUE_LEN          0 | NEURONSPI_FUNGROUP_RS485 << 8
+#define NEURONSPI_REGFUN_RS485_CONFIG          1 | NEURONSPI_FUNGROUP_RS485 << 8
+#define NEURONSPI_REGFUN_RS485_ADDRESS         2 | NEURONSPI_FUNGROUP_RS485 << 8
+
+// Secondary Analog Output Functions
+#define NEURONSPI_FUNGROUP_AO_VER2                             8
+#define NEURONSPI_REGFUN_AO_VER2_RW                    0 | NEURONSPI_FUNGROUP_AO_VER2 << 8
+
+// Secondary Analog Input Functions
+#define NEURONSPI_FUNGROUP_AI_VER2                             9
+#define NEURONSPI_REGFUN_AI_VER2_READ_LOWER    0 | NEURONSPI_FUNGROUP_AI_VER2 << 8
+#define NEURONSPI_REGFUN_AI_VER2_READ_UPPER    0 | NEURONSPI_FUNGROUP_AI_VER2 << 8
+#define NEURONSPI_REGFUN_AI_VER2_MODE          1 | NEURONSPI_FUNGROUP_AI_VER2 << 8
+
+// Register access flags
+#define NEURONSPI_REGFLAG_ACC_NEVER    0
+#define NEURONSPI_REGFLAG_ACC_AFAP     0x1 << 16
+#define NEURONSPI_REGFLAG_ACC_10HZ     0x2 << 16
+#define NEURONSPI_REGFLAG_ACC_1HZ   0x3 << 16
+#define NEURONSPI_REGFLAG_ACC_6SEC  0x4 << 16
+#define NEURONSPI_REGFLAG_ACC_1MIN  0x5 << 16
+#define NEURONSPI_REGFLAG_ACC_15MIN 0x6 << 16
+#define NEURONSPI_REGFLAG_ACC_ONCE     0x7 << 16
+
+// Register system flags
+#define NEURONSPI_REGFLAG_SYS_READ_ONLY        0x10 << 24
+
+// IIO Modes
+#define NEURONSPI_IIO_AI_STM_MODE_VOLTAGE 0x0
+#define NEURONSPI_IIO_AI_STM_MODE_CURRENT 0x1
+#define NEURONSPI_IIO_AI_STM_MODE_RESISTANCE 0x3
+
+/*********************
+ * Data Declarations *
+ *********************/
+
+extern struct platform_device *neuron_plc_dev;
+
+// Board Definitions
+extern struct neuronspi_board_combination NEURONSPI_BOARD_B1000_HW_COMBINATION[];                              // B_1000 (S103)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8RO_HW_COMBINATION[];                    // E-8Di8Ro (M103)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E14RO_HW_COMBINATION[];                              // E-14Ro
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DI_HW_COMBINATION[];                              // E-16Di
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E8DI8ROP11DIR485_HW_COMBINATION[];   // E-8Di8Ro_P-11DiR485 (xS10)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E14ROP11DIR485_HW_COMBINATION[];             // E-14Ro_P-11DiR485 (xS40)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DIP11DIR485_HW_COMBINATION[];             // E-16Di_P-11DiR485 (xS30)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14RO_HW_COMBINATION[];                 // E-14Ro_U-14Ro (M403)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14RO_HW_COMBINATION[];                 // E-16Di_U-14Ro (M203)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E14ROU14DI_HW_COMBINATION[];                 // E-14Ro_U-14Di (L503)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E16DIU14DI_HW_COMBINATION[];                 // E-16Di_U-14Di (M303)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AO_HW_COMBINATION[];                            // E-4Ai4Ao
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMBINATION[];             // E-4Ai4Ao_P-6Di5Ro (xS50)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_B485_HW_COMBINATION[];                               // B-485
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E4LIGHT_HW_COMBINATION[];                            // E-4Light (M613)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION[];             // E-4Ai4Ao_U-6Di5Ro (L503)
+
+// Model Definitions
+#define NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE 1
+extern struct neuronspi_board_combination NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD_SIZE 1
+extern struct neuronspi_board_combination NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103G_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD_SIZE 1
+extern struct neuronspi_board_combination NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103IQ_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD_SIZE 1
+extern struct neuronspi_board_combination NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD[NEURONSPI_MODEL_S103EO_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD_SIZE 2
+extern struct neuronspi_board_combination NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M103_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD_SIZE 2
+extern struct neuronspi_board_combination NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M203_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD_SIZE 2
+extern struct neuronspi_board_combination NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M303_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD_SIZE 2
+extern struct neuronspi_board_combination NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M403_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD_SIZE 2
+extern struct neuronspi_board_combination NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M503_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD_SIZE 2
+extern struct neuronspi_board_combination NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD[NEURONSPI_MODEL_M603_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD_SIZE 3
+extern struct neuronspi_board_combination NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L203_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD_SIZE 3
+extern struct neuronspi_board_combination NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L303_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD_SIZE 3
+extern struct neuronspi_board_combination NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L403_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD_SIZE 3
+extern struct neuronspi_board_combination NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L503_HW_DEFINITION_BOARD_SIZE];
+#define NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD_SIZE 3
+extern struct neuronspi_board_combination NEURONSPI_MODEL_L513_HW_DEFINITION_BOARD[];
+
+// Board table
+#define NEURONSPI_BOARDTABLE_LEN               16
+extern struct neuronspi_board_entry NEURONSPI_BOARDTABLE[];
+
+// Module table
+#define NEURONSPI_MODELTABLE_LEN               15
+extern struct neuronspi_model_definition NEURONSPI_MODELTABLE[];
+
+/*************************
+ * Function Declarations *
+ *************************/
+
+int neuronspi_regmap_hw_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size);
+int neuronspi_regmap_hw_read(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size);
+int neuronspi_regmap_hw_reg_read(void *context, unsigned int reg, unsigned int *val);
+int neuronspi_regmap_hw_reg_write(void *context, unsigned int reg, unsigned int val);
+int neuronspi_regmap_hw_write(void *context, const void *data, size_t count);
+void neuronspi_regmap_invalidate_device(struct regmap *reg_map, struct neuronspi_board_combination *device_def, u32 period_counter);
+s32 neuronspi_regmap_invalidate(void *data);
+int neuronspi_create_reg_starts(struct neuronspi_board_regstart_table *out_table, struct neuronspi_board_combination *board);
+s32 neuronspi_find_reg_start(struct neuronspi_board_combination *board, u16 regfun);
+s32 neuronspi_find_model_id(u32 probe_count);
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_PLATFORM_H_ */
diff --git a/modules/unipi/src/unipi_spi.c b/modules/unipi/src/unipi_spi.c
new file mode 100644 (file)
index 0000000..d58c5c4
--- /dev/null
@@ -0,0 +1,1587 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2017 UniPi Tech
+nologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/************
+ * Includes *
+ ************/
+
+#include "unipi_common.h"
+#include "unipi_sysfs.h"
+#include "unipi_uart.h"
+#include "unipi_platform.h"
+#include "unipi_gpio.h"
+#include "unipi_iio.h"
+#include "unipi_misc.h"
+#include "unipi_spi.h"
+
+/********************
+ * Data Definitions *
+ ********************/
+
+MODULE_DEVICE_TABLE(of, neuronspi_id_match);
+
+struct spi_driver neuronspi_spi_driver =
+{
+       .driver =
+       {
+               .name                   = NEURON_DRIVER_NAME,
+               .of_match_table = of_match_ptr(neuronspi_id_match)
+       },
+       .probe                          = neuronspi_spi_probe,
+       .remove                         = neuronspi_spi_remove,
+};
+
+struct file_operations file_ops =
+{
+       .open                           = neuronspi_open,
+       .read                           = neuronspi_read,
+       .write                          = neuronspi_write,
+       .release                        = neuronspi_release,
+       .owner                          = THIS_MODULE
+};
+
+struct neuronspi_char_driver neuronspi_cdrv =
+{
+       .dev = NULL
+};
+
+struct mutex neuronspi_master_mutex;
+struct spinlock* neuronspi_spi_w_spinlock;
+u8 neuronspi_spi_w_flag = 1;
+u8 neuronspi_probe_count = 0;
+int neuronspi_model_id = -1;
+spinlock_t neuronspi_probe_spinlock;
+struct spi_device* neuronspi_s_dev[NEURONSPI_MAX_DEVS];
+struct task_struct *neuronspi_invalidate_thread;
+
+/************************
+ * Non-static Functions *
+ ************************/
+
+int neuronspi_open (struct inode *inode_p, struct file *file_p)
+{
+       struct neuronspi_file_data *f_internal_data;
+       if (neuronspi_s_dev == NULL || file_p == NULL || inode_p == NULL) {
+               return -1;
+       }
+       neuronspi_cdrv.open_counter += 1;
+       f_internal_data = kzalloc(sizeof(*f_internal_data), GFP_KERNEL);
+       f_internal_data->recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
+       f_internal_data->send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
+       f_internal_data->spi_device = neuronspi_s_dev;
+       mutex_init(&f_internal_data->lock);
+       file_p->private_data = f_internal_data;
+       return 0;
+}
+
+int neuronspi_release (struct inode *inode_p, struct file *file_p)
+{
+       struct neuronspi_file_data *f_internal_data;
+       if (file_p == NULL) {
+               return -1;
+       }
+       f_internal_data = (struct neuronspi_file_data*)file_p->private_data;
+       f_internal_data->spi_device = NULL;
+       kfree(f_internal_data->recv_buf);
+       f_internal_data->recv_buf = NULL;
+       kfree(f_internal_data->send_buf);
+       f_internal_data->send_buf = NULL;
+       kfree(f_internal_data);
+       file_p->private_data = NULL;
+       neuronspi_cdrv.open_counter -= 1;
+       return 0;
+}
+
+ssize_t neuronspi_read (struct file *file_p, char *buffer, size_t len, loff_t *offset)
+{
+
+       s32 result = 0;
+       u8 device_index = 0;
+       u32 frequency = NEURONSPI_COMMON_FREQ;
+       struct neuronspi_file_data* private_data;
+       struct spi_device* spi_driver_data;
+       struct neuronspi_driver_data* driver_data;
+       // Sanity checking
+       if (neuronspi_cdrv.open_counter == 0) {
+               neuronspi_cdrv.open_counter = 1;
+       }
+       if (buffer == NULL) return -7; // Invalid read buffer
+    if (len == 0) return result; // Empty read
+    if (len > 4095) return -EMSGSIZE;
+    if (file_p == NULL) {
+       printk(KERN_DEBUG "NEURONSPI: File Pointer is NULL\n");
+       return -8;
+    }
+    if (file_p->private_data == NULL) {
+       printk(KERN_DEBUG "NEURONSPI: No Private Data\n");
+       return -1;      // No private data
+    }
+    private_data = (struct neuronspi_file_data*) file_p->private_data;
+    if (private_data == NULL) return -4;
+    device_index = private_data->send_buf[0];
+    spi_driver_data = private_data->spi_device[device_index];  // Get private (driver) data from FP
+    if (spi_driver_data == NULL) return -2;
+    driver_data = spi_get_drvdata(spi_driver_data);
+    if (driver_data == NULL) return -2;
+    if (driver_data->spi_driver == NULL) return -2;    // Invalid private data
+    if (driver_data->first_probe_reply[0] == 0) return -3; // No device present
+    if (driver_data->slower_model) {
+       frequency = NEURONSPI_SLOWER_FREQ;
+    }
+    mutex_lock(&(private_data->lock));
+    if (private_data->recv_buf == NULL) {
+       mutex_unlock(&(private_data->lock));
+       return -10;
+    }
+#if NEURONSPI_DETAILED_DEBUG > 0
+    printk(KERN_INFO "NEURONSPI: Device read %d DEV:%s%d DRV:%s%d\n", private_data->message_len, (spi_driver_data->dev.of_node->name),
+               (spi_driver_data->chip_select), (driver_data->spi_driver->driver.name), (device_index));
+#endif
+    if ((((s32)len) == private_data->message_len + 10)) {
+       memcpy(buffer, private_data->recv_buf, len);
+       result = len;
+    } else if (private_data->message_len == 0) {
+       mutex_unlock(&(private_data->lock));
+       return -9;
+    } else if (len <= private_data->message_len) {
+       result = simple_read_from_buffer(buffer, len, offset, private_data->recv_buf, len);
+    } else {
+       mutex_unlock(&(private_data->lock));
+       return -9;
+    }
+    memset(private_data->recv_buf, 0, NEURONSPI_BUFFER_MAX);
+       mutex_unlock(&(private_data->lock));
+       return result;
+}
+
+
+
+ssize_t neuronspi_write (struct file *file_p, const char *buffer, size_t len, loff_t *w_offset)
+{
+       u8 device_index = 0;
+       s32 result = 0;
+       u32 frequency = NEURONSPI_COMMON_FREQ;
+       s32 transmit_len = len - NEURONSPI_HEADER_LENGTH;
+       s32 send_header = 0;
+       s32 delay = 25;
+       struct neuronspi_file_data* private_data;
+       struct spi_device* spi_driver_data;
+       struct neuronspi_driver_data* driver_data;
+       // Sanity checking
+       if (neuronspi_cdrv.open_counter == 0) {
+               neuronspi_cdrv.open_counter = 1;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: LENGTH:%d\n", len);
+#endif
+       if (buffer == NULL) {
+               return 0; // Void write
+       }
+    if (len == 0) {
+       return result; // Empty write
+    }
+    if (len > 4095) return -EMSGSIZE;
+    if (file_p == NULL) {
+       return -12;
+    }
+    if (file_p->private_data == NULL) {
+       printk(KERN_DEBUG "NEURONSPI: No Private Data\n");
+       return -1;      // No private data
+    }
+    // Read packet header and initialise private data (dependent on each other)
+    device_index = buffer[0];
+    if (device_index > NEURONSPI_MAX_DEVS - 1) return -2;
+    private_data = (struct neuronspi_file_data*) file_p->private_data;
+    spi_driver_data = private_data->spi_device[device_index];  // Get private (driver) data from FP
+    if (spi_driver_data == NULL) return -2;
+    driver_data = spi_get_drvdata(spi_driver_data);
+    if (driver_data == NULL) return -2;
+    if (driver_data->spi_driver == NULL) return -2;    // Invalid private data
+    if (driver_data->first_probe_reply[0] == 0) return -3; // Device not present
+    send_header = buffer[3];
+    if (buffer[4]) {   // Frequency setting
+       frequency = (buffer[4] << 8 | buffer[5]) * 1000;
+    }
+    if (buffer[6]) {   // Delay setting
+       delay = buffer[6];
+    }
+    if (buffer[7]) {   // Device reservation
+       if (buffer[7] == 255) { // Unlock device
+               driver_data->reserved_device = 0;
+       } else if ((driver_data->reserved_device) && buffer[7] != driver_data->reserved_device) {
+               return -4;                              // Another device reserved
+       } else if (!driver_data->reserved_device) {
+               driver_data->reserved_device = buffer[7];       // Reserve the device
+       }
+#ifdef STRICT_RESERVING
+    } else if (driver_data->reserved_device) {
+       return -5;                      // Device reserved
+    }
+    if (driver_data->slower_model) {
+       frequency = NEURONSPI_SLOWER_FREQ;
+    }
+#else
+       } else if (device_index == (driver_data->reserved_device - 1)) {
+               return -5;                      // Device reserved
+       }
+       if (driver_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+#endif
+    mutex_lock(&(private_data->lock));
+    memset(private_data->send_buf, 0, NEURONSPI_BUFFER_MAX );
+    memcpy(private_data->send_buf, buffer, len);
+    memset(private_data->recv_buf, 0, NEURONSPI_BUFFER_MAX );
+    private_data->message_len = transmit_len;
+    spin_lock(neuronspi_spi_w_spinlock);
+    neuronspi_spi_w_flag = 1;
+    spin_unlock(neuronspi_spi_w_spinlock);
+    neuronspi_spi_send_message(spi_driver_data, &private_data->send_buf[NEURONSPI_HEADER_LENGTH], private_data->recv_buf,
+               transmit_len, frequency, delay, send_header);
+    mutex_unlock(&private_data->lock);
+    return len;
+}
+
+s32 neuronspi_spi_uart_write(struct spi_device *spi, u8 *send_buf, u8 length, u8 uart_index)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       s32 transmit_len, i;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+       u16 crc1, crc2;
+       u32 frequency = NEURONSPI_COMMON_FREQ;
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: UART SPI Write, dev:%d, len:%d\n", uart_index, length);
+#endif
+       if (length == 0) {
+               return -1;
+       }
+       if (length == 1) {
+               transmit_len = 6;
+               message_buf = kzalloc(transmit_len, GFP_KERNEL);
+               memcpy(message_buf, NEURONSPI_SPI_UART_SHORT_MESSAGE, NEURONSPI_SPI_UART_SHORT_MESSAGE_LEN);
+               message_buf[1] = send_buf[0];
+               message_buf[3] = uart_index;
+               crc1 = neuronspi_spi_crc(message_buf, 4, 0);
+               memcpy(&message_buf[4], &crc1, 2);
+       } else {
+               transmit_len = 6 + length + 2;
+               message_buf = kzalloc(transmit_len, GFP_KERNEL);
+               memcpy(message_buf, NEURONSPI_SPI_UART_LONG_MESSAGE, NEURONSPI_SPI_UART_LONG_MESSAGE_LEN);
+               message_buf[1] = length;
+               message_buf[3] = uart_index;
+               crc1 = neuronspi_spi_crc(message_buf, 4, 0);
+               memcpy(&message_buf[4], &crc1, 2);
+               for (i = 0; i < length; i++) {
+                       message_buf[6 + i] = send_buf[i];
+               }
+               crc2 = neuronspi_spi_crc(&message_buf[6], length, crc1);
+               memcpy(&message_buf[6+length], &crc2, 2);
+       }
+       recv_buf = kzalloc(transmit_len, GFP_KERNEL);
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi, message_buf, recv_buf, transmit_len, frequency, 65, 1);
+       }
+       kfree(message_buf);
+       kfree(recv_buf);
+       return 0;
+}
+
+
+void neuronspi_spi_uart_read(struct spi_device* spi, u8 *send_buf, u8 *recv_buf, s32 len, u8 uart_index)
+{
+       s32 transmit_len;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+       u16 crc1, crc2;
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: UART SPI Read, cs:%d, len:%d\n", uart_index, len);
+#endif
+       if (len <= 2) {
+               memcpy(send_buf, NEURONSPI_SPI_UART_READ_MESSAGE, NEURONSPI_SPI_UART_READ_MESSAGE_LEN);
+               transmit_len = NEURONSPI_SPI_UART_READ_MESSAGE_LEN;
+       } else {
+               memcpy(send_buf, NEURONSPI_SPI_UART_READ_MESSAGE, NEURONSPI_SPI_UART_READ_MESSAGE_LEN);
+               if (len < 100) {
+                       len = (len * 2) + 1;
+               } else {
+                       len = 201;
+               }
+               transmit_len = 5 + len + 6;     // Header (-1 for the byte there) + 4 bytes in second part + 2 bytes of CRC
+               send_buf[1] = len + 3;  // Length of second part (len + 4 - 1)
+
+               crc1 = neuronspi_spi_crc(send_buf, 4, 0);
+               memcpy(&send_buf[4], &crc1, 2);
+               send_buf[7] = len;
+               crc2 = neuronspi_spi_crc(&send_buf[6], len + 3, crc1);
+               memcpy(&send_buf[len + 9], &crc2, 2);
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_INFO "NEURONSPI: UART Device Read len:%d %100ph\n", transmit_len, send_buf);
+#endif
+       }
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi, send_buf, recv_buf, transmit_len, frequency, 65, 1);
+       }
+}
+
+void neuronspi_spi_set_irqs(struct spi_device* spi_dev, u16 to)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       u16 crc1, crc2;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: SPI IRQ Set, Dev-CS:%d, to:%d\n", spi_dev->chip_select, to);
+#endif
+       message_buf = kzalloc(NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN, GFP_KERNEL);
+       recv_buf = kzalloc(NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN, GFP_KERNEL);
+       memcpy(message_buf, NEURONSPI_SPI_IRQ_SET_MESSAGE, NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN);
+       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
+       memcpy(&message_buf[4], &crc1, 2);
+       crc2 = neuronspi_spi_crc(&message_buf[6], NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN - 8, crc1);
+       memcpy(&message_buf[NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN - 2], &crc2, 2);
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN, frequency, 65, 1);
+       }
+       kfree(message_buf);
+       kfree(recv_buf);
+}
+
+void neuronspi_spi_uart_set_cflag(struct spi_device* spi_dev, u8 port, u32 to)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       u16 crc1, crc2;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: SPI TERMIOS Set, Dev-CS:%d, to:%x\n", spi_dev->chip_select, to);
+#endif
+       message_buf = kzalloc(NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
+       recv_buf = kzalloc(NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
+       memcpy(message_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN);
+       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
+       memcpy(&message_buf[4], &crc1, 2);
+       memcpy(&message_buf[10], &to, 4);
+       crc2 = neuronspi_spi_crc(&message_buf[6], NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN - 8, crc1);
+       memcpy(&message_buf[NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN - 2], &crc2, 2);
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, frequency, 65, 1);
+       }
+       kfree(message_buf);
+       kfree(recv_buf);
+}
+
+void neuronspi_spi_uart_set_ldisc(struct spi_device* spi_dev, u8 port, u8 to)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 1
+       printk(KERN_INFO "NEURONSPI: SPI TERMIOS Set, Dev-CS:%d, to:%x\n", spi_dev->chip_select, to);
+#endif
+       neuronspi_spi_compose_single_register_write(503, &message_buf, &recv_buf, to);
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, frequency, 35, 1);
+       }
+       kfree(message_buf);
+       kfree(recv_buf);
+}
+
+u8 neuronspi_spi_uart_get_ldisc(struct spi_device* spi_dev, u8 port)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       u8 outp;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+       neuronspi_spi_compose_single_register_read(503, &message_buf, &recv_buf);
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN, frequency, 35, 1);
+       }
+       outp = recv_buf[MODBUS_FIRST_DATA_BYTE + 1];
+#if NEURONSPI_DETAILED_DEBUG > 1
+       printk(KERN_INFO "NEURONSPI: SPI TERMIOS GET, Dev-CS:%d, to:%x\n", spi_dev->chip_select, outp);
+#endif
+       kfree(message_buf);
+       kfree(recv_buf);
+       return outp;
+}
+
+
+/*
+ * NOTE: This function uses 64-bit fixed-point arithmetic,
+ * which necessitates using the do_div macro to avoid unnecessary long/long division.
+ */
+void neuronspi_spi_iio_sec_ai_read_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 sec_ai_val_l = 0;
+       u32 sec_ai_val_h = 0;
+       u32 sec_ai_val_m = 0;
+       u8 sec_ai_exp = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &sec_ai_val_h);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + 1 + (2 * ai_data->index), &sec_ai_val_l);
+       sec_ai_val_m = ((((u32)sec_ai_val_h) << 25) | (((u32)sec_ai_val_l) << 9)) >> 16;
+       sec_ai_exp = (sec_ai_val_h & 0x7F80) >> 7;
+       *val = sec_ai_val_m | 0x00010000;
+       if (142 - ((int)sec_ai_exp) <= 0) {
+               *val = (*val << (((int)sec_ai_exp) - 142)) * 1000;
+               *val2 = 1;
+       } else {
+               *val = *val * 1000;
+               *val2 = 2 << (142 - sec_ai_exp);
+       }
+
+}
+
+void neuronspi_spi_iio_sec_ai_read_current(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 sec_ai_val_l = 0;
+       u32 sec_ai_val_h = 0;
+       u32 sec_ai_val_m = 0;
+       u8 sec_ai_exp = 0;
+
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &sec_ai_val_h);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + 1 + (2 * ai_data->index), &sec_ai_val_l);
+       sec_ai_val_m = ((((u32)sec_ai_val_h) << 25) | (((u32)sec_ai_val_l) << 9)) >> 16;
+       sec_ai_exp = (sec_ai_val_h & 0x7F80) >> 7;
+       *val = sec_ai_val_m | 0x00010000;
+       if (142 - ((int)sec_ai_exp) <= 0) {
+               *val2 = 1;
+               *val = *val << (((int)sec_ai_exp) - 142);
+       } else {
+               *val2 = 2 << (142 - sec_ai_exp);
+       }
+}
+
+void neuronspi_spi_iio_sec_ai_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 sec_ai_val_l = 0;
+       u32 sec_ai_val_h = 0;
+       u32 sec_ai_val_m = 0;
+       u8 sec_ai_exp = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &sec_ai_val_h);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + 1 + (2 * ai_data->index), &sec_ai_val_l);
+       sec_ai_val_m = ((((u32)sec_ai_val_h) << 25) | (((u32)sec_ai_val_l) << 9)) >> 16;
+       sec_ai_exp = (sec_ai_val_h & 0x7F80) >> 7;
+       *val = sec_ai_val_m | 0x00010000;
+       if (142 - ((int)sec_ai_exp) <= 0) {
+               *val2 = 1;
+               *val = *val << (((int)sec_ai_exp) - 142);
+       } else {
+               *val2 = 2 << (142 - sec_ai_exp);
+       }
+}
+
+void neuronspi_spi_iio_sec_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+       struct neuronspi_sec_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 sec_true_val = (val * 2) / 5;
+       if (val > 10000) val = 10000;
+       regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_val_reg + ao_data->index, sec_true_val);
+}
+
+/*
+ * NOTE: This function uses 64-bit fixed-point arithmetic,
+ * which necessitates using the do_div macro to avoid unnecessary long/long division.
+ */
+void neuronspi_spi_iio_stm_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_stm_ai_data *ai_data = iio_priv(iio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 stm_ai_val = 0;
+       u32 stm_v_int_ref = 0;
+       u32 stm_v_inp_ref = 0;
+       u32 stm_v_err = 0;
+       u32 stm_v_off = 0;
+       u64 stm_true_val = 0;
+       u64 stm_true_ref = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_val_reg, &stm_ai_val);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_vol_err, &stm_v_err);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_vol_off, &stm_v_off);
+       stm_true_ref = ((u64)stm_v_int_ref) * 99000;
+       stm_v_inp_ref = stm_v_inp_ref * 10000;
+       stm_true_val = stm_true_ref * ((u64)(stm_ai_val * 1000));
+       do_div(stm_true_val, stm_v_inp_ref);
+       do_div(stm_true_val, 4096);
+       stm_true_val *= (10000 + stm_v_err);
+       stm_true_val += stm_v_off;
+       do_div(stm_true_val, 10000);
+       *val = stm_true_val;
+}
+
+void neuronspi_spi_iio_stm_ai_read_current(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 stm_ai_val = 0;
+       u32 stm_v_int_ref = 0;
+       u32 stm_v_inp_ref = 0;
+       u32 stm_i_err = 0;
+       u32 stm_i_off = 0;
+       u64 stm_true_val = 0;
+       u64 stm_true_ref = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_val_reg, &stm_ai_val);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_curr_err, &stm_i_err);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_curr_off, &stm_i_off);
+       stm_true_ref = ((u64)stm_v_int_ref) * 330000;
+       stm_v_inp_ref = stm_v_inp_ref * 10000;
+       stm_true_val = stm_true_ref * ((u64)(stm_ai_val * 1000));
+       do_div(stm_true_val, stm_v_inp_ref);
+       do_div(stm_true_val, 4096);
+       stm_true_val *= (10000 + stm_i_err);
+       stm_true_val += stm_i_off;
+       do_div(stm_true_val, 10000);
+       *val = stm_true_val;
+}
+
+void neuronspi_spi_iio_stm_ao_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask)
+{
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 stm_aio_val = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_aio_val_reg, &stm_aio_val);
+       *val = stm_aio_val;
+}
+
+
+void neuronspi_spi_iio_stm_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 stm_v_int_ref = 0;
+       u32 stm_v_inp_ref = 0;
+       u32 stm_v_err = 0;
+       u32 stm_v_off = 0;
+       u64 stm_true_val = val;
+       u64 stm_true_ref = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_vol_err, &stm_v_err);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_vol_off, &stm_v_off);
+       stm_true_ref = ((u64)stm_v_int_ref) * (99000 + stm_v_err) * 1000;
+       stm_v_inp_ref = stm_v_inp_ref * 10000;
+       stm_true_val = ((stm_true_val * 10000) - stm_v_off) * 4095;
+       do_div(stm_true_ref, stm_v_inp_ref);
+       stm_v_inp_ref = stm_true_ref;
+       do_div(stm_true_val, stm_v_inp_ref);
+       do_div(stm_true_val, 10000);
+       if (stm_true_val > 4095) stm_true_val = 4095;
+       regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_val_reg, (unsigned int) stm_true_val);
+}
+
+void neuronspi_spi_iio_stm_ao_set_current(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       u32 stm_v_int_ref = 0;
+       u32 stm_v_inp_ref = 0;
+       u32 stm_i_err = 0;
+       u32 stm_i_off = 0;
+       u64 stm_true_val = 0;
+       u64 stm_true_ref = 0;
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_int, &stm_v_int_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->vref_inp, &stm_v_inp_ref);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_curr_err, &stm_i_err);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_curr_off, &stm_i_off);
+       stm_true_ref = ((u64)stm_v_int_ref) * (330000 + stm_i_err);
+       stm_v_inp_ref = stm_v_inp_ref * 10000;
+       stm_true_val = (stm_true_val * 10000) - stm_i_off;
+       do_div(stm_true_ref, stm_v_inp_ref);
+       do_div(stm_true_ref, 4095);
+       stm_v_inp_ref = stm_true_ref;
+       do_div(stm_true_val, stm_v_inp_ref);
+       if (stm_true_val > 4095) stm_true_val = 4095;
+       regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_val_reg, (unsigned int)stm_true_val);
+}
+
+/*
+static s32 neuronspi_spi_watchdog(void *data)
+{
+       s32 *cycle = (s32 *) data;
+       while (!kthread_should_stop()) {
+               msleep(*cycle);
+               spin_lock(neuronspi_spi_w_spinlock);
+               if (neuronspi_spi_w_flag == 0) {
+                       panic_timeout = -1;
+                       panic("SPI Watchdog Failure\n");
+               } else {
+                       neuronspi_spi_w_flag = 0;
+               }
+               spin_unlock(neuronspi_spi_w_spinlock);
+       }
+       return 0;
+}
+*/
+
+
+
+void neuronspi_spi_send_message(struct spi_device* spi_dev, u8 *send_buf, u8 *recv_buf, s32 len, s32 freq, s32 delay, s32 send_header)
+{
+       s32 i = 0;
+       u16 recv_crc1 = 0;
+       u16 recv_crc2 = 0;
+       u16 packet_crc = 0;
+       s32 trans_count = (len / NEURONSPI_MAX_TX) + 3; // number of transmissions
+       struct spi_message s_msg;
+       struct neuronspi_driver_data *d_data;
+    struct spi_transfer* s_trans;
+       mutex_lock(&neuronspi_master_mutex);
+    s_trans = kzalloc(sizeof(struct spi_transfer) * trans_count, GFP_KERNEL);
+#if NEURONSPI_DETAILED_DEBUG > 1
+    printk(KERN_INFO "NEURONSPI: SPI Master Write, len:%d,\n %100ph\n", len, send_buf);
+#endif
+       if (!send_header) {
+               trans_count -= 1;       // one less transmission as the header is omitted
+       }
+    spi_message_init(&s_msg);
+    for (i = 0; i < trans_count; i++) {
+       memset(&(s_trans[i]), 0, sizeof(s_trans[i]));
+       s_trans[i].delay_usecs = 0;
+       s_trans[i].bits_per_word = 8;
+       s_trans[i].speed_hz = freq;
+       if (i == 0) {
+               s_trans[i].delay_usecs = NEURONSPI_EDGE_DELAY;
+       } else if (i == 1) {
+                   s_trans[i].tx_buf = send_buf;
+                   s_trans[i].rx_buf = recv_buf;
+               if (send_header) {
+                   s_trans[i].delay_usecs = delay;
+                   s_trans[i].len = NEURONSPI_FIRST_MESSAGE_LENGTH;
+               } else {
+                       // If len is more than NEURONSPI_MAX_TX * i, then chunk len is NEURONSPI_MAX_TX, otherwise it's the remainder
+                       s_trans[i].len = (len - (NEURONSPI_MAX_TX * i)) > 0 ? NEURONSPI_MAX_TX : len;
+               }
+       } else if (i == trans_count - 1) {
+               if (send_header) {
+                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
+                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
+                       s_trans[i].len = ((NEURONSPI_MAX_TX * (i - 1)) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 2)));
+               } else {
+                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_MAX_TX * (i - 1)]);
+                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_MAX_TX * (i - 1)]);
+                       s_trans[i].len = ((NEURONSPI_MAX_TX * i) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 1)));
+               }
+               s_trans[i].delay_usecs = NEURONSPI_LAST_TRANSFER_DELAY;
+               // If len is more than NEURONSPI_MAX_TX * i (+ optionally header), then chunk len is NEURONSPI_MAX_TX (+ optionally header),
+               // otherwise it's the remainder
+       } else {
+               if (send_header) {
+                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
+                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_FIRST_MESSAGE_LENGTH + (NEURONSPI_MAX_TX * (i - 2))]);
+                       s_trans[i].len = ((NEURONSPI_MAX_TX * (i - 1)) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 2)));
+               } else {
+                       s_trans[i].tx_buf = &(send_buf[NEURONSPI_MAX_TX * (i - 1)]);
+                       s_trans[i].rx_buf = &(recv_buf[NEURONSPI_MAX_TX * (i - 1)]);
+                       s_trans[i].len = ((NEURONSPI_MAX_TX * i) - len) < 0 ? NEURONSPI_MAX_TX : (len - (NEURONSPI_MAX_TX * (i - 1)));
+               }
+               // If len is more than NEURONSPI_MAX_TX * i (+ optionally header), then chunk len is NEURONSPI_MAX_TX (+ optionally header),
+               // otherwise it's the remainder
+       }
+       spi_message_add_tail(&(s_trans[i]), &s_msg);
+    }
+    spi_sync(spi_dev, &s_msg);
+    for (i = 0; i < trans_count; i++) {
+       spi_transfer_del(&(s_trans[i]));
+    }
+#if NEURONSPI_DETAILED_DEBUG > 1
+    printk(KERN_INFO "NEURONSPI: SPI Master Read - %d:\n\t%100ph\n\t%100ph\n\t%100ph\n\t%100ph\n", len,recv_buf, &recv_buf[64],
+               &recv_buf[128], &recv_buf[192]);
+#endif
+    d_data = spi_get_drvdata(spi_dev);
+    if (d_data == NULL || (d_data != NULL && !d_data->reserved_device)) {
+               recv_crc1 = neuronspi_spi_crc(recv_buf, 4, 0);
+               memcpy(&packet_crc, &recv_buf[4], 2);
+#if NEURONSPI_DETAILED_DEBUG > 1
+               printk(KERN_INFO "NEURONSPI: SPI CRC1: %x\t COMPUTED CRC1:%x\n", packet_crc, recv_crc1);
+#endif
+               if (recv_crc1 == packet_crc) {
+               // Signal the UART to issue character reads
+#if NEURONSPI_DETAILED_DEBUG > 1
+               printk(KERN_INFO "NEURONSPI: SPI CRC1 Correct");
+#endif
+                       if (d_data && recv_buf[0] == 0x41) {
+                               d_data->uart_buf[0] = recv_buf[3];
+#if NEURONSPI_DETAILED_DEBUG > 0
+                               printk(KERN_INFO "NEURONSPI: Reading UART data for device %d\n", d_data->neuron_index);
+#endif
+                               for (i = 0; i < d_data->uart_data->p_count; i++) {
+                                       if (d_data->uart_data->p[i].dev_index == d_data->neuron_index) {
+                                               neuronspi_uart_handle_rx(&d_data->uart_data->p[i], 1, 1);
+                                       }
+                               }
+                               if (!(d_data->uart_read) && (d_data->uart_count)) {
+                                       d_data->uart_read = recv_buf[2];
+                                       for (i = 0; i < d_data->uart_data->p_count; i++) {
+#if NEURONSPI_DETAILED_DEBUG > 0
+                                       printk(KERN_INFO "NEURONSPI: UART Buffer:%d, UART Local Port Count:%d, UART Global Port Count:%d\n", d_data->uart_read,
+                                                       d_data->uart_count,  d_data->uart_data->p_count);
+#endif
+                                               if (d_data->uart_data->p[i].dev_index == d_data->neuron_index && !d_data->reserved_device) {
+                                                       kthread_queue_work(&d_data->uart_data->kworker, &d_data->uart_data->p[i].rx_work);
+                                               }
+                                       }
+                               }
+                       }
+               }
+#if NEURONSPI_DETAILED_DEBUG > 0
+               else {
+                       printk(KERN_INFO "NEURONSPI: SPI CRC1 Not Correct");
+               }
+#endif
+               recv_crc2 = neuronspi_spi_crc(&recv_buf[6], len - 8, recv_crc1);
+               memcpy(&packet_crc, &recv_buf[len - 2], 2);
+#if NEURONSPI_DETAILED_DEBUG > 1
+               printk(KERN_INFO "NEURONSPI: SPI CRC2: %x\t COMPUTED CRC2:%x\n", packet_crc, recv_crc2);
+#endif
+               if (recv_crc2 != packet_crc) {
+#if NEURONSPI_DETAILED_DEBUG > 0
+                       printk(KERN_INFO "NEURONSPI: SPI CRC2 Not Correct");
+#endif
+                       recv_buf[0] = 0;
+               }
+    }
+
+    mutex_unlock(&neuronspi_master_mutex);
+    kfree(s_trans);
+}
+
+
+
+irqreturn_t neuronspi_spi_irq(s32 irq, void *dev_id)
+{
+       s32 i;
+       struct spi_device *spi;
+       struct neuronspi_driver_data *d_data;
+       struct neuronspi_uart_data *u_data;
+       spi = (struct spi_device *)dev_id;
+       d_data = spi_get_drvdata(spi);
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: SPI IRQ\n");
+#endif
+       if (d_data->uart_count) {
+               u_data = d_data->uart_data;
+               for (i = 0; i < u_data->p_count; i++) {
+                       if (u_data->p[i].dev_index == d_data->neuron_index) {
+                               kthread_queue_work(&u_data->kworker, &u_data->p[i].irq_work);
+                       }
+
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+void neuronspi_spi_led_set_brightness(struct spi_device* spi_dev, enum led_brightness brightness, int id)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       u16 crc1;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: SPI LED Set, Dev-CS:%d, led id:%d\n", spi_dev->chip_select, id);
+#endif
+       message_buf = kzalloc(NEURONSPI_SPI_LED_SET_MESSAGE_LEN, GFP_KERNEL);
+       recv_buf = kzalloc(NEURONSPI_SPI_LED_SET_MESSAGE_LEN, GFP_KERNEL);
+       memcpy(message_buf, NEURONSPI_SPI_LED_SET_MESSAGE, NEURONSPI_SPI_LED_SET_MESSAGE_LEN);
+       message_buf[2] += id;
+       if (brightness > 0) {
+               message_buf[1] = 0x01;
+       } else {
+               message_buf[1] = 0x00;
+       }
+       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
+       memcpy(&message_buf[4], &crc1, 2);
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_LED_SET_MESSAGE_LEN, frequency, 25, 0);
+       }
+       printk(KERN_INFO "NEURONSPI: Brightness set to %d on led %d\n", brightness, id);
+       kfree(message_buf);
+       kfree(recv_buf);
+}
+
+int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id)
+{
+       u8 *recv_buf;
+       bool ret = 0;
+       u32 offset = id / 16;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       recv_buf = kzalloc(4, GFP_KERNEL);
+       printk(KERN_INFO "NEURONSPI: REGMAP TEST: %d\n", regmap_read(d_data->reg_map, d_data->regstart_table->di_val_reg + offset, (void*)recv_buf));
+       if (*recv_buf & (0x1 << offset)) {
+               ret = 1;
+       }
+       kfree(recv_buf);
+       printk(KERN_INFO "NEURONSPI: GPIO DI %d get %d\n", id, ret);
+       return ret;
+}
+
+int neuronspi_spi_gpio_do_set(struct spi_device* spi_dev, u32 id, int value)
+{
+       u32 current_value = 0;
+       bool ret = 0;
+       u32 offset = id / 16;
+       u16 off_val = value << (id % 16);
+       u16 mask = ~(1 << (id % 16));
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       regmap_read(d_data->reg_map, d_data->regstart_table->do_val_reg + offset, &current_value);
+       current_value&= mask;
+       current_value|= off_val;
+       regmap_write(d_data->reg_map, d_data->regstart_table->do_val_reg + offset, current_value);
+       printk(KERN_INFO "NEURONSPI: GPIO DO %d set %d\n", id, value);
+       return ret;
+}
+
+int neuronspi_spi_gpio_ro_set(struct spi_device* spi_dev, u32 id, int value)
+{
+       u32 current_value = 0;
+       bool ret = 0;
+       u32 offset = id / 16;
+       u16 off_val = value << (id % 16);
+       u16 mask = ~(1 << (id % 16));
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       regmap_read(d_data->reg_map, d_data->regstart_table->ro_val_reg + offset, &current_value);
+       current_value&= mask;
+       current_value|= off_val;
+       regmap_write(d_data->reg_map, d_data->regstart_table->ro_val_reg + offset, current_value);
+       printk(KERN_INFO "NEURONSPI: GPIO RO %d set %d\n", id, value);
+       return ret;
+}
+
+
+
+s32 neuronspi_spi_probe(struct spi_device *spi)
+{
+       const struct neuronspi_devtype *devtype;
+       struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
+
+       struct neuronspi_driver_data *n_spi;
+
+       s32 ret, i, no_irq = 0;
+       u8 uart_count = 0;
+       n_spi = kzalloc(sizeof *n_spi, GFP_KERNEL);
+       spin_lock(&neuronspi_probe_spinlock);
+       neuronspi_probe_count++;
+       spin_unlock(&neuronspi_probe_spinlock);
+       if (!n_spi)
+               return -ENOMEM;
+       printk(KERN_INFO "NEURONSPI: Neuronspi Probe Started\n");
+       if (n_spi == NULL || spi == NULL) {
+               return -8;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: Chip Max Hz-%d\n",spi->master->max_speed_hz);
+#endif
+       /* Setup SPI bus */
+       spi->bits_per_word      = 8;
+       spi->mode               = spi->mode ? spi->mode : SPI_MODE_0;
+       spi->max_speed_hz       = spi->max_speed_hz ? spi->max_speed_hz : 12000000;
+       ret = spi_setup(spi);
+       n_spi->neuron_index = spi->chip_select - 1;
+       n_spi->reserved_device = 0;
+
+       if (neuron_plc_dev == NULL) {
+               neuron_plc_dev = platform_device_alloc("unipi_plc", -1);
+               neuron_plc_dev->dev.groups = neuron_plc_attr_groups;
+               platform_device_add(neuron_plc_dev);
+       }
+
+       if (ret)
+               return ret;
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: Chip Max Hz-%d %d\n", spi->master->max_speed_hz, spi->max_speed_hz);
+#endif
+       if (spi->dev.of_node) {
+               const struct of_device_id *of_id =
+                       of_match_device(neuronspi_id_match, &spi->dev);
+               if (!of_id) {
+                       printk(KERN_DEBUG "NEURONSPI: Probe %s does not match a device!\n", *(&spi->dev.of_node->full_name));
+                       return -ENODEV;
+               }
+               of_property_read_u32_array(spi->dev.of_node, "neuron-board-index", &(n_spi->neuron_index), 1);
+               //print_device_tree_node(spi->dev.of_node->parent, 0);
+               devtype = (struct neuronspi_devtype *)of_id->data;
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_INFO "DEVICE TREE NODE FOUND %d\n", n_spi->neuron_index);
+#endif
+       } else {
+               const struct spi_device_id *id_entry = spi_get_device_id(spi);
+               devtype = (struct neuronspi_devtype *)id_entry->driver_data;
+       }
+
+
+       kthread_init_worker(&n_spi->primary_worker);
+
+       n_spi->primary_worker_task = kthread_run(kthread_worker_fn, &n_spi->primary_worker, "neuronspi");
+       if (IS_ERR(n_spi->primary_worker_task )) {
+               ret = PTR_ERR(n_spi->primary_worker_task);
+               return ret;
+       }
+       sched_setscheduler(n_spi->primary_worker_task, SCHED_FIFO, &sched_param);
+
+
+       // We perform an initial probe of registers 1000-1004 to identify the device, using a premade message
+       n_spi->recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
+       n_spi->send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
+       n_spi->first_probe_reply = kzalloc(NEURONSPI_PROBE_MESSAGE_LEN, GFP_KERNEL);    // allocate space for initial probe
+       n_spi->second_probe_reply = kzalloc(NEURONSPI_PROBE_MESSAGE_LEN, GFP_KERNEL); // allocate space for uart probe
+       n_spi->lower_board_id = 0xFF;
+       n_spi->upper_board_id = 0xFF;
+       n_spi->combination_id = 0xFF;
+       n_spi->spi_driver = &neuronspi_spi_driver;
+
+       memcpy(n_spi->send_buf, &NEURONSPI_PROBE_MESSAGE, NEURONSPI_PROBE_MESSAGE_LEN);
+       neuronspi_spi_send_message(spi, n_spi->send_buf, n_spi->first_probe_reply, NEURONSPI_PROBE_MESSAGE_LEN, NEURONSPI_DEFAULT_FREQ, 25, 1);
+
+       // Throw away the first message - the associated SPI Master is sometimes not properly initialised at this point
+       i = 0;
+       do {
+               memcpy(n_spi->send_buf, &NEURONSPI_PROBE_MESSAGE, NEURONSPI_PROBE_MESSAGE_LEN);
+               memset(n_spi->first_probe_reply, 0, NEURONSPI_PROBE_MESSAGE_LEN);
+               neuronspi_spi_send_message(spi, n_spi->send_buf, n_spi->first_probe_reply, NEURONSPI_PROBE_MESSAGE_LEN, NEURONSPI_DEFAULT_FREQ, 25, 1);
+               i++;
+               if (i > 1000) { // Sanity check to prevent looping if we get constant UART/0x41 messages
+                       ret = -4;
+                       kfree(n_spi);
+                       printk(KERN_INFO "NEURONSPI: Probe did not detect a valid Neuron device on CS %d\n", spi->chip_select);
+                       return ret;
+               }
+       } while (n_spi->first_probe_reply[0] == 0x41);  // UART messages should be ignored
+
+       if (n_spi->first_probe_reply[0] != 0) {         // CRC error sets the first byte to 0
+               uart_count = n_spi->first_probe_reply[14] & 0x0f;
+               for (i = 0; i < NEURONSPI_BOARDTABLE_LEN; i++) {
+                       if (n_spi->first_probe_reply[19] == NEURONSPI_BOARDTABLE[i].lower_board_id) {
+                               if (n_spi->combination_id == 0xFF && NEURONSPI_BOARDTABLE[i].upper_board_id == 0) {
+                                       n_spi->combination_id = NEURONSPI_BOARDTABLE[i].index;
+                               }
+                               if (n_spi->lower_board_id == 0xFF) {
+                                       n_spi->lower_board_id = n_spi->first_probe_reply[17];
+                               }
+                               if (n_spi->first_probe_reply[17] == NEURONSPI_BOARDTABLE[i].index) {
+                                       n_spi->combination_id = n_spi->first_probe_reply[17];
+                                       n_spi->upper_board_id = NEURONSPI_BOARDTABLE[i].upper_board_id;
+                               }
+                       }
+               }
+       } else {
+               ret = -5;
+               kfree(n_spi);
+               printk(KERN_INFO "NEURONSPI: Probe did not detect a valid Neuron device on CS %d\n", spi->chip_select);
+               return ret;
+       }
+
+       if (n_spi->lower_board_id != 0xFF && n_spi->combination_id != 0xFF) {
+               n_spi->features = kzalloc(sizeof(struct neuronspi_board_features), GFP_KERNEL);
+               n_spi->features = &(NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->features);
+       } else {
+               n_spi->features = NULL;
+       }
+
+       n_spi->ideal_frequency = NEURONSPI_COMMON_FREQ;
+       for (i = 0; i < NEURONSPI_SLOWER_MODELS_LEN; i++) {
+               if (NEURONSPI_SLOWER_MODELS[i] == (n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18])) {
+                       n_spi->slower_model = 1;
+                       n_spi->ideal_frequency = NEURONSPI_SLOWER_FREQ;
+               }
+       }
+       if (n_spi->lower_board_id != 0xFF && n_spi->combination_id != 0xFF) {
+               printk(KERN_INFO "NEURONSPI: Probe detected Neuron Board %s (L:%x U:%x C:%x) Index: %d Fw: v%d.%d on CS %d, \
+Uart count: %d - reg1000: %x, reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
+                               NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name,
+                               n_spi->lower_board_id, n_spi->upper_board_id, n_spi->combination_id,  n_spi->neuron_index,
+                               n_spi->first_probe_reply[11],  n_spi->first_probe_reply[10], spi->chip_select, uart_count,
+                               n_spi->first_probe_reply[11] << 8 | n_spi->first_probe_reply[10],
+                               n_spi->first_probe_reply[13] << 8 | n_spi->first_probe_reply[12], n_spi->first_probe_reply[15] << 8 | n_spi->first_probe_reply[14],
+                               n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16], n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18]);
+       } else if (n_spi->lower_board_id != 0xFF) {
+               printk(KERN_INFO "NEURONSPI: Probe detected Neuron Board L:%x C:??? Index: %d Fw: v%d.%d on CS %d, Uart count: %d - reg1000: %x, \
+reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
+                               n_spi->lower_board_id, n_spi->neuron_index, n_spi->first_probe_reply[11],  n_spi->first_probe_reply[10],
+                               spi->chip_select, uart_count, n_spi->first_probe_reply[11] << 8 | n_spi->first_probe_reply[10],
+                               n_spi->first_probe_reply[13] << 8 | n_spi->first_probe_reply[12], n_spi->first_probe_reply[15] << 8 | n_spi->first_probe_reply[14],
+                               n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16], n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18]);
+       } else {
+               printk(KERN_INFO "NEURONSPI: Probe detected Neuron Board L:??? C:??? Index: %d Fw: v%d.%d on CS %d, Uart count: %d - reg1000: %x, \
+reg1001: %x, reg1002: %x, reg1003: %x, reg1004: %x\n",
+                               n_spi->neuron_index, n_spi->first_probe_reply[11],  n_spi->first_probe_reply[10], spi->chip_select, uart_count,
+                               n_spi->first_probe_reply[11] << 8 | n_spi->first_probe_reply[10], n_spi->first_probe_reply[13] << 8 | n_spi->first_probe_reply[12],
+                               n_spi->first_probe_reply[15] << 8 | n_spi->first_probe_reply[14], n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16],
+                               n_spi->first_probe_reply[19] << 8 | n_spi->first_probe_reply[18]);
+       }
+       printk(KERN_INFO "NEURONSPI: Neuron device %s on CS %d uses SPI communication freq. %d Hz\n",
+                       NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name,
+                       spi->chip_select, n_spi->ideal_frequency);
+
+       n_spi->reg_map = regmap_init(&(spi->dev), &neuronspi_regmap_bus, spi, &neuronspi_regmap_config_default);
+       spin_lock_init(&n_spi->sysfs_regmap_lock);
+       if (n_spi->features) {
+               n_spi->regstart_table = kzalloc(sizeof(struct neuronspi_board_regstart_table), 1);
+               neuronspi_create_reg_starts(n_spi->regstart_table, NEURONSPI_BOARDTABLE[n_spi->combination_id].definition);
+       } else {
+               n_spi->regstart_table = NULL;
+       }
+
+
+       // Check for user-configurable LED devices
+       if (n_spi->features && n_spi->features->led_count > 0) {
+               printk(KERN_INFO "NEURONSPI: LED model %s with %d LEDs detected at CS: %d\n",
+                               NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name,
+                               n_spi->features->led_count, spi->chip_select);
+               n_spi->led_driver = kzalloc(sizeof(struct neuronspi_led_driver) * n_spi->features->led_count, GFP_KERNEL);
+               for (i = 0; i < n_spi->features->led_count; i++) {
+                       kthread_init_work(&(n_spi->led_driver[i].led_work), neuronspi_led_proc);
+               }
+       }
+
+
+       if (uart_count && neuronspi_uart == NULL) {     // Register UART if not registered
+               neuronspi_uart = kzalloc(sizeof(struct uart_driver), GFP_KERNEL);
+               neuronspi_uart->owner           = THIS_MODULE;
+               neuronspi_uart->dev_name        = "ttyNS";
+               neuronspi_uart->driver_name = "ttyNS";
+               neuronspi_uart->nr      = NEURONSPI_MAX_UART;
+               ret = uart_register_driver(neuronspi_uart);
+               if (ret) {
+                       printk(KERN_ERR "NEURONSPI:Failed to register the neuronspi uart driver, ERR:%d\n", ret);
+               } else {
+#if NEURONSPI_DETAILED_DEBUG > 0
+                       printk(KERN_DEBUG "NEURONSPI: UART driver registered successfully!\n");
+#endif
+               }
+               if (neuronspi_uart_glob_data != NULL) {
+                       printk(KERN_ERR "NEURONSPI:Uart data already allocated!\n");
+               } else {
+                       neuronspi_uart_glob_data = kzalloc(sizeof(struct neuronspi_uart_data), GFP_KERNEL);
+#if NEURONSPI_DETAILED_DEBUG > 0
+                       printk(KERN_DEBUG "NEURONSPI: UART driver data allocated successfully!\n");
+#endif
+               }
+
+       }
+       if (neuronspi_uart_glob_data != NULL) {
+               n_spi->uart_data = neuronspi_uart_glob_data;
+       }
+       n_spi->char_driver = &neuronspi_cdrv;
+       if (uart_count) {
+               n_spi->serial_driver = neuronspi_uart;
+       } else {
+               n_spi->serial_driver = NULL;
+       }
+       n_spi->uart_count = uart_count;
+
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: CHIP SELECT %d\n", spi->chip_select);
+#endif
+       spin_lock(&neuronspi_probe_spinlock);
+       neuronspi_s_dev[n_spi->neuron_index] = spi;
+       spi_set_drvdata(neuronspi_s_dev[n_spi->neuron_index], n_spi);
+       if (neuronspi_probe_count == NEURONSPI_MAX_DEVS) {
+               printk(KERN_INFO "NEURONSPI: MAXPROBECOUNT\n");
+               neuronspi_model_id = neuronspi_find_model_id(neuronspi_probe_count);
+       }
+       spin_unlock(&neuronspi_probe_spinlock);
+       if (neuronspi_model_id != -1) {
+               printk(KERN_INFO "NEURONSPI: Detected Neuron board combination corresponding to %s\n", NEURONSPI_MODELTABLE[neuronspi_model_id].model_name);
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: SPI IRQ: %d", spi->irq);
+#endif
+       strcpy(n_spi->platform_name, "io_group0");
+       n_spi->platform_name[8] = n_spi->neuron_index + '1';
+       n_spi->board_device = platform_device_alloc(n_spi->platform_name, -1);
+       n_spi->board_device->dev.parent = &(neuron_plc_dev->dev);
+       n_spi->board_device->dev.groups = neuron_board_attr_groups;
+       n_spi->board_device->dev.driver = &neuronspi_spi_driver.driver;
+       platform_device_add(n_spi->board_device);
+       platform_set_drvdata(n_spi->board_device, n_spi);
+
+       if (!(neuronspi_cdrv.major_number)) { // Register character device if it doesn't exist
+               ret = char_register_driver();
+               if (ret) {
+                       printk(KERN_ERR "NEURONSPI: Failed to register the neuronspi character driver, ERR:%d\n", ret);
+               }
+       }
+
+       if (n_spi->features) {
+               if (n_spi->features->led_count) {
+                       for (i = 0; i < n_spi->features->led_count; i++) {
+                               strcpy(n_spi->led_driver[i].name, "neuron:green:uled-x1");
+                               n_spi->led_driver[i].name[19] = i + '1';
+                               // Initialise the rest of the structure
+                               n_spi->led_driver[i].id = i;
+                               n_spi->led_driver[i].brightness = LED_OFF;
+                               n_spi->led_driver[i].spi = spi;
+                               spin_lock_init(&n_spi->led_driver[i].lock);
+                               n_spi->led_driver[i].ldev.name = n_spi->led_driver[i].name;
+                               n_spi->led_driver[i].ldev.brightness = n_spi->led_driver[i].brightness;
+                               n_spi->led_driver[i].ldev.brightness_set = neuronspi_led_set_brightness;
+                               led_classdev_register(&(n_spi->board_device->dev), &(n_spi->led_driver[i].ldev));
+                       }
+               }
+#ifdef CONFIG_GPIOLIB
+
+               if (n_spi->features->di_count) {
+                       n_spi->di_driver = kzalloc(sizeof(struct neuronspi_di_driver*) * n_spi->features->di_count, GFP_KERNEL);
+                       for (i = 0; i < n_spi->features->di_count; i++) {
+                               n_spi->di_driver[i] = kzalloc(sizeof(struct neuronspi_di_driver), GFP_KERNEL);
+                               strcpy(n_spi->di_driver[i]->name, "di_0_00");
+                               n_spi->di_driver[i]->name[3] = n_spi->neuron_index + '1';
+                               n_spi->di_driver[i]->name[5] = ((i + 1) / 10) + '0';
+                               n_spi->di_driver[i]->name[6] = ((i + 1) % 10) + '0';
+                               n_spi->di_driver[i]->di_index = i;
+                               n_spi->di_driver[i]->spi = spi;
+                               n_spi->di_driver[i]->plat_dev = platform_device_alloc(n_spi->di_driver[i]->name, -1);
+                               n_spi->di_driver[i]->plat_dev->dev.parent = &(n_spi->board_device->dev);
+                               n_spi->di_driver[i]->plat_dev->dev.groups = neuron_gpio_di_attr_groups;
+                               n_spi->di_driver[i]->plat_dev->dev.driver = &neuronspi_spi_driver.driver;
+                               platform_device_add(n_spi->di_driver[i]->plat_dev);
+                               platform_set_drvdata(n_spi->di_driver[i]->plat_dev, n_spi->di_driver[i]);
+                               n_spi->di_driver[i]->gpio_c.owner = THIS_MODULE;
+                               n_spi->di_driver[i]->gpio_c.parent = &(n_spi->di_driver[i]->plat_dev->dev);
+                               n_spi->di_driver[i]->gpio_c.label = "neuron_di";
+                               n_spi->di_driver[i]->gpio_c.can_sleep = 1;
+                               n_spi->di_driver[i]->gpio_c.ngpio = 1;
+                               n_spi->di_driver[i]->gpio_c.base = -1;
+                               n_spi->di_driver[i]->gpio_c.direction_input = neuronspi_gpio_di_direction_input;
+                               n_spi->di_driver[i]->gpio_c.get = neuronspi_gpio_di_get;
+                               gpiochip_add_data(&n_spi->di_driver[i]->gpio_c, n_spi->di_driver[i]);
+                       }
+               }
+
+               if (n_spi->features->do_count) {
+                       n_spi->do_driver = kzalloc(sizeof(struct neuronspi_do_driver*) * n_spi->features->do_count, GFP_KERNEL);
+                       for (i = 0; i < n_spi->features->do_count; i++) {
+                               n_spi->do_driver[i] = kzalloc(sizeof(struct neuronspi_do_driver), GFP_KERNEL);
+                               strcpy(n_spi->do_driver[i]->name, "do_0_00");
+                               n_spi->do_driver[i]->name[3] = n_spi->neuron_index + '1';
+                               n_spi->do_driver[i]->name[5] = ((i + 1) / 10) + '0';
+                               n_spi->do_driver[i]->name[6] = ((i + 1) % 10) + '0';
+                               n_spi->do_driver[i]->do_index = i;
+                               n_spi->do_driver[i]->spi = spi;
+                               n_spi->do_driver[i]->plat_dev = platform_device_alloc(n_spi->do_driver[i]->name, -1);
+                               n_spi->do_driver[i]->plat_dev->dev.parent = &(n_spi->board_device->dev);
+                               n_spi->do_driver[i]->plat_dev->dev.groups = neuron_gpio_do_attr_groups;
+                               n_spi->do_driver[i]->plat_dev->dev.driver = &neuronspi_spi_driver.driver;
+                               platform_device_add(n_spi->do_driver[i]->plat_dev);
+                               platform_set_drvdata(n_spi->do_driver[i]->plat_dev, n_spi->do_driver[i]);
+                               n_spi->do_driver[i]->gpio_c.owner = THIS_MODULE;
+                               n_spi->do_driver[i]->gpio_c.parent = &(n_spi->do_driver[i]->plat_dev->dev);
+                               n_spi->do_driver[i]->gpio_c.label = "neuron_do";
+                               n_spi->do_driver[i]->gpio_c.can_sleep = 1;
+                               n_spi->do_driver[i]->gpio_c.ngpio = n_spi->features->do_count;
+                               n_spi->do_driver[i]->gpio_c.base = -1;
+                               n_spi->do_driver[i]->gpio_c.direction_output = neuronspi_gpio_do_direction_output;
+                               n_spi->do_driver[i]->gpio_c.set = neuronspi_gpio_do_set;
+                               gpiochip_add_data(&n_spi->do_driver[i]->gpio_c, n_spi->do_driver[i]);
+                       }
+               }
+
+               if (n_spi->features->ro_count) {
+                       n_spi->ro_driver = kzalloc(sizeof(struct neuronspi_ro_driver*) * n_spi->features->ro_count, GFP_KERNEL);
+                       for (i = 0; i < n_spi->features->ro_count; i++) {
+                               n_spi->ro_driver[i] = kzalloc(sizeof(struct neuronspi_ro_driver), GFP_KERNEL);
+                               strcpy(n_spi->ro_driver[i]->name, "ro_0_00");
+                               n_spi->ro_driver[i]->name[3] = n_spi->neuron_index + '1';
+                               n_spi->ro_driver[i]->name[5] = ((i + 1) / 10) + '0';
+                               n_spi->ro_driver[i]->name[6] = ((i + 1) % 10) + '0';
+                               n_spi->ro_driver[i]->ro_index = i;
+                               n_spi->ro_driver[i]->spi = spi;
+                               n_spi->ro_driver[i]->plat_dev = platform_device_alloc(n_spi->ro_driver[i]->name, -1);
+                               n_spi->ro_driver[i]->plat_dev->dev.parent = &(n_spi->board_device->dev);
+                               n_spi->ro_driver[i]->plat_dev->dev.groups = neuron_gpio_ro_attr_groups;
+                               n_spi->ro_driver[i]->plat_dev->dev.driver = &neuronspi_spi_driver.driver;
+                               platform_device_add(n_spi->ro_driver[i]->plat_dev);
+                               platform_set_drvdata(n_spi->ro_driver[i]->plat_dev, n_spi->ro_driver[i]);
+                               n_spi->ro_driver[i]->gpio_c.owner = THIS_MODULE;
+                               n_spi->ro_driver[i]->gpio_c.parent = &(n_spi->ro_driver[i]->plat_dev->dev);
+                               n_spi->ro_driver[i]->gpio_c.label = "neuron_ro";
+                               n_spi->ro_driver[i]->gpio_c.can_sleep = 1;
+                               n_spi->ro_driver[i]->gpio_c.ngpio = n_spi->features->ro_count;
+                               n_spi->ro_driver[i]->gpio_c.base = -1;
+                               n_spi->ro_driver[i]->gpio_c.direction_output = neuronspi_gpio_ro_direction_output;
+                               n_spi->ro_driver[i]->gpio_c.set = neuronspi_gpio_ro_set;
+                               gpiochip_add_data(&n_spi->ro_driver[i]->gpio_c, n_spi->ro_driver[i]);
+                       }
+               }
+
+#endif
+               if (n_spi->features->stm_ai_count) {
+                       n_spi->stm_ai_driver = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_stm_ai_data));
+                       ((struct neuronspi_stm_ai_data*)iio_priv(n_spi->stm_ai_driver))->parent = spi;
+                       n_spi->stm_ai_driver->modes = INDIO_DIRECT_MODE;
+                       n_spi->stm_ai_driver->currentmode = INDIO_DIRECT_MODE;
+                       n_spi->stm_ai_driver->name = "ai_type_a";
+                       n_spi->stm_ai_driver->dev.parent = &(n_spi->board_device->dev);
+                       dev_set_name(&n_spi->stm_ai_driver->dev, "ai_%d_1",     (int)n_spi->neuron_index + 1);
+                       n_spi->stm_ai_driver->num_channels = 2;
+                       n_spi->stm_ai_driver->channels = neuronspi_stm_ai_chan_spec;
+                       n_spi->stm_ai_driver->info = &neuronspi_stm_ai_info;
+                       iio_device_register(n_spi->stm_ai_driver);
+               }
+               if (n_spi->features->stm_ao_count) {
+                       n_spi->stm_ao_driver = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_stm_ai_data));
+                       ((struct neuronspi_stm_ao_data*)iio_priv(n_spi->stm_ao_driver))->parent = spi;
+                       n_spi->stm_ao_driver->modes = INDIO_DIRECT_MODE;
+                       n_spi->stm_ao_driver->currentmode = INDIO_DIRECT_MODE;
+                       n_spi->stm_ao_driver->name = "ao_type_a";
+                       n_spi->stm_ao_driver->dev.parent = &(n_spi->board_device->dev);
+                       dev_set_name(&n_spi->stm_ao_driver->dev, "ao_%d_1",     (int)n_spi->neuron_index + 1);
+                       n_spi->stm_ao_driver->num_channels = 3;
+                       n_spi->stm_ao_driver->channels = neuronspi_stm_ao_chan_spec;
+                       n_spi->stm_ao_driver->info = &neuronspi_stm_ao_info;
+                       iio_device_register(n_spi->stm_ao_driver);
+               }
+               if (n_spi->features->sec_ai_count) {
+                       n_spi->sec_ai_driver = kzalloc(sizeof(struct neuronspi_sec_ai_data*) * n_spi->features->sec_ai_count, GFP_KERNEL);
+                       for (i = 0; i < n_spi->features->sec_ai_count; i++) {
+                               n_spi->sec_ai_driver[i] = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_sec_ai_data));
+                               ((struct neuronspi_sec_ai_data*)iio_priv(n_spi->sec_ai_driver[i]))->parent = spi;
+                               n_spi->sec_ai_driver[i]->modes = INDIO_DIRECT_MODE;
+                               n_spi->sec_ai_driver[i]->currentmode = INDIO_DIRECT_MODE;
+                               n_spi->sec_ai_driver[i]->name = "ai_type_b";
+                               n_spi->sec_ai_driver[i]->dev.parent = &(n_spi->board_device->dev);
+                               dev_set_name(&n_spi->sec_ai_driver[i]->dev, "ai_%d_%d", (int)n_spi->neuron_index + 1, (int)i + 1);
+                               n_spi->sec_ai_driver[i]->num_channels = 3;
+                               n_spi->sec_ai_driver[i]->channels = neuronspi_sec_ai_chan_spec;
+                               n_spi->sec_ai_driver[i]->info = &neuronspi_sec_ai_info;
+                               iio_device_register(n_spi->sec_ai_driver[i]);
+                       }
+               }
+               if (n_spi->features->sec_ao_count) {
+                       n_spi->sec_ao_driver = kzalloc(sizeof(struct neuronspi_sec_ao_data*) * n_spi->features->sec_ao_count, GFP_KERNEL);
+                       for (i = 0; i < n_spi->features->sec_ao_count; i++) {
+                               n_spi->sec_ao_driver[i] = devm_iio_device_alloc(&(spi->dev), sizeof(struct neuronspi_sec_ao_data));
+                               ((struct neuronspi_sec_ao_data*)iio_priv(n_spi->sec_ao_driver[i]))->parent = spi;
+                               n_spi->sec_ao_driver[i]->modes = INDIO_DIRECT_MODE;
+                               n_spi->sec_ao_driver[i]->currentmode = INDIO_DIRECT_MODE;
+                               n_spi->sec_ao_driver[i]->name = "ao_type_b";
+                               n_spi->sec_ao_driver[i]->dev.parent = &(n_spi->board_device->dev);
+                               dev_set_name(&n_spi->sec_ao_driver[i]->dev, "ao_%d_%d", (int)n_spi->neuron_index + 1, (int)i + 1);
+                               n_spi->sec_ao_driver[i]->num_channels = 1;
+                               n_spi->sec_ao_driver[i]->channels = neuronspi_sec_ao_chan_spec;
+                               n_spi->sec_ao_driver[i]->info = &neuronspi_sec_ao_info;
+                               iio_device_register(n_spi->sec_ao_driver[i]);
+                       }
+               }
+       }
+
+       if (uart_count) {
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_DEBUG "NEURONSPI: UART registration 1\n");
+#endif
+               n_spi->uart_buf = kzalloc(NEURONSPI_FIFO_SIZE, GFP_KERNEL);
+               neuronspi_uart_probe(spi, n_spi->neuron_index);
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_DEBUG "NEURONSPI: UART PROBE MCTRL:%d\n", neuronspi_spi_uart_get_cflag(spi, 0));
+#endif
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: UART registration\n");
+#endif
+       neuronspi_spi_set_irqs(spi, 0x5);
+       for (i = 0; i < NEURONSPI_NO_INTERRUPT_MODELS_LEN; i++) {
+               if (NEURONSPI_NO_INTERRUPT_MODELS[i] == (n_spi->first_probe_reply[17] << 8 | n_spi->first_probe_reply[16])) {
+                       no_irq = 1;
+               }
+       }
+
+       n_spi->poll_thread = NULL;
+       if (!no_irq) {
+               n_spi->no_irq = 0;
+               ret = devm_request_irq(&(spi->dev), spi->irq, neuronspi_spi_irq, 0x81, dev_name(&(spi->dev)), spi);
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_DEBUG "NEURONSPI: IRQ registration, ret:%d\n", ret);
+#endif
+       } else {
+               n_spi->no_irq = 1;
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_DEBUG "NEURONSPI: NO IRQ ON THIS MODEL !!\n");
+#endif
+       }
+
+       return ret;
+}
+
+u32 neuronspi_spi_uart_get_cflag(struct spi_device* spi_dev, u8 port)
+{
+       u8 *message_buf;
+       u8 *recv_buf;
+       u16 crc1, crc2, ret;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       s32 frequency = NEURONSPI_COMMON_FREQ;
+       if (d_data->slower_model) {
+               frequency = NEURONSPI_SLOWER_FREQ;
+       }
+       message_buf = kzalloc(NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
+       recv_buf = kzalloc(NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN, GFP_KERNEL);
+       memcpy(message_buf, NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE, NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN);
+       crc1 = neuronspi_spi_crc(message_buf, 4, 0);
+       memcpy(&message_buf[4], &crc1, 2);
+       crc2 = neuronspi_spi_crc(&message_buf[6], NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN - 8, crc1);
+       memcpy(&message_buf[NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN - 2], &crc2, 2);
+       if (!d_data->reserved_device) {
+               neuronspi_spi_send_message(spi_dev, message_buf, recv_buf, NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN, frequency, 65, 1);
+       }
+       ret = ((u32*)recv_buf)[5];
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: SPI TERMIOS Get, Dev-CS:%d, val:%x\n", spi_dev->chip_select, ret);
+#endif
+       kfree(message_buf);
+       kfree(recv_buf);
+       return ret;
+}
+
+s32 neuronspi_spi_remove(struct spi_device *spi)
+{
+       int i;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       if (n_spi) {
+               if (n_spi->led_driver) {
+                       for (i = 0; i < n_spi->features->led_count; i++) {
+                               led_classdev_unregister(&(n_spi->led_driver[i].ldev));
+                       }
+                       kthread_flush_worker(&n_spi->primary_worker);
+                       kfree(n_spi->led_driver);
+                       n_spi->led_driver = NULL;
+               }
+               printk(KERN_INFO "NEURONSPI: LED DRIVER UNREGISTERED\n");
+               if (n_spi->di_driver) {
+                       for (i = 0; i < n_spi->features->di_count; i++) {
+                               gpiochip_remove(&n_spi->di_driver[i]->gpio_c);
+                               platform_set_drvdata(n_spi->di_driver[i]->plat_dev, 0);
+                               platform_device_unregister(n_spi->di_driver[i]->plat_dev);
+                               kfree(n_spi->di_driver[i]);
+                       }
+                       kfree(n_spi->di_driver);
+               }
+               if (n_spi->do_driver) {
+                       for (i = 0; i < n_spi->features->do_count; i++) {
+                               gpiochip_remove(&n_spi->do_driver[i]->gpio_c);
+                               platform_set_drvdata(n_spi->do_driver[i]->plat_dev, 0);
+                               platform_device_unregister(n_spi->do_driver[i]->plat_dev);
+                               kfree(n_spi->do_driver[i]);
+                       }
+                       kfree(n_spi->do_driver);
+               }
+               if (n_spi->ro_driver) {
+                       for (i = 0; i < n_spi->features->ro_count; i++) {
+                               gpiochip_remove(&n_spi->ro_driver[i]->gpio_c);
+                               platform_set_drvdata(n_spi->ro_driver[i]->plat_dev, 0);
+                               platform_device_unregister(n_spi->ro_driver[i]->plat_dev);
+                               kfree(n_spi->ro_driver[i]);
+                       }
+                       kfree(n_spi->ro_driver);
+               }
+               printk(KERN_INFO "NEURONSPI: GPIO DRIVER UNREGISTERED\n");
+               if (n_spi->stm_ai_driver) {
+                       iio_device_unregister(n_spi->stm_ai_driver);
+               }
+               if (n_spi->stm_ao_driver) {
+                       iio_device_unregister(n_spi->stm_ao_driver);
+               }
+               if (n_spi->sec_ai_driver) {
+                       for (i = 0; i < n_spi->features->sec_ai_count; i++) {
+                               iio_device_unregister(n_spi->sec_ai_driver[i]);
+                       }
+                       kfree(n_spi->sec_ai_driver);
+                       n_spi->sec_ai_driver = NULL;
+               }
+               if (n_spi->sec_ao_driver) {
+                       for (i = 0; i < n_spi->features->sec_ao_count; i++) {
+                               iio_device_unregister(n_spi->sec_ao_driver[i]);
+                       }
+                       kfree(n_spi->sec_ao_driver);
+                       n_spi->sec_ao_driver = NULL;
+               }
+               printk(KERN_INFO "NEURONSPI: IIO DRIVER UNREGISTERED\n");
+               if (n_spi->send_buf) {
+                       kfree(n_spi->send_buf);
+                       n_spi->send_buf = NULL;
+               }
+               if (n_spi->recv_buf) {
+                       kfree(n_spi->recv_buf);
+                       n_spi->recv_buf = NULL;
+               }
+               if (n_spi->uart_buf) {
+                       kfree(n_spi->uart_buf);
+                       n_spi->uart_buf = NULL;
+               }
+               printk(KERN_INFO "NEURONSPI: SPI/UART DRIVER UNREGISTERED\n");
+               if (n_spi->board_device) {
+                       platform_set_drvdata(n_spi->board_device, 0);
+                       platform_device_unregister(n_spi->board_device);
+               }
+               kfree(n_spi);
+       }
+       return 0;
+}
+
+s32 char_register_driver(void)
+{
+       s32 ret = 0;
+
+       // Character device registration
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: Initialising Character Device\n");
+#endif
+       neuronspi_cdrv.major_number = register_chrdev(0, NEURON_DEVICE_NAME, &file_ops);
+       if (neuronspi_cdrv.major_number < 0){
+          printk(KERN_ALERT "NEURONSPI: failed to register a major number\n");
+          return neuronspi_cdrv.major_number;
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: registered correctly with major number %d\n", neuronspi_cdrv.major_number);
+#endif
+
+       // Character class registration
+       neuronspi_cdrv.driver_class = class_create(THIS_MODULE, NEURON_DEVICE_CLASS);
+       if (IS_ERR(neuronspi_cdrv.driver_class)) {
+               unregister_chrdev(neuronspi_cdrv.major_number, NEURON_DEVICE_NAME);
+               printk(KERN_ALERT "NEURONSPI: Failed to register device class\n");
+               return PTR_ERR(neuronspi_cdrv.driver_class);
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: device class registered correctly\n");
+#endif
+
+       // Device driver registration
+       neuronspi_cdrv.dev = device_create_with_groups(neuronspi_cdrv.driver_class, &(neuron_plc_dev->dev), MKDEV(neuronspi_cdrv.major_number, 0), NULL, neuron_plc_attr_groups, NEURON_DEVICE_NAME);
+       if (IS_ERR(neuronspi_cdrv.dev)) {
+               class_destroy(neuronspi_cdrv.driver_class);
+               unregister_chrdev(neuronspi_cdrv.major_number, NEURON_DEVICE_NAME);
+               printk(KERN_ALERT "NEURONSPI: Failed to create the device\n");
+               return PTR_ERR(neuronspi_cdrv.dev);
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: device class created correctly\n");
+#endif
+       return ret;
+}
+
+s32 char_unregister_driver(void)
+{
+       device_destroy(neuronspi_cdrv.driver_class, MKDEV(neuronspi_cdrv.major_number, 0));     // Destroy the device
+       class_unregister(neuronspi_cdrv.driver_class);                                                          // Unregister the class
+       class_destroy(neuronspi_cdrv.driver_class);                                                             // Destroy the class
+       unregister_chrdev(neuronspi_cdrv.major_number, NEURON_DEVICE_NAME);                                     // Unregister the major number
+       printk(KERN_INFO "NEURONSPI: Device unloaded successfully\n");
+       return 0;
+}
+
+/*********************
+ * Final definitions *
+ *********************/
+
+MODULE_ALIAS("spi:neuronspi");
+
+static s32 __init neuronspi_init(void)
+{
+       s32 ret = 0;
+       neuronspi_spi_w_spinlock = kzalloc(sizeof(struct spinlock), GFP_KERNEL);
+       spin_lock_init(neuronspi_spi_w_spinlock);
+       mutex_init(&neuronspi_master_mutex);
+       memset(&neuronspi_s_dev, 0, sizeof(neuronspi_s_dev));
+       ret = spi_register_driver(&neuronspi_spi_driver);
+       if (ret < 0) {
+               printk(KERN_ERR "NEURONSPI: Failed to init neuronspi spi --> %d\n", ret);
+               return ret;
+       } else {
+#ifdef NEURONSPI_MAJOR_VERSIONSTRING
+               printk(KERN_INFO "NEURONSPI: SPI Driver Registered, Major Version: %s\n", NEURONSPI_MAJOR_VERSIONSTRING);
+#else
+               printk(KERN_INFO "NEURONSPI: SPI Driver Registered\n");
+#endif
+       }
+       neuronspi_invalidate_thread = kthread_create(neuronspi_regmap_invalidate, NULL, "neuronspi_inv");
+       if (neuronspi_invalidate_thread != NULL) {
+               wake_up_process(neuronspi_invalidate_thread);
+       }
+       return ret;
+}
+__attribute__((unused)) module_init(neuronspi_init);
+
+static void __exit neuronspi_exit(void)
+{
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: Open Counter is %d\n", neuronspi_cdrv.open_counter);
+#endif
+       if (neuronspi_invalidate_thread) {
+               kthread_stop(neuronspi_invalidate_thread);
+       }
+       char_unregister_driver();
+       if (neuronspi_uart) {
+               neuronspi_uart_remove(neuronspi_uart_glob_data);
+               uart_unregister_driver(neuronspi_uart);
+               kfree(neuronspi_uart);
+               kfree(neuronspi_uart_glob_data);
+       }
+       spi_unregister_driver(&neuronspi_spi_driver);
+       if (neuron_plc_dev) {
+               platform_device_unregister(neuron_plc_dev);
+       }
+       kfree(neuronspi_spi_w_spinlock);
+       printk(KERN_INFO "NEURONSPI: SPI Driver Unregistered\n");
+}
+__attribute__((unused)) module_exit(neuronspi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomas Knot <knot@faster.cz>");
+MODULE_DESCRIPTION("UniPi Neuron driver");
diff --git a/modules/unipi/src/unipi_spi.h b/modules/unipi/src/unipi_spi.h
new file mode 100644 (file)
index 0000000..75e795f
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2017 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_SPI_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_SPI_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+#include "unipi_common.h"
+#include "unipi_platform.h"
+#include "unipi_sysfs.h"
+#include "unipi_iio.h"
+
+/********************
+ * Module Constants *
+ ********************/
+
+#define NEURONSPI_SLOWER_MODELS_LEN                                    3
+static const u16 NEURONSPI_SLOWER_MODELS[NEURONSPI_SLOWER_MODELS_LEN] = {
+               0xb10, 0xc10, 0xf10
+};
+
+#define NEURONSPI_PROBE_MESSAGE_LEN                                            22
+static const u8 NEURONSPI_PROBE_MESSAGE[NEURONSPI_PROBE_MESSAGE_LEN] = {
+               0x04, 0x0e, 0xe8, 0x03, 0xa0, 0xdd,
+               0x04, 0x00, 0xe8, 0x03, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00,     0x12, 0x16
+};
+
+#define NEURONSPI_UART_PROBE_MESSAGE_LEN                               6
+static const u8 NEURONSPI_UART_PROBE_MESSAGE[NEURONSPI_UART_PROBE_MESSAGE_LEN] = {
+               0xfa, 0x00, 0x55, 0x0e, 0xb6, 0x0a
+};
+
+#define NEURONSPI_SPI_UART_SHORT_MESSAGE_LEN                   6
+static const u8 NEURONSPI_SPI_UART_SHORT_MESSAGE[NEURONSPI_SPI_UART_SHORT_MESSAGE_LEN] = {
+               0x41, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#define NEURONSPI_SPI_UART_LONG_MESSAGE_LEN                            8
+static const u8 NEURONSPI_SPI_UART_LONG_MESSAGE[NEURONSPI_SPI_UART_LONG_MESSAGE_LEN] = {
+               0x64, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00
+};
+
+#define NEURONSPI_SPI_UART_READ_MESSAGE_LEN                            14
+static const u8 NEURONSPI_SPI_UART_READ_MESSAGE[NEURONSPI_SPI_UART_READ_MESSAGE_LEN] = {
+               0x65, 0x06, 0x00, 0x00, 0x44, 0x69,
+               0x65, 0x03, 0x00, 0x00, 0x00, 0x05,
+               0x6a, 0x0c
+};
+
+#define NEURONSPI_SPI_IRQ_SET_MESSAGE_LEN                              14
+static const u8 NEURONSPI_SPI_IRQ_SET_MESSAGE[NEURONSPI_SPI_UART_READ_MESSAGE_LEN] = {
+               0x06, 0x06, 0xef, 0x03, 0x00, 0x00,
+               0x06, 0x01, 0xef, 0x03, 0x05, 0x00,
+               0x00, 0x00
+};
+
+#define NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN               16
+static const u8 NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE[NEURONSPI_SPI_UART_GET_CFLAG_MESSAGE_LEN] = {
+               0x04, 0x08, 0xf4, 0x01, 0x00, 0x00,
+               0x04, 0x02, 0xf4, 0x01, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00
+};
+
+#define NEURONSPI_SPI_UART_GET_LDISC_MESSAGE_LEN               16
+static const u8 NEURONSPI_SPI_UART_GET_LDISC_MESSAGE[NEURONSPI_SPI_UART_GET_LDISC_MESSAGE_LEN] = {
+               0x04, 0x08, 0xf6, 0x01, 0x00, 0x00,
+               0x04, 0x02, 0xf6, 0x01, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00
+};
+
+#define NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN               16
+static const u8 NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE[NEURONSPI_SPI_UART_SET_CFLAG_MESSAGE_LEN] = {
+               0x06, 0x08, 0xf4, 0x01, 0x00, 0x00,
+               0x06, 0x02, 0xf4, 0x01, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00
+};
+
+#define NEURONSPI_SPI_LED_SET_MESSAGE_LEN                              6
+static const u8 NEURONSPI_SPI_LED_SET_MESSAGE[NEURONSPI_SPI_LED_SET_MESSAGE_LEN] = {
+               0x05, 0x00, 0x08, 0x00, 0x00, 0x00
+};
+
+#define NEURONSPI_CRC16TABLE_LEN                                               256
+static const u16 NEURONSPI_CRC16TABLE[NEURONSPI_CRC16TABLE_LEN] = {
+    0,  1408,  3968,  2560,  7040,  7680,  5120,  4480, 13184, 13824, 15360,
+14720, 10240, 11648, 10112,  8704, 25472, 26112, 27648, 27008, 30720, 32128,
+30592, 29184, 20480, 21888, 24448, 23040, 19328, 19968, 17408, 16768, 50048,
+50688, 52224, 51584, 55296, 56704, 55168, 53760, 61440, 62848, 65408, 64000,
+60288, 60928, 58368, 57728, 40960, 42368, 44928, 43520, 48000, 48640, 46080,
+45440, 37760, 38400, 39936, 39296, 34816, 36224, 34688, 33280, 33665, 34305,
+35841, 35201, 38913, 40321, 38785, 37377, 45057, 46465, 49025, 47617, 43905,
+44545, 41985, 41345, 57345, 58753, 61313, 59905, 64385, 65025, 62465, 61825,
+54145, 54785, 56321, 55681, 51201, 52609, 51073, 49665, 16385, 17793, 20353,
+18945, 23425, 24065, 21505, 20865, 29569, 30209, 31745, 31105, 26625, 28033,
+26497, 25089,  9089,  9729, 11265, 10625, 14337, 15745, 14209, 12801,  4097,
+ 5505,  8065,  6657,  2945,  3585,  1025,   385,   899,  1539,  3075,  2435,
+ 6147,  7555,  6019,  4611, 12291, 13699, 16259, 14851, 11139, 11779,  9219,
+ 8579, 24579, 25987, 28547, 27139, 31619, 32259, 29699, 29059, 21379, 22019,
+23555, 22915, 18435, 19843, 18307, 16899, 49155, 50563, 53123, 51715, 56195,
+56835, 54275, 53635, 62339, 62979, 64515, 63875, 59395, 60803, 59267, 57859,
+41859, 42499, 44035, 43395, 47107, 48515, 46979, 45571, 36867, 38275, 40835,
+39427, 35715, 36355, 33795, 33155, 32770, 34178, 36738, 35330, 39810, 40450,
+37890, 37250, 45954, 46594, 48130, 47490, 43010, 44418, 42882, 41474, 58242,
+58882, 60418, 59778, 63490, 64898, 63362, 61954, 53250, 54658, 57218, 55810,
+52098, 52738, 50178, 49538, 17282, 17922, 19458, 18818, 22530, 23938, 22402,
+20994, 28674, 30082, 32642, 31234, 27522, 28162, 25602, 24962,  8194,  9602,
+12162, 10754, 15234, 15874, 13314, 12674,  4994,  5634,  7170,  6530,  2050,
+ 3458,  1922,   514
+};
+
+static const struct of_device_id neuronspi_id_match[] = {
+               {.compatible = "unipi,neuron"},
+               {.compatible = NEURON_DEVICE_NAME},
+               {}
+};
+
+/***************
+ * Definitions *
+ ***************/
+
+#define NEURON_INT_RX_NOT_EMPTY                        0x1
+#define NEURON_INT_TX_FINISHED                         0x2
+#define NEURON_INT_RX_MODBUS                           0x4
+#define NEURON_INT_DI_CHANGED                          0x8
+#define NEURON_INT_ID_MASK                             0x0f
+#define NEURON_INT_NO_INT_BIT                          0x0f
+
+#define NEURONSPI_RECONF_MD                                    (1 << 0)
+#define NEURONSPI_RECONF_IER                           (1 << 1)
+#define NEURONSPI_RECONF_RS485                         (1 << 2)
+
+#define MODBUS_FIRST_DATA_BYTE                         10
+
+#define MODBUS_MAX_READ_BITS                2000
+#define MODBUS_MAX_WRITE_BITS               1968
+#define MODBUS_MAX_READ_REGISTERS           125
+#define MODBUS_MAX_WRITE_REGISTERS          123
+#define MODBUS_MAX_WR_WRITE_REGISTERS       121
+#define MODBUS_MAX_WR_READ_REGISTERS        125
+
+/*************************
+ * Function Declarations *
+ *************************/
+
+int neuronspi_open (struct inode *, struct file *);
+int neuronspi_release (struct inode *, struct file *);
+ssize_t neuronspi_read (struct file *, char *, size_t, loff_t *);
+ssize_t neuronspi_write (struct file *, const char *, size_t, loff_t *);
+s32 char_register_driver(void);
+s32 char_unregister_driver(void);
+irqreturn_t neuronspi_spi_irq(s32 irq, void *dev_id);
+s32 neuronspi_spi_probe(struct spi_device *spi);
+s32 neuronspi_spi_remove(struct spi_device *spi);
+void neuronspi_spi_send_message(struct spi_device *spi_dev, u8 *send_buf, u8 *recv_buf, s32 len, s32 freq, s32 delay, s32 send_header);
+s32 neuronspi_spi_uart_write(struct spi_device *spi, u8 *send_buf, u8 length, u8 uart_index);
+void neuronspi_spi_uart_read(struct spi_device* spi_dev, u8 *send_buf, u8 *recv_buf, s32 len, u8 uart_index);
+void neuronspi_spi_set_irqs(struct spi_device* spi_dev, u16 to);
+void neuronspi_spi_led_set_brightness(struct spi_device* spi_dev, enum led_brightness brightness, int id);
+void neuronspi_spi_iio_stm_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+void neuronspi_spi_iio_stm_ai_read_current(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+void neuronspi_spi_iio_stm_ao_read_resistance(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+void neuronspi_spi_iio_stm_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
+void neuronspi_spi_iio_stm_ao_set_current(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
+void neuronspi_spi_iio_sec_ai_read_voltage(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+void neuronspi_spi_iio_sec_ai_read_current(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+void neuronspi_spi_iio_sec_ai_read_resistance(struct iio_dev *iio_dev, struct iio_chan_spec const *ch, int *val, int *val2, long mask);
+void neuronspi_spi_iio_sec_ao_set_voltage(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask);
+int neuronspi_spi_gpio_do_set(struct spi_device* spi_dev, u32 id, int value);
+int neuronspi_spi_gpio_ro_set(struct spi_device* spi_dev, u32 id, int value);
+int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id);
+int neuronspi_spi_gpio_di_get(struct spi_device* spi_dev, u32 id);
+
+/***********************
+ * Function structures *
+ ***********************/
+
+// Host driver struct
+extern struct spi_driver neuronspi_spi_driver;
+extern struct file_operations file_ops;
+
+static const struct regmap_bus neuronspi_regmap_bus =
+{
+       .fast_io                                        = 1,
+       .write                                          = neuronspi_regmap_hw_write,
+       .gather_write                           = neuronspi_regmap_hw_gather_write,
+       .reg_write                                      = neuronspi_regmap_hw_reg_write,
+       .read                                           = neuronspi_regmap_hw_read,
+       .reg_read                                       = neuronspi_regmap_hw_reg_read,
+       .reg_format_endian_default  = REGMAP_ENDIAN_NATIVE,
+       .val_format_endian_default  = REGMAP_ENDIAN_NATIVE,
+       .max_raw_read                           = 200,                                                          // CRC and other overhead not included
+       .max_raw_write                          = 200,                                                          // CRC and other overhead not included
+};
+
+static const struct regmap_config neuronspi_regmap_config_default =
+{
+               .name                                   = "Neuronspi Regmap",
+               .reg_bits                               = 16,
+               .reg_stride                             = 0,
+               .pad_bits                               = 0,
+               .val_bits                               = 16,
+               .max_register                   = 65535,
+               .cache_type                             = REGCACHE_RBTREE,
+               .use_single_rw                  = 0,
+               .can_multi_write                = 1,
+};
+
+static const struct iio_chan_spec neuronspi_stm_ai_chan_spec[] = {
+       {
+                       .type = IIO_VOLTAGE,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 0
+       },
+       {
+                       .type = IIO_CURRENT,
+                       .indexed = 1,
+                       .channel = 1,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 0
+       }
+};
+
+static const struct iio_chan_spec neuronspi_stm_ao_chan_spec[] = {
+       {
+                       .type = IIO_VOLTAGE,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 1
+       },
+       {
+                       .type = IIO_CURRENT,
+                       .indexed = 1,
+                       .channel = 1,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 1
+       },
+       {
+                       .type = IIO_RESISTANCE,
+                       .indexed = 1,
+                       .channel = 2,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 0
+       }
+};
+
+static const struct iio_chan_spec neuronspi_sec_ai_chan_spec[] = {
+       {
+                       .type = IIO_VOLTAGE,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 0
+       },
+       {
+                       .type = IIO_CURRENT,
+                       .indexed = 1,
+                       .channel = 1,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 0
+       },
+       {
+                       .type = IIO_RESISTANCE,
+                       .indexed = 1,
+                       .channel = 2,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 0
+       }
+};
+
+static const struct iio_chan_spec neuronspi_sec_ao_chan_spec[] = {
+       {
+                       .type = IIO_VOLTAGE,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .output = 1
+       }
+};
+
+static const struct iio_info neuronspi_stm_ai_info = {
+       .read_raw = neuronspi_iio_stm_ai_read_raw,
+       .driver_module = THIS_MODULE,
+       .attrs = &neuron_stm_ai_group,
+};
+
+static const struct iio_info neuronspi_stm_ao_info = {
+       .read_raw = neuronspi_iio_stm_ao_read_raw,
+       .write_raw = neuronspi_iio_stm_ao_write_raw,
+       .driver_module = THIS_MODULE,
+       .attrs = &neuron_stm_ao_group,
+};
+
+static const struct iio_info neuronspi_sec_ai_info = {
+       .read_raw = neuronspi_iio_sec_ai_read_raw,
+       .driver_module = THIS_MODULE,
+       .attrs = &neuron_sec_ai_group,
+};
+
+static const struct iio_info neuronspi_sec_ao_info = {
+       .write_raw = neuronspi_iio_sec_ao_write_raw,
+       .driver_module = THIS_MODULE,
+       .attrs = &neuron_sec_ao_group,
+};
+
+// These defines need to be at the end
+#define to_neuronspi_uart_data(p,e)  ((container_of((p), struct neuronspi_uart_data, e)))
+#define to_neuronspi_port(p,e) ((container_of((p), struct neuronspi_port, e)))
+#define to_led_driver(p,e)     ((container_of((p), struct neuronspi_led_driver, e)))
+#define to_uart_port(p,e)      ((container_of((p), struct uart_port, e)))
+
+
+/*********************
+ * In-line Functions *
+ *********************/
+
+static __always_inline u16 neuronspi_spi_crc(u8* inputstring, s32 length, u16 initval)
+{
+    s32 i;
+    u16 result = initval;
+    for (i=0; i<length; i++) {
+        result = (result >> 8) ^ NEURONSPI_CRC16TABLE[(result ^ inputstring[i]) & 0xff];
+    }
+    return result;
+}
+
+static __always_inline size_t neuronspi_spi_compose_single_coil_write(u16 start, u8 **buf_inp, u8 **buf_outp, u8 data)
+{
+       u16 crc1;
+       *buf_outp = kzalloc(6, GFP_KERNEL);
+       *buf_inp = kzalloc(6, GFP_KERNEL);
+       (*buf_inp)[0] = 0x05;
+       (*buf_inp)[1] = data;
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       return 6;
+}
+
+static __always_inline size_t neuronspi_spi_compose_single_coil_read(u16 start, u8 **buf_inp, u8 **buf_outp)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(14, GFP_KERNEL);
+       *buf_inp = kzalloc(14, GFP_KERNEL);
+       (*buf_inp)[0] = 0x01;
+       (*buf_inp)[1] = 0x06;
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 6, crc1);
+       memcpy(&(*buf_inp)[12], &crc2, 2);
+       return 14;
+}
+
+static __always_inline size_t neuronspi_spi_compose_multiple_coil_write(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp, u8 *data)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
+       *buf_inp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
+       (*buf_inp)[0] = 0x0F;
+       (*buf_inp)[1] = 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       (*buf_inp)[7] = number;
+       memcpy(&(*buf_inp)[10], data, NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number));
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), crc1);
+       memcpy(&(*buf_inp)[10 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number)], &crc2, 2);
+       return 12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
+}
+
+static __always_inline size_t neuronspi_spi_compose_multiple_coil_read(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
+       *buf_inp = kzalloc(12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), GFP_KERNEL);
+       (*buf_inp)[0] = 0x01;
+       (*buf_inp)[1] = 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number), crc1);
+       memcpy(&(*buf_inp)[10 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number)], &crc2, 2);
+       return 12 + NEURONSPI_GET_COIL_READ_PHASE2_BYTE_LENGTH(number);
+}
+
+static __always_inline size_t neuronspi_spi_compose_single_register_write(u16 start, u8 **buf_inp, u8 **buf_outp, u16 data)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(14, GFP_KERNEL);
+       *buf_inp = kzalloc(14, GFP_KERNEL);
+       (*buf_inp)[0] = 0x06;
+       (*buf_inp)[1] = 0x06;
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       printk(KERN_INFO "NEURONSPI: COMPOSE SINGLE WRITE DATA: %x\n", data);
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       (*buf_inp)[7] = 0x01;
+       memcpy(&(*buf_inp)[10], &data, 2);
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 6, crc1);
+       memcpy(&(*buf_inp)[12], &crc2, 2);
+       return 14;
+}
+
+static __always_inline size_t neuronspi_spi_compose_single_register_read(u16 start, u8 **buf_inp, u8 **buf_outp)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(14, GFP_KERNEL);
+       *buf_inp = kzalloc(14, GFP_KERNEL);
+       (*buf_inp)[0] = 0x03;
+       (*buf_inp)[1] = 0x06;
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       (*buf_inp)[7] = 0x01;
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 6, crc1);
+       memcpy(&(*buf_inp)[12], &crc2, 2);
+       return 14;
+}
+
+static __always_inline size_t neuronspi_spi_compose_multiple_register_write(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp, u8 *data)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(12 + (number * 2), GFP_KERNEL);
+       *buf_inp = kzalloc(12 + (number * 2), GFP_KERNEL);
+       (*buf_inp)[0] = 0x10;
+       (*buf_inp)[1] = 4 + (number * 2);
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       (*buf_inp)[7] = number;
+       memcpy(&(*buf_inp)[10], data, number * 2);
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + (number * 2), crc1);
+       memcpy(&(*buf_inp)[10 + (number * 2)], &crc2, 2);
+       return 12 + (number * 2);
+}
+
+static __always_inline size_t neuronspi_spi_compose_multiple_register_read(u8 number, u16 start, u8 **buf_inp, u8 **buf_outp)
+{
+       u16 crc1, crc2;
+       *buf_outp = kzalloc(12 + (number * 2), GFP_KERNEL);
+       *buf_inp = kzalloc(12 + (number * 2), GFP_KERNEL);
+       (*buf_inp)[0] = 0x03;
+       (*buf_inp)[1] = 4 + (number * 2);
+       (*buf_inp)[2] = start & 0xFF;
+       (*buf_inp)[3] = start >> 8;
+       crc1 = neuronspi_spi_crc(*buf_inp, 4, 0);
+       memcpy(&(*buf_inp)[4], &crc1, 2);
+       memcpy(&(*buf_inp)[6], *buf_inp, 4);
+       (*buf_inp)[7] = number;
+       crc2 = neuronspi_spi_crc(&(*buf_inp)[6], 4 + (number * 2), crc1);
+       memcpy(&(*buf_inp)[10 + (number * 2)], &crc2, 2);
+       return 12 + (number * 2);
+}
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_SPI_H_ */
diff --git a/modules/unipi/src/unipi_sysfs.c b/modules/unipi/src/unipi_sysfs.c
new file mode 100644 (file)
index 0000000..e82f957
--- /dev/null
@@ -0,0 +1,1098 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+/************
+ * Includes *
+ ************/
+
+#include "unipi_sysfs.h"
+
+/************************
+ * Static Functions *
+ ************************/
+
+static ssize_t neuronspi_show_model(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       if (neuronspi_model_id != -1) {
+               ret = scnprintf(buf, 255, "%s\n", NEURONSPI_MODELTABLE[neuronspi_model_id].model_name);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_show_eeprom(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       if (neuronspi_model_id != -1) {
+               ret = scnprintf(buf, 255, "%s\n", NEURONSPI_MODELTABLE[neuronspi_model_id].eeprom_name);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_serial(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val[2] = {0, 0};
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_serial_num, val);
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_serial_num + 1, &(val[1]));
+               ret = scnprintf(buf, 255, "%d\n", val[0]);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_hw_version(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_hw_ver, &val);
+               ret = scnprintf(buf, 255, "%x.%x\n", (val & 0xF0) >> 4, val & 0xF);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_hw_flash_version(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_hw_flash_ver, &val);
+               ret = scnprintf(buf, 255, "%x.%x\n", (val & 0xF0) >> 4, val & 0xF);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_fw_version(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->sys_sw_ver, &val);
+               ret = scnprintf(buf, 255, "%x.%x%x\n", (val & 0xF00) >> 8, (val & 0xF0) >> 4, val & 0xF);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_uart_queue_length(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->regstart_table->uart_queue_reg) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->uart_queue_reg, &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_uart_config(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->regstart_table->uart_conf_reg) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->uart_conf_reg, &val);
+               ret = scnprintf(buf, 255, "%x\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_store_uart_config(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->regstart_table->uart_conf_reg) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->uart_conf_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_show_watchdog_status(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->wd_val_reg, &val);
+               ret = scnprintf(buf, 255, "%x\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_store_watchdog_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->wd_val_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_show_watchdog_timeout(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->wd_timeout_reg, &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_store_watchdog_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->wd_timeout_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_show_pwm_presc(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_pwm_ps_reg, &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_store_pwm_presc(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_pwm_ps_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_show_pwm_freq(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_pwm_c_reg, &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_store_pwm_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_pwm_c_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_show_pwm_cycle(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_pwm_reg + n_do->do_index, &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_store_pwm_cycle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_pwm_reg + n_do->do_index, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_di_show_counter(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_counter_reg + (2 * n_di->di_index), &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_di_store_counter(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_counter_reg + (2 * n_di->di_index), val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_di_show_debounce(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->features && n_spi->features->di_count > n_di->di_index) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_deboun_reg + n_di->di_index, &val);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_di_store_debounce(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map && n_spi->features && n_spi->features->di_count > n_di->di_index) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_deboun_reg + n_di->di_index, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_di_show_value(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->di_count > n_di->di_index) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_val_reg + (n_di->di_index / 16), &val);
+               val &= 0x1 << (n_di->di_index % 15);
+               val = val >> (n_di->di_index % 15);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_do_show_value(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       int val;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->do_count > n_do->do_index) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_val_reg + (n_do->do_index / 16), &val);
+               val &= 0x1 << (n_do->do_index % 15);
+               val = val >> (n_do->do_index % 15);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_do_store_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       int inp = 0;
+       unsigned int val;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       err = kstrtoint(buf, 0, &inp);
+       if (err < 0) goto err_end;
+       if (inp > 1 || inp < 0) {
+               goto err_end;
+       }
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->do_count > n_do->do_index) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->do_val_reg + (n_do->do_index / 16), &val);
+               val &= ~(0x1 << (n_do->do_index % 15));
+               val |= inp << (n_do->do_index % 15);
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->do_val_reg + (n_do->do_index / 16), val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_ro_show_value(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       int val;
+       struct neuronspi_ro_driver *n_ro;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_ro = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_ro->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ro_count > n_ro->ro_index) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->ro_val_reg + (n_ro->ro_index / 16), &val);
+               val &= 0x1 << (n_ro->ro_index % 15);
+               val = val >> (n_ro->ro_index % 15);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_ro_store_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       int inp = 0;
+       unsigned int val;
+       struct neuronspi_ro_driver *n_ro;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_ro = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_ro->spi);
+       err = kstrtoint(buf, 0, &inp);
+       if (err < 0) goto err_end;
+       if (inp > 1 || inp < 0) {
+               goto err_end;
+       }
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ro_count > n_ro->ro_index) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->ro_val_reg + (n_ro->ro_index / 16), &val);
+               val &= ~(0x1 << (n_ro->ro_index % 15));
+               val |= inp << (n_ro->ro_index % 15);
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->ro_val_reg + (n_ro->ro_index / 16), val);
+       }
+err_end:
+       return count;
+}
+
+
+static ssize_t neuronspi_spi_gpio_show_ds_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_direct_reg + (n_di->di_index / 16), &val);
+               val &= 0x1 << (n_di->di_index % 15);
+               val = val >> (n_di->di_index % 15);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_ds_toggle(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_toggle_reg + (n_di->di_index / 16), &val);
+               val &= 0x1 << (n_di->di_index % 15);
+               val = val >> (n_di->di_index % 15);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_ds_polarity(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_polar_reg + (n_di->di_index / 16), &val);
+               val &= 0x1 << (n_di->di_index % 15);
+               val = val >> (n_di->di_index % 15);
+               ret = scnprintf(buf, 255, "%d\n", val);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_store_ds_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       int inp = 0;
+       unsigned int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       err = kstrtoint(buf, 0, &inp);
+       if (err < 0) goto err_end;
+       if (inp > 1 || inp < 0) {
+               goto err_end;
+       }
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_direct_reg + (n_di->di_index / 16), &val);
+               val &= ~(0x1 << (n_di->di_index % 15));
+               val |= inp << (n_di->di_index % 15);
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_direct_reg + (n_di->di_index / 16), val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_store_ds_toggle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       int inp = 0;
+       unsigned int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       err = kstrtoint(buf, 0, &inp);
+       if (err < 0) goto err_end;
+       if (inp > 1 || inp < 0) {
+               goto err_end;
+       }
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_toggle_reg + (n_di->di_index / 16), &val);
+               val &= ~(0x1 << (n_di->di_index % 15));
+               val |= inp << (n_di->di_index % 15);
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_toggle_reg + (n_di->di_index / 16), val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_gpio_store_ds_polarity(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       int inp = 0;
+       unsigned int val;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       err = kstrtoint(buf, 0, &inp);
+       if (err < 0) goto err_end;
+       if (inp > 1 || inp < 0) {
+               goto err_end;
+       }
+       if (n_spi && n_spi->combination_id != -1 && n_spi->features && n_spi->features->ds_count) {
+               regmap_read(n_spi->reg_map, n_spi->regstart_table->di_polar_reg + (n_di->di_index / 16), &val);
+               val &= ~(0x1 << (n_di->di_index % 15));
+               val |= inp << (n_di->di_index % 15);
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->di_polar_reg + (n_di->di_index / 16), val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_show_regmap(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       u32 val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi && n_spi->reg_map) {
+               spin_lock(&n_spi->sysfs_regmap_lock);
+               regmap_read(n_spi->reg_map, n_spi->sysfs_regmap_target, &val);
+               ret = scnprintf(buf, 255, "%x\n", val);
+               spin_unlock(&n_spi->sysfs_regmap_lock);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_store_regmap(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->reg_map && val < 65536) {
+               spin_lock(&n_spi->sysfs_regmap_lock);
+               n_spi->sysfs_regmap_target = val;
+               spin_unlock(&n_spi->sysfs_regmap_lock);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_spi_show_board(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi->combination_id != -1 && n_spi->combination_id < NEURONSPI_BOARDTABLE_LEN) {
+               ret = scnprintf(buf, 255, "%s\n", NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->combination_name);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_lboard_id(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi->combination_id != -1 && n_spi->combination_id < NEURONSPI_BOARDTABLE_LEN) {
+               ret = scnprintf(buf, 255, "%d\n", NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->lower_board_id);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_show_uboard_id(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_spi = platform_get_drvdata(plat);
+       if (n_spi->combination_id != -1 && n_spi->combination_id < NEURONSPI_BOARDTABLE_LEN) {
+               ret = scnprintf(buf, 255, "%d\n", NEURONSPI_BOARDTABLE[n_spi->combination_id].definition->upper_board_id);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_do_prefix(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi->features && n_spi->features->do_count > 0 && n_spi->do_driver) {
+               ret = scnprintf(buf, 255, "%s_%d\n", n_spi->do_driver[n_do->do_index]->gpio_c.label, n_spi->neuron_index + 1);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_di_prefix(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi->features && n_spi->features->di_count > 0 && n_spi->di_driver) {
+               ret = scnprintf(buf, 255, "%s_%d\n", n_spi->di_driver[n_di->di_index]->gpio_c.label, n_spi->neuron_index + 1);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_ro_prefix(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_ro_driver *n_ro;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_ro = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_ro->spi);
+       if (n_spi->features && n_spi->features->ro_count > 0 && n_spi->ro_driver) {
+               ret = scnprintf(buf, 255, "%s_%d\n", n_spi->ro_driver[n_ro->ro_index]->gpio_c.label, n_spi->neuron_index + 1);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_do_base(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi->features && n_spi->features->do_count > 0 && n_spi->do_driver) {
+               ret = scnprintf(buf, 255, "%d\n", n_spi->do_driver[n_do->do_index]->gpio_c.base);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_di_base(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi->features && n_spi->features->di_count > 0 && n_spi->di_driver) {
+               ret = scnprintf(buf, 255, "%d\n", n_spi->di_driver[n_di->di_index]->gpio_c.base);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_ro_base(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_ro_driver *n_ro;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_ro = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_ro->spi);
+       if (n_spi->features && n_spi->features->ro_count > 0 && n_spi->ro_driver) {
+               ret = scnprintf(buf, 255, "%d\n", n_spi->ro_driver[n_ro->ro_index]->gpio_c.base);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_do_count(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_do_driver *n_do;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_do = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_do->spi);
+       if (n_spi->features && n_spi->features->do_count > 0 && n_spi->do_driver) {
+               ret = scnprintf(buf, 255, "%d\n", n_spi->do_driver[n_do->do_index]->gpio_c.ngpio);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_di_count(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_di_driver *n_di;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_di = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_di->spi);
+       if (n_spi->features && n_spi->features->di_count > 0 && n_spi->di_driver) {
+               ret = scnprintf(buf, 255, "%d\n", n_spi->di_driver[n_di->di_index]->gpio_c.ngpio);
+       }
+       return ret;
+}
+
+static ssize_t neuronspi_spi_gpio_show_ro_count(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ssize_t ret = 0;
+       struct neuronspi_ro_driver *n_ro;
+       struct neuronspi_driver_data *n_spi;
+       struct platform_device *plat = to_platform_device(dev);
+       n_ro = platform_get_drvdata(plat);
+       n_spi = spi_get_drvdata(n_ro->spi);
+       if (n_spi->features && n_spi->features->ro_count > 0 && n_spi->ro_driver) {
+               ret = scnprintf(buf, 255, "%d\n", n_spi->ro_driver[n_ro->ro_index]->gpio_c.ngpio);
+       }
+       return ret;
+}
+
+
+static ssize_t neuronspi_iio_show_primary_ai_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int ret = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ai_mode_reg, &val);
+       ret = scnprintf(buf, 255, "%d\n", val);
+       return ret;
+}
+
+static ssize_t neuronspi_iio_store_primary_ai_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_stm_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ai_mode_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_iio_show_primary_ao_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int ret = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, &val);
+       ret = scnprintf(buf, 255, "%d\n", val);
+       return ret;
+}
+
+static ssize_t neuronspi_iio_store_primary_ao_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_stm_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->stm_ao_mode_reg, val);
+       }
+err_end:
+       return count;
+}
+
+static ssize_t neuronspi_iio_show_secondary_ai_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int ret = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_mode_reg + ai_data->index, &val);
+       ret = scnprintf(buf, 255, "%d\n", val);
+       return ret;
+}
+static ssize_t neuronspi_iio_store_secondary_ai_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_sec_ai_data *ai_data = iio_priv(indio_dev);
+       struct spi_device *spi = ai_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->sec_ai_mode_reg + ai_data->index, val);
+       }
+err_end:
+       return count;
+}
+static ssize_t neuronspi_iio_show_secondary_ao_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int ret = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_sec_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ao_mode_reg + ao_data->index, &val);
+       ret = scnprintf(buf, 255, "%d\n", val);
+       return ret;
+}
+static ssize_t neuronspi_iio_store_secondary_ao_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       ssize_t err = 0;
+       unsigned int val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct neuronspi_sec_ao_data *ao_data = iio_priv(indio_dev);
+       struct spi_device *spi = ao_data->parent;
+       struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
+       err = kstrtouint(buf, 0, &val);
+       if (err < 0) goto err_end;
+       if (n_spi && n_spi->combination_id != -1 && n_spi->reg_map) {
+               regmap_write(n_spi->reg_map, n_spi->regstart_table->sec_ao_mode_reg + ao_data->index, val);
+       }
+err_end:
+       return count;
+}
+
+/**********************************
+ * Function Structure Definitions *
+ **********************************/
+
+static DEVICE_ATTR(model_name, 0440, neuronspi_show_model, NULL);
+static DEVICE_ATTR(sys_eeprom_name, 0440, neuronspi_show_eeprom, NULL);
+static DEVICE_ATTR(register_read, 0660, neuronspi_show_regmap, neuronspi_store_regmap);
+static DEVICE_ATTR(sys_board_serial, 0440, neuronspi_spi_show_serial, NULL);
+static DEVICE_ATTR(sys_board_name, 0440, neuronspi_spi_show_board, NULL);
+static DEVICE_ATTR(sys_primary_major_id, 0440, neuronspi_spi_show_lboard_id, NULL);
+static DEVICE_ATTR(sys_secondary_major_id, 0440, neuronspi_spi_show_uboard_id, NULL);
+static DEVICE_ATTR(sys_primary_minor_id, 0440, neuronspi_spi_show_hw_version, NULL);
+static DEVICE_ATTR(sys_secondary_minor_id, 0440, neuronspi_spi_show_hw_flash_version, NULL);
+static DEVICE_ATTR(firmware_version, 0440, neuronspi_spi_show_fw_version, NULL);
+static DEVICE_ATTR(watchdog_status, 0660, neuronspi_spi_show_watchdog_status, neuronspi_spi_store_watchdog_status);
+static DEVICE_ATTR(watchdog_timeout, 0660, neuronspi_spi_show_watchdog_timeout, neuronspi_spi_store_watchdog_timeout);
+static DEVICE_ATTR(sys_gpio_do_count, 0440, neuronspi_spi_gpio_show_do_count, NULL);
+static DEVICE_ATTR(sys_gpio_do_prefix, 0440, neuronspi_spi_gpio_show_do_prefix, NULL);
+static DEVICE_ATTR(sys_gpio_do_base, 0440, neuronspi_spi_gpio_show_do_base, NULL);
+static DEVICE_ATTR(sys_gpio_di_count, 0440, neuronspi_spi_gpio_show_di_count, NULL);
+static DEVICE_ATTR(sys_gpio_di_prefix, 0440, neuronspi_spi_gpio_show_di_prefix, NULL);
+static DEVICE_ATTR(ro_value, 0660, neuronspi_spi_gpio_ro_show_value, neuronspi_spi_gpio_ro_store_value);
+static DEVICE_ATTR(do_value, 0660, neuronspi_spi_gpio_do_show_value, neuronspi_spi_gpio_do_store_value);
+static DEVICE_ATTR(counter, 0660, neuronspi_spi_gpio_di_show_counter, neuronspi_spi_gpio_di_store_counter);
+static DEVICE_ATTR(debounce, 0660, neuronspi_spi_gpio_di_show_debounce, neuronspi_spi_gpio_di_store_debounce);
+static DEVICE_ATTR(di_value, 0440, neuronspi_spi_gpio_di_show_value, NULL);
+static DEVICE_ATTR(direct_switch_enable, 0660, neuronspi_spi_gpio_show_ds_enable, neuronspi_spi_gpio_store_ds_enable);
+static DEVICE_ATTR(direct_switch_toggle, 0660, neuronspi_spi_gpio_show_ds_toggle, neuronspi_spi_gpio_store_ds_toggle);
+static DEVICE_ATTR(direct_switch_polarity, 0660, neuronspi_spi_gpio_show_ds_polarity, neuronspi_spi_gpio_store_ds_polarity);
+static DEVICE_ATTR(pwm_frequency_cycle, 0660, neuronspi_spi_gpio_show_pwm_freq, neuronspi_spi_gpio_store_pwm_freq);
+static DEVICE_ATTR(pwm_prescale, 0660, neuronspi_spi_gpio_show_pwm_presc, neuronspi_spi_gpio_store_pwm_presc);
+static DEVICE_ATTR(pwm_duty_cycle, 0660, neuronspi_spi_gpio_show_pwm_cycle, neuronspi_spi_gpio_store_pwm_cycle);
+static DEVICE_ATTR(uart_queue_length, 0440, neuronspi_spi_show_uart_queue_length, NULL);
+static DEVICE_ATTR(uart_config, 0660, neuronspi_spi_show_uart_config, neuronspi_spi_store_uart_config);
+static DEVICE_ATTR(sys_gpio_di_base, 0440, neuronspi_spi_gpio_show_di_base, NULL);
+static DEVICE_ATTR(sys_gpio_ro_count, 0440, neuronspi_spi_gpio_show_ro_count, NULL);
+static DEVICE_ATTR(sys_gpio_ro_prefix, 0440, neuronspi_spi_gpio_show_ro_prefix, NULL);
+static DEVICE_ATTR(sys_gpio_ro_base, 0440, neuronspi_spi_gpio_show_ro_base, NULL);
+static DEVICE_ATTR(mode_ai_type_a, 0660, neuronspi_iio_show_primary_ai_mode, neuronspi_iio_store_primary_ai_mode);
+static DEVICE_ATTR(mode_ao_type_a, 0660, neuronspi_iio_show_primary_ao_mode, neuronspi_iio_store_primary_ao_mode);
+static DEVICE_ATTR(mode_ai_type_b, 0660, neuronspi_iio_show_secondary_ai_mode, neuronspi_iio_store_secondary_ai_mode);
+static DEVICE_ATTR(mode_ao_type_b, 0660, neuronspi_iio_show_secondary_ao_mode, neuronspi_iio_store_secondary_ao_mode);
+
+static struct attribute *neuron_plc_attrs[] = {
+               &dev_attr_model_name.attr,
+               &dev_attr_sys_eeprom_name.attr,
+               NULL,
+};
+
+static struct attribute *neuron_board_attrs[] = {
+               &dev_attr_sys_board_name.attr,
+               &dev_attr_sys_primary_major_id.attr,
+               &dev_attr_sys_secondary_major_id.attr,
+               &dev_attr_sys_primary_minor_id.attr,
+               &dev_attr_sys_secondary_minor_id.attr,
+               &dev_attr_firmware_version.attr,
+               &dev_attr_watchdog_status.attr,
+               &dev_attr_watchdog_timeout.attr,
+               &dev_attr_sys_board_serial.attr,
+               &dev_attr_uart_queue_length.attr,
+               &dev_attr_uart_config.attr,
+               &dev_attr_register_read.attr,
+               NULL,
+};
+
+static struct attribute *neuron_gpio_di_attrs[] = {
+               &dev_attr_sys_gpio_di_count.attr,
+               &dev_attr_sys_gpio_di_prefix.attr,
+               &dev_attr_sys_gpio_di_base.attr,
+               &dev_attr_direct_switch_enable.attr,
+               &dev_attr_direct_switch_toggle.attr,
+               &dev_attr_direct_switch_polarity.attr,
+               &dev_attr_di_value.attr,
+               &dev_attr_counter.attr,
+               &dev_attr_debounce.attr,
+               NULL,
+};
+
+static struct attribute *neuron_gpio_do_attrs[] = {
+               &dev_attr_sys_gpio_do_count.attr,
+               &dev_attr_sys_gpio_do_prefix.attr,
+               &dev_attr_sys_gpio_do_base.attr,
+               &dev_attr_pwm_frequency_cycle.attr,
+               &dev_attr_pwm_prescale.attr,
+               &dev_attr_pwm_duty_cycle.attr,
+               &dev_attr_do_value.attr,
+               NULL,
+};
+
+static struct attribute *neuron_gpio_ro_attrs[] = {
+               &dev_attr_sys_gpio_ro_count.attr,
+               &dev_attr_sys_gpio_ro_prefix.attr,
+               &dev_attr_sys_gpio_ro_base.attr,
+               &dev_attr_ro_value.attr,
+               NULL,
+};
+
+static struct attribute *neuron_stm_ai_attrs[] = {
+               &dev_attr_mode_ai_type_a.attr,
+               NULL,
+};
+
+static struct attribute *neuron_stm_ao_attrs[] = {
+               &dev_attr_mode_ao_type_a.attr,
+               NULL,
+};
+
+static struct attribute *neuron_sec_ai_attrs[] = {
+               &dev_attr_mode_ai_type_b.attr,
+               NULL,
+};
+
+static struct attribute *neuron_sec_ao_attrs[] = {
+               &dev_attr_mode_ao_type_b.attr,
+               NULL,
+};
+
+static struct attribute_group neuron_plc_attr_group = {
+       .attrs = neuron_plc_attrs,
+};
+
+static struct attribute_group neuron_board_attr_group = {
+       .attrs = neuron_board_attrs,
+};
+
+static struct attribute_group neuron_gpio_di_attr_group = {
+       .attrs = neuron_gpio_di_attrs,
+};
+
+static struct attribute_group neuron_gpio_do_attr_group = {
+       .attrs = neuron_gpio_do_attrs,
+};
+
+static struct attribute_group neuron_gpio_ro_attr_group = {
+       .attrs = neuron_gpio_ro_attrs,
+};
+
+const struct attribute_group neuron_stm_ai_group = {
+       .attrs = neuron_stm_ai_attrs,
+};
+
+const struct attribute_group neuron_stm_ao_group = {
+       .attrs = neuron_stm_ao_attrs,
+};
+
+const struct attribute_group neuron_sec_ai_group = {
+       .attrs = neuron_sec_ai_attrs,
+};
+
+const struct attribute_group neuron_sec_ao_group = {
+       .attrs = neuron_sec_ao_attrs,
+};
+
+const struct attribute_group *neuron_plc_attr_groups[] = {
+       &neuron_plc_attr_group,
+       NULL,
+};
+
+const struct attribute_group *neuron_board_attr_groups[] = {
+       &neuron_board_attr_group,
+       NULL,
+};
+
+const struct attribute_group *neuron_gpio_di_attr_groups[] = {
+       &neuron_gpio_di_attr_group,
+       NULL,
+};
+
+const struct attribute_group *neuron_gpio_do_attr_groups[] = {
+       &neuron_gpio_do_attr_group,
+       NULL,
+};
+
+const struct attribute_group *neuron_gpio_ro_attr_groups[] = {
+       &neuron_gpio_ro_attr_group,
+       NULL,
+};
diff --git a/modules/unipi/src/unipi_sysfs.h b/modules/unipi/src/unipi_sysfs.h
new file mode 100644 (file)
index 0000000..72ae365
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_SYSFS_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_SYSFS_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+#include "unipi_common.h"
+#include "unipi_platform.h"
+
+extern const struct attribute_group neuron_stm_ai_group;
+extern const struct attribute_group neuron_stm_ao_group;
+extern const struct attribute_group neuron_sec_ai_group;
+extern const struct attribute_group neuron_sec_ao_group;
+
+extern const struct attribute_group *neuron_plc_attr_groups[];
+extern const struct attribute_group *neuron_board_attr_groups[];
+extern const struct attribute_group *neuron_gpio_di_attr_groups[];
+extern const struct attribute_group *neuron_gpio_do_attr_groups[];
+extern const struct attribute_group *neuron_gpio_ro_attr_groups[];
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_SYSFS_H_ */
diff --git a/modules/unipi/src/unipi_uart.c b/modules/unipi/src/unipi_uart.c
new file mode 100644 (file)
index 0000000..ed549f0
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+/************
+ * Includes *
+ ************/
+
+#include "unipi_uart.h"
+#include "unipi_spi.h"
+
+/********************
+ * Data Definitions *
+ ********************/
+
+struct neuronspi_uart_data* neuronspi_uart_glob_data;
+unsigned long neuronspi_lines;
+struct uart_driver* neuronspi_uart;
+
+/************************
+ * Non-static Functions *
+ ************************/
+
+void neuronspi_uart_tx_proc(struct kthread_work *ws)
+{
+       struct neuronspi_port *port = to_neuronspi_port(ws, tx_work);
+
+       if ((port->port.rs485.flags & SER_RS485_ENABLED) &&
+           (port->port.rs485.delay_rts_before_send > 0)) {
+               msleep(port->port.rs485.delay_rts_before_send);
+       }
+
+       neuronspi_uart_handle_tx(port);
+}
+
+u32 neuronspi_uart_tx_empty(struct uart_port *port)
+{
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: UART TX Empty\n");
+#endif
+       return TIOCSER_TEMT;
+}
+
+u32 neuronspi_uart_get_mctrl(struct uart_port *port)
+{
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: UART MCTRL Get\n");
+#endif
+       return TIOCM_DSR | TIOCM_CAR;
+}
+
+int    neuronspi_uart_ioctl (struct uart_port *port, unsigned int ioctl_code, unsigned long ioctl_arg)
+{
+       u8 *inp_buf, *outp_buf;
+       int write_length;
+       struct neuronspi_port *n_port;
+       struct spi_device *spi;
+       struct neuronspi_driver_data *n_spi;
+       n_port = to_neuronspi_port(port, port);
+       spi = neuronspi_s_dev[n_port->dev_index];
+       n_spi = spi_get_drvdata(spi);
+       switch (ioctl_code) {
+       case TIOCSETD: {
+               printk(KERN_INFO "NEURONSPI: IOCTL TIOCSETD (processed via set_termios)\n");
+               return 1;
+       }
+       case 0x5480: {
+               printk(KERN_INFO "NEURONSPI: IOCTL 0x5480\n");
+               write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_TIMEOUT_REGISTER, &inp_buf, &outp_buf, (ioctl_arg * 1000000) / n_port->baud);
+               neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
+               return 1;
+       }
+       case 0x5481: {
+               printk(KERN_INFO "NEURONSPI: IOCTL 0x5481\n");
+               write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_TIMEOUT_REGISTER, &inp_buf, &outp_buf, ioctl_arg);
+               neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
+               return 1;
+       }
+       default: {
+               return 0;
+       }
+       }
+}
+
+void neuronspi_uart_set_parmrk(struct uart_port *port, int to)
+{
+       u8 *inp_buf, *outp_buf;
+       int write_length;
+       struct neuronspi_port *n_port;
+       struct spi_device *spi;
+       struct neuronspi_driver_data *n_spi;
+       n_port = to_neuronspi_port(port, port);
+       spi = neuronspi_s_dev[n_port->dev_index];
+       n_spi = spi_get_drvdata(spi);
+       printk(KERN_INFO "NEURONSPI: SET PARMRK to %d\n", to);
+       write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_IFLAGS_REGISTER, &inp_buf, &outp_buf, to);
+       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
+}
+
+void neuronspi_uart_set_ldisc(struct uart_port *port, struct ktermios *kterm)
+{
+       u8 *inp_buf, *outp_buf;
+       int write_length;
+       struct neuronspi_port *n_port;
+       struct spi_device *spi;
+       struct neuronspi_driver_data *n_spi;
+       n_port = to_neuronspi_port(port, port);
+       spi = neuronspi_s_dev[n_port->dev_index];
+       n_spi = spi_get_drvdata(spi);
+       printk(KERN_INFO "NEURONSPI: PROFIBUS discipline set\n");
+       write_length = neuronspi_spi_compose_single_register_write(NEURONSPI_UART_LDISC_REGISTER, &inp_buf, &outp_buf, kterm->c_line);
+       neuronspi_spi_send_message(spi, inp_buf, outp_buf, write_length, n_spi->ideal_frequency, 25, 1);
+}
+
+void neuronspi_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+{
+       struct neuronspi_port *n_port;
+       n_port = to_neuronspi_port(port, port);
+       if (old && old->c_iflag && old->c_iflag != termios->c_iflag) {
+               printk(KERN_INFO "NEURONSPI: c_iflag termios:%d\n", termios->c_iflag);
+       }
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: TERMIOS Set, p:%d, c_cflag:%x\n", port->line, termios->c_cflag);
+#endif
+       neuronspi_spi_uart_set_cflag(neuronspi_s_dev[n_port->dev_index], n_port->dev_port, termios->c_cflag);
+       if (old && termios && (old->c_iflag & PARMRK) != (termios->c_iflag & PARMRK)) {
+               if (termios->c_iflag & PARMRK) {
+                       neuronspi_uart_set_parmrk(port, 1);
+               } else {
+                       neuronspi_uart_set_parmrk(port, 0);
+               }
+       }
+       if (old && termios && old->c_line != termios->c_line) {
+               if (termios->c_line == N_PROFIBUS_FDL) {
+                       printk(KERN_INFO "NEURONSPI: Line Discipline change/n");
+                       neuronspi_uart_set_ldisc(port, termios);
+               }
+       }
+       n_port->baud = uart_get_baud_rate(port, termios, old, 2400, 115200);
+       uart_update_timeout(port, termios->c_cflag, n_port->baud);
+}
+
+s32 neuronspi_uart_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+{
+       port->rs485 = *rs485;
+       return 0;
+}
+
+const char* neuronspi_uart_type(struct uart_port *port)
+{
+       return port->type == PORT_NEURONSPI ? "NEURONSPI_NAME" : NULL;
+}
+
+s32 neuronspi_uart_request_port(struct uart_port *port)
+{
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: Requested port %d\n", port->line);
+#endif
+       return 0;
+}
+
+void neuronspi_uart_fifo_read(struct uart_port *port, u32 rxlen)
+{
+       struct neuronspi_port *s = to_neuronspi_port(port,port);
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(neuronspi_s_dev[s->dev_index]);
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: FIFO Read len:%d\n", rxlen);
+#endif
+    memcpy(s->buf, d_data->uart_buf, rxlen);
+}
+
+void neuronspi_uart_fifo_write(struct neuronspi_port *port, u8 to_send)
+{
+       s32 i;
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: FIFO Write to_send:%d\n", to_send);
+#endif
+       for (i = 0; i < to_send; i++) {
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_INFO "NEURONSPI: UART Char Send: %x\n", port->buf[i]);
+#endif
+       }
+    neuronspi_spi_uart_write(neuronspi_s_dev[port->dev_index], port->buf, to_send, port->dev_port);
+}
+
+s32 neuronspi_uart_alloc_line(void)
+{
+       s32 i;
+       BUILD_BUG_ON(NEURONSPI_MAX_DEVS > BITS_PER_LONG);
+
+       for (i = 0; i < NEURONSPI_MAX_DEVS; i++)
+               if (!test_and_set_bit(i, &neuronspi_lines))
+                       break;
+
+       return i;
+}
+
+void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir)
+{
+       u32 ch, flag, bytes_read, i;
+       while (rxlen) {
+
+               neuronspi_uart_fifo_read(&port->port, rxlen);
+               bytes_read = rxlen;
+
+               port->port.icount.rx++;
+               flag = TTY_NORMAL;
+
+               for (i = 0; i < bytes_read; ++i) {
+#if NEURONSPI_DETAILED_DEBUG > 0
+                       printk(KERN_INFO "NEURONSPI: UART Insert Char:%x\n", port->buf[i]);
+#endif
+                       ch = port->buf[i];
+                       if (uart_handle_sysrq_char(port, ch))
+                               continue;
+
+                       uart_insert_char(&port->port, 0, 0, ch, flag);
+               }
+               rxlen -= bytes_read;
+       }
+
+       tty_flip_buffer_push(&port->port.state->port);
+}
+
+void neuronspi_uart_handle_tx(struct neuronspi_port *port)
+{
+       u32 txlen, to_send, i;
+       struct spi_device *spi;
+       struct neuronspi_driver_data *d_data;
+       struct circ_buf *xmit;
+
+       spi = neuronspi_s_dev[port->dev_index];
+       d_data = spi_get_drvdata(spi);
+       xmit = &port->port.state->xmit;
+
+       if (unlikely(port->port.x_char)) {
+               neuronspi_spi_uart_write(spi, &port->port.x_char, 1, port->dev_port);
+               port->port.icount.tx++;
+               port->port.x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&port->port)) {
+               return;
+       }
+
+       /* Get length of data pending in circular buffer */
+       to_send = uart_circ_chars_pending(xmit);
+       if (likely(to_send)) {
+               /* Limit to size of TX FIFO */
+               txlen = NEURONSPI_FIFO_SIZE;
+               to_send = (to_send > txlen) ? txlen : to_send;
+
+               /* Add data to send */
+               port->port.icount.tx += to_send;
+
+               /* Convert to linear buffer */
+               for (i = 0; i < to_send; ++i) {
+                       port->buf[i] = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               }
+
+               neuronspi_uart_fifo_write(port, to_send);
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+               uart_write_wakeup(&port->port);
+       }
+}
+
+void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno)
+{
+       struct neuronspi_port *n_port = &uart_data->p[portno];
+       struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+       u8 *send_buf = kzalloc(NEURONSPI_UART_PROBE_MESSAGE_LEN, GFP_KERNEL);
+       u8 *recv_buf = kzalloc(NEURONSPI_UART_PROBE_MESSAGE_LEN, GFP_KERNEL);
+       memcpy(send_buf, NEURONSPI_UART_PROBE_MESSAGE, NEURONSPI_UART_PROBE_MESSAGE_LEN);
+       neuronspi_spi_send_message(spi, send_buf, recv_buf, NEURONSPI_UART_PROBE_MESSAGE_LEN, NEURONSPI_DEFAULT_FREQ, 25, 1);
+       kfree(send_buf);
+       kfree(recv_buf);
+}
+
+void neuronspi_uart_ist(struct kthread_work *ws)
+{
+       struct neuronspi_port *p = to_neuronspi_port(ws, irq_work);
+       neuronspi_uart_handle_irq(p->parent, p->line);
+}
+
+void neuronspi_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_NEURONSPI;
+       }
+}
+
+s32 neuronspi_uart_verify_port(struct uart_port *port,
+                                struct serial_struct *s)
+{
+       if ((s->type != PORT_UNKNOWN) && (s->type != PORT_NEURONSPI))
+               return -EINVAL;
+       if (s->irq != port->irq)
+               return -EINVAL;
+
+       return 0;
+}
+
+void neuronspi_uart_pm(struct uart_port *port, u32 state, u32 oldstate)
+{
+       neuronspi_uart_power(port, (state == UART_PM_STATE_ON) ? 1 : 0);
+}
+
+s32 neuronspi_uart_probe(struct spi_device* dev, u8 device_index)
+{
+       struct neuronspi_driver_data* driver_data = spi_get_drvdata(dev);
+       struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
+       s32 i, j, ret, new_uart_count;
+       struct neuronspi_uart_data *uart_data = driver_data->uart_data;
+
+       if (uart_data->p == NULL) {
+               uart_data->p = kzalloc(sizeof(struct neuronspi_port[NEURONSPI_MAX_UART]), GFP_KERNEL);
+               for (i = 0; i < NEURONSPI_MAX_UART; i++) {
+                       uart_data->p[i].parent = uart_data;
+               }
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_DEBUG "NEURONSPI: Allocated port structure for %d potential UART devices\n", NEURONSPI_MAX_UART);
+#endif
+       }
+
+       new_uart_count = driver_data->uart_count + uart_data->p_count;
+
+       // Initialise port data
+       for (i = uart_data->p_count; i < new_uart_count; i++) {
+               uart_data->p[i].dev_index = device_index;
+               uart_data->p[i].dev_port = i - uart_data->p_count;
+               uart_data->p[i].line            = i;
+               uart_data->p[i].port.dev        = &(dev->dev);
+               uart_data->p[i].port.irq        = dev->irq;
+               uart_data->p[i].port.type       = PORT_NEURONSPI;
+               uart_data->p[i].port.fifosize   = NEURONSPI_FIFO_SIZE;
+               uart_data->p[i].port.flags      = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+               uart_data->p[i].port.iotype     = UPIO_PORT;
+               uart_data->p[i].port.uartclk    = 9600;
+               uart_data->p[i].port.rs485_config = neuronspi_uart_config_rs485;
+               uart_data->p[i].port.ops        = &neuronspi_uart_ops;
+               uart_data->p[i].port.line       = neuronspi_uart_alloc_line();
+               spin_lock_init(&uart_data->p[i].port.lock);
+               if (uart_data->p[i].port.line >= NEURONSPI_MAX_DEVS) {
+                       ret = -ENOMEM;
+               }
+               kthread_init_work(&(uart_data->p[i].tx_work), neuronspi_uart_tx_proc);
+               kthread_init_work(&(uart_data->p[i].rx_work), neuronspi_uart_rx_proc);
+               kthread_init_work(&(uart_data->p[i].irq_work), neuronspi_uart_ist);
+               uart_add_one_port(driver_data->serial_driver, &uart_data->p[i].port);
+               printk(KERN_INFO "NEURONSPI: Added UART port %d\n", i);
+       }
+
+       // For ports on multiple SPI devices renumber the ports to correspond to SPI chip-select numbering
+       if (uart_data->p_count) {
+               // First remove all existing ports
+               for (i = 0; i < new_uart_count; i++) {
+                       uart_remove_one_port(driver_data->serial_driver, &uart_data->p[i].port);
+                       clear_bit(uart_data->p[i].port.line, &neuronspi_lines);
+                       kthread_flush_worker(&uart_data->kworker);
+               }
+               // Now add the ports in the correct order
+               for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
+                       if (neuronspi_s_dev[i] != NULL) {
+                               driver_data = spi_get_drvdata(neuronspi_s_dev[i]);
+#if NEURONSPI_DETAILED_DEBUG > 0
+                               printk(KERN_DEBUG "NEURONSPI: Renumber not NULL %d UC:%d\n", i, driver_data->uart_count);
+#endif
+                               if (driver_data->uart_count) {
+                                       for (j = 0; j < new_uart_count; j++) {
+                                               if (uart_data->p[j].dev_index == i) {
+                                                       uart_data->p[j].port.dev        = &(neuronspi_s_dev[i]->dev);
+                                                       uart_data->p[j].port.irq        = neuronspi_s_dev[i]->irq;
+                                                       uart_data->p[j].port.type       = PORT_NEURONSPI;
+                                                       uart_data->p[j].port.fifosize   = NEURONSPI_FIFO_SIZE;
+                                                       uart_data->p[j].port.flags      = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+                                                       uart_data->p[j].port.iotype     = UPIO_PORT;
+                                                       uart_data->p[j].port.uartclk    = 9800;
+                                                       uart_data->p[j].port.rs485_config = neuronspi_uart_config_rs485;
+                                                       uart_data->p[j].port.ops        = &neuronspi_uart_ops;
+                                                       uart_data->p[j].port.line       = neuronspi_uart_alloc_line();
+                                                       uart_add_one_port(driver_data->serial_driver, &uart_data->p[j].port);
+#if NEURONSPI_DETAILED_DEBUG > 0
+                                                       printk(KERN_DEBUG "NEURONSPI: Added UART port %d\n", j);
+#endif
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       uart_data->p_count = new_uart_count;
+       if (uart_data->kworker_task == NULL) {
+#if NEURONSPI_DETAILED_DEBUG > 0
+               printk(KERN_DEBUG "NEURONSPI: KWorker Task is NULL\n");
+#endif
+
+               kthread_init_worker(&uart_data->kworker);
+
+               uart_data->kworker_task = kthread_run(kthread_worker_fn, &uart_data->kworker,
+                                                 "neuronspi");
+               if (IS_ERR(uart_data->kworker_task)) {
+                       ret = PTR_ERR(uart_data->kworker_task);
+               }
+               sched_setscheduler(uart_data->kworker_task, SCHED_FIFO, &sched_param);
+       }
+       return ret;
+}
+
+s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data)
+{
+       struct neuronspi_driver_data *d_data;
+       struct spi_device *spi;
+       s32 i;
+
+       for (i = 0; i < NEURONSPI_MAX_DEVS; i++) {
+               if (!(neuronspi_s_dev[i] == NULL)) {
+                       spi = neuronspi_s_dev[i];
+                       d_data = spi_get_drvdata(spi);
+                       if (d_data->poll_thread != NULL) {
+                               kthread_stop(d_data->poll_thread);
+                       }
+               }
+       }
+       for (i = 0; i < u_data->p_count; i++) {
+               uart_remove_one_port(neuronspi_uart, &u_data->p[i].port);
+               clear_bit(u_data->p[i].port.line, &neuronspi_lines);
+               neuronspi_uart_power(&u_data->p[i].port, 0);
+       }
+
+       kthread_flush_worker(&u_data->kworker);
+       return 0;
+}
+
+void neuronspi_uart_rx_proc(struct kthread_work *ws)
+{
+       s32 end_flag = 0;
+       s32 read_count = 0;
+       struct neuronspi_port *n_port = to_neuronspi_port(ws, rx_work);
+       struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+
+       u8 *send_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
+       u8 *recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_KERNEL);
+
+       mutex_lock(&neuronspi_master_mutex);
+       read_count = d_data->uart_read;
+       mutex_unlock(&neuronspi_master_mutex);
+
+       while (!end_flag) {
+               memset(recv_buf, 0, NEURONSPI_BUFFER_MAX);
+               neuronspi_spi_uart_read(spi, send_buf, recv_buf, read_count, n_port->dev_port);
+               if (recv_buf[6] == 0x65 && recv_buf[7] > 0) {
+                       mutex_lock(&neuronspi_master_mutex);
+                       memcpy(&d_data->uart_buf[0], &recv_buf[10], recv_buf[7]);
+                       neuronspi_uart_handle_rx(n_port, recv_buf[7], 1);
+                       read_count = recv_buf[9];
+                       mutex_unlock(&neuronspi_master_mutex);
+               } else if (recv_buf[0] != 0x41) {
+                       mutex_lock(&neuronspi_master_mutex);
+                       d_data->uart_read = 0;
+                       end_flag = 1;
+                       mutex_unlock(&neuronspi_master_mutex);
+               }
+       }
+       kfree(recv_buf);
+       kfree(send_buf);
+}
+
+void neuronspi_uart_start_tx(struct uart_port *port)
+{
+       struct neuronspi_port *n_port = to_neuronspi_port(port,port);
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_INFO "NEURONSPI: Start TX\n");
+#endif
+       kthread_queue_work(&n_port->parent->kworker, &n_port->tx_work);
+}
+
+s32 neuronspi_uart_poll(void *data)
+{
+       struct neuronspi_driver_data *d_data = (struct neuronspi_driver_data*) data;
+       struct neuronspi_uart_data *u_data;
+       s32 i;
+       while (!kthread_should_stop()) {
+               usleep_range(2000,8000);
+               if (d_data->uart_count) {
+                       u_data = d_data->uart_data;
+                       for (i = 0; i < u_data->p_count; i++) {
+                               if (u_data->p[i].dev_index == d_data->neuron_index) {
+                                       kthread_queue_work(&u_data->kworker, &u_data->p[i].irq_work);
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+// Initialise the driver
+s32 neuronspi_uart_startup(struct uart_port *port)
+{
+       struct neuronspi_port *n_port = to_neuronspi_port(port, port);
+       struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+       neuronspi_spi_set_irqs(spi, 0x5);
+       if (d_data->poll_thread != NULL) {
+               wake_up_process(d_data->poll_thread);
+       } else if (d_data->no_irq) {
+               d_data->poll_thread = kthread_create(neuronspi_uart_poll, (void *)d_data, "UART_poll_thread");
+       }
+       neuronspi_uart_power(port, 1);
+       // TODO: /* Reset FIFOs*/
+#if NEURONSPI_DETAILED_DEBUG > 0
+       printk(KERN_DEBUG "NEURONSPI: UART Startup\n");
+#endif
+       return 0;
+}
+
+void neuronspi_uart_shutdown(struct uart_port *port)
+{
+    neuronspi_uart_power(port, 0);
+}
+
+/*******************
+ * Empty functions *
+ *******************/
+
+void neuronspi_uart_stop_tx(struct uart_port *port)
+{
+       /* Do Nothing */
+}
+
+void neuronspi_uart_stop_rx(struct uart_port *port)
+{
+       /* Do Nothing */
+}
+void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl)
+{
+       /* Do Nothing */
+}
+void neuronspi_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       /* Do Nothing */
+}
+void neuronspi_uart_power(struct uart_port *port, s32 on)
+{
+    /* Do nothing */
+}
+void neuronspi_uart_null_void(struct uart_port *port)
+{
+       /* Do nothing */
+}
diff --git a/modules/unipi/src/unipi_uart.h b/modules/unipi/src/unipi_uart.h
new file mode 100644 (file)
index 0000000..81a702d
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * UniPi Neuron tty serial driver - Copyright (C) 2018 UniPi Technologies
+ * Author: Tomas Knot <tomasknot@gmail.com>
+ *
+ *  Based on the SC16IS7xx driver by Jon Ringle <jringle@gridpoint.com>,
+ *  which was in turn based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.
+ *
+ */
+
+#ifndef MODULES_NEURON_SPI_SRC_UNIPI_UART_H_
+#define MODULES_NEURON_SPI_SRC_UNIPI_UART_H_
+
+/************
+ * Includes *
+ ************/
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <uapi/linux/iio/types.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
+#include <linux/leds.h>
+#include <linux/uaccess.h>
+#include <asm/termbits.h>
+#include <asm/gpio.h>
+
+#include "unipi_common.h"
+#include "unipi_platform.h"
+
+/***************
+ * Definitions *
+ ***************/
+
+#define NEURONSPI_UART_IFLAGS_REGISTER         502
+#define NEURONSPI_UART_LDISC_REGISTER  503
+#define NEURONSPI_UART_TIMEOUT_REGISTER 504
+
+/*************************
+ * Function Declarations *
+ *************************/
+
+void neuronspi_uart_start_tx(struct uart_port *port);
+void neuronspi_uart_stop_tx(struct uart_port *port);
+void neuronspi_uart_stop_rx(struct uart_port *port);
+void neuronspi_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old);
+u32 neuronspi_uart_tx_empty(struct uart_port *port);
+void neuronspi_uart_break_ctl(struct uart_port *port, int break_state);
+void neuronspi_uart_shutdown(struct uart_port *port);
+s32 neuronspi_uart_startup(struct uart_port *port);
+s32 neuronspi_uart_request_port(struct uart_port *port);
+s32 neuronspi_uart_alloc_line(void);
+void neuronspi_uart_set_mctrl(struct uart_port *port, u32 mctrl);
+int    neuronspi_uart_ioctl (struct uart_port *port, unsigned int ioctl_code, unsigned long ioctl_arg);
+void neuronspi_uart_set_ldisc(struct uart_port *port, struct ktermios *kterm);
+u32 neuronspi_uart_get_mctrl(struct uart_port *port);
+const char *neuronspi_uart_type(struct uart_port *port);
+void neuronspi_uart_null_void(struct uart_port *port);
+void neuronspi_uart_config_port(struct uart_port *port, int flags);
+s32 neuronspi_uart_verify_port(struct uart_port *port, struct serial_struct *s);
+void neuronspi_uart_pm(struct uart_port *port, u32 state,  u32 oldstate);
+s32 neuronspi_uart_poll(void *data);
+s32 neuronspi_uart_probe(struct spi_device* dev, u8 device_index);
+s32 neuronspi_uart_remove(struct neuronspi_uart_data *u_data);
+void neuronspi_uart_power(struct uart_port *port, s32 on);
+s32 neuronspi_uart_config_rs485(struct uart_port *port, struct serial_rs485 *rs485);
+void neuronspi_spi_uart_set_cflag(struct spi_device* spi_dev, u8 port, u32 to);
+u32 neuronspi_spi_uart_get_cflag(struct spi_device* spi_dev, u8 port);
+void neuronspi_uart_fifo_write(struct neuronspi_port *port, u8 to_send);
+void neuronspi_uart_fifo_read(struct uart_port *port, u32 rxlen);
+void neuronspi_uart_rx_proc(struct kthread_work *ws);
+void neuronspi_uart_tx_proc(struct kthread_work *ws);
+void neuronspi_uart_ist(struct kthread_work *ws);
+void neuronspi_uart_handle_tx(struct neuronspi_port *port);
+void neuronspi_uart_handle_rx(struct neuronspi_port *port, u32 rxlen, u32 iir);
+void neuronspi_uart_handle_irq(struct neuronspi_uart_data *uart_data, u32 portno);
+
+/*********************
+ * Data Declarations *
+ *********************/
+
+extern struct neuronspi_uart_data* neuronspi_uart_glob_data;
+extern unsigned long neuronspi_lines;
+extern struct uart_driver* neuronspi_uart;
+
+static const struct uart_ops neuronspi_uart_ops =
+{
+       .tx_empty                       = neuronspi_uart_tx_empty,
+       .set_mctrl                      = neuronspi_uart_set_mctrl,
+       .get_mctrl                      = neuronspi_uart_get_mctrl,
+       .stop_tx                        = neuronspi_uart_stop_tx,
+       .start_tx                       = neuronspi_uart_start_tx,
+       .stop_rx                        = neuronspi_uart_stop_rx,
+       .break_ctl                      = neuronspi_uart_break_ctl,
+       .startup                        = neuronspi_uart_startup,
+       .shutdown                       = neuronspi_uart_shutdown,
+       .set_termios            = neuronspi_uart_set_termios,
+       .set_ldisc                      = neuronspi_uart_set_ldisc,
+       .type                           = neuronspi_uart_type,
+       .request_port           = neuronspi_uart_request_port,
+       .release_port           = neuronspi_uart_null_void,
+       .config_port            = neuronspi_uart_config_port,
+       .verify_port            = neuronspi_uart_verify_port,
+       .pm                                     = neuronspi_uart_pm,
+       .ioctl                          = neuronspi_uart_ioctl,
+};
+
+#endif /* MODULES_NEURON_SPI_SRC_UNIPI_UART_H_ */