rework spi to use async calling and RT kthread
authorMiroslav Ondra <ondra@faster.cz>
Wed, 27 Mar 2019 15:49:22 +0000 (16:49 +0100)
committerMiroslav Ondra <ondra@faster.cz>
Wed, 27 Mar 2019 15:49:22 +0000 (16:49 +0100)
debian/changelog
debian/neuron-kernel.changelog
modules/unipi/src/unipi_common.h
modules/unipi/src/unipi_iio.c
modules/unipi/src/unipi_platform.c
modules/unipi/src/unipi_platform.h
modules/unipi/src/unipi_spi.c
modules/unipi/src/unipi_spi.h
modules/unipi/src/unipi_uart.c
modules/unipi/src/unipi_uart.h

index 61da8c200df7e041a87d281724b9b4c90090ff06..393998b6fa3d7ebe33bca1903ced4c2382e00d33 100644 (file)
@@ -1,3 +1,9 @@
+unipi-kernel-modules (1.21) unstable; urgency=medium
+
+  * rework spi to use async calling and RT kthread
+
+ -- Miroslav Ondra <bokula@bokula.faster.cz>  Wed, 27 Mar 2019 16:43:52 +0100
+
 unipi-kernel-modules (1.20) unstable; urgency=medium
 
   * fix line discipline setting on standard uarts
index 84ace888117bab8348d8fb015869afa525895eb4..03f3552c9a52f0adb17fc4619ff07673f552491a 100644 (file)
@@ -1,3 +1,15 @@
+unipi-kernel-modules (1.21.1.20190215-1) unstable; urgency=medium
+
+  * Compiled for raspberrypi-kernel 1.20190215-1
+
+ -- Miroslav Ondra <bokula@bokula.faster.cz>  Wed, 27 Mar 2019 16:42:04 +0100
+
+unipi-kernel-modules (1.21) UNRELEASED; urgency=medium
+
+  * rework spi to use async calling and RT kthread
+
+ -- Miroslav Ondra <bokula@bokula.faster.cz>  Thu, 21 Feb 2019 14:47:46 +0100
+
 unipi-kernel-modules (1.19.1.20181112-1) unstable; urgency=medium
 
   * Compiled for raspberrypi-kernel 1.20181112-1
index 92b6b88d85f9c4ea4df6bc88ef360d488357529e..cad9e6ece9bae383875dce68b99969297080dba4 100644 (file)
 /***************
  * Definitions *
  ***************/
+//#define UNIPISPI_USE_RX_THREAD
 
 #define NEURONSPI_SCHED_REQUIRED 1 // Older kernels do not require sched/types to be specifically imported
 #if NEURONSPI_SCHED_REQUIRED > 0
        #include <uapi/linux/sched/types.h>
 #endif
-#define NEURONSPI_MAJOR_VERSIONSTRING "Version 1.20:2019:02:05"
+#define NEURONSPI_MAJOR_VERSIONSTRING "Version 1.21:2019:02:20"
 
 #define NEURONSPI_MAX_DEVS                             3
 #define NEURONSPI_MAX_UART                             16
@@ -102,6 +103,11 @@ struct neuronspi_op_buffer
     u8  *second_message;
 };
 
+
+#define CB_WRITESTRING 1
+#define CB_GETTXFIFO  2
+#define START_TX       3
+
 struct neuronspi_port
 {
        struct uart_port                        port;
@@ -109,16 +115,9 @@ struct neuronspi_port
        u8                                                      dev_port;   // index of port on neuronspi device
     struct neuronspi_driver_data  *n_spi;     // shorthand to n_spi 
     
-    spinlock_t                  rx_queue_lock;
-    u8*                         rx_queue_primary;
-    int                         rx_qlen_primary;
-    u8*                         rx_queue_secondary;
-    int                         rx_qlen_secondary;
     u8                          rx_remain;
     
        struct kthread_work                     tx_work;
-       struct kthread_work                     rx_work;
-
     u16                         tx_fifo_reg;  // register in neuronspi device modbus map to read internal tx fifo length
                                               // 0 if undefined
     u16                         tx_fifo_len;  // estimates char count in neuron internal tx fifo
@@ -126,6 +125,20 @@ struct neuronspi_port
 
        s32                                                     baud;
     s64                         one_char_nsec;
+
+    spinlock_t                  rx_in_progress_lock;
+    int                         rx_in_progress;
+    struct neuronspi_op_buffer  rx_send_buf;
+    struct neuronspi_op_buffer  rx_recv_buf;
+    u8                          rx_send_msg[NEURONSPI_FIFO_SIZE+4];
+    u8                          rx_recv_msg[NEURONSPI_FIFO_SIZE+4];
+
+    spinlock_t                  txop_lock;
+    int                         pending_txop;
+    struct neuronspi_op_buffer  tx_send_buf;
+    struct neuronspi_op_buffer  tx_recv_buf;
+    u8                          tx_send_msg[NEURONSPI_FIFO_SIZE+4];
+    u8                          tx_recv_msg[NEURONSPI_FIFO_SIZE+4];
 };
 
 struct neuronspi_uart_data
@@ -164,6 +177,9 @@ struct neuronspi_driver_data
        u16 sysfs_regmap_target;
        u16 sysfs_register_target;
        u16 sysfs_counter_target;
+    
+    //struct neuronspi_op_buffer  idle_recv_buf;
+    cycles_t last_cs_cycles;
 };
 
 
index 59691b9dca7bed8f7ad026c7cce8a9e900437ea0..1eb28207f35118f7e6c289f2bfc52db549740347 100644 (file)
  * NOTE: This function uses 64-bit fixed-point arithmetic,
  * which necessitates using the do_div macro to avoid unnecessary long/long division.
  */
+/*
+ * Convert float32 (low_val:hight_val) to integer value / divider. 
+ *   optionaly multiply value by factor
+*/
+void float2int_with_divider(u16 low_val, u16 high_val, int factor, int* value, int* divider)
+{
+        int exponent;
+        //int i, mask;
+        int preshift = 0;
+        s64 tmp;
+        // exponent can be [-127 .. 128], exp=0 means value in (1 .. 1.999999)
+        // mantisa has 24 bit
+        
+        // calc log2(factor)
+        if (factor > 1) {
+            for (preshift = 30; preshift > 0; preshift--) {
+                if (factor & (1 << preshift)) {
+                    if (factor != (1 << preshift)) preshift++;
+                    break;
+                }
+            }
+        }
+        exponent = (int)((high_val >> 7) & 0xff) - 127 + preshift;
+        if (exponent > 23) { 
+            // value > 16M
+            *value = 1 << 24;
+            *divider = 1;
+        } else if (exponent < -23) {
+            // value is almost zero, set value to 0
+            *value = 0;
+            *divider = 1;
+        } else {
+            *value = (1 << 23) | ((high_val & 0x7f) << 16) | low_val;
+            if ((23 - exponent) < 30) {
+                // shift divider into right position
+                *divider = 1 << (23 - exponent);
+            } else {
+                // set max divider and shift value
+                *divider = 1 << 30;
+                *value = *value >> ((23 - exponent) - 30);
+            }
+            if (preshift) {
+                tmp = *value;
+                *value = (tmp * factor) >> preshift;
+            }
+        }
+        // check and set sign of value
+        if (high_val & 0x8000) *value = -(*value);
+}
+
 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_analog_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 + 1 + (2 * ai_data->index), &sec_ai_val_h);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (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);
-       }
+       u32 float_l;
+       u32 float_h;
 
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &float_l);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index) + 1, &float_h);
+        float2int_with_divider(float_l, float_h, 1000, val, val2);
 }
 
 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)
@@ -56,22 +95,12 @@ void neuronspi_spi_iio_sec_ai_read_current(struct iio_dev *indio_dev, struct iio
        struct neuronspi_analog_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 + 1 + (2 * ai_data->index), &sec_ai_val_h);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (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);
-       }
+       u32 float_l;
+       u32 float_h;
+
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &float_l);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index) + 1, &float_h);
+        float2int_with_divider(float_l, float_h, 1, val, val2);
 }
 
 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)
@@ -79,21 +108,12 @@ void neuronspi_spi_iio_sec_ai_read_resistance(struct iio_dev *indio_dev, struct
        struct neuronspi_analog_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 + 1 + (2 * ai_data->index), &sec_ai_val_h);
-       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (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);
-       }
+       u32 float_l;
+       u32 float_h;
+
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index), &float_l);
+       regmap_read(n_spi->reg_map, n_spi->regstart_table->sec_ai_val_reg + (2 * ai_data->index) + 1, &float_h);
+        float2int_with_divider(float_l, float_h, 1, val, val2);
 }
 
 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)
@@ -404,26 +424,34 @@ int neuronspi_iio_sec_ao_write_raw(struct iio_dev *indio_dev, struct iio_chan_sp
  *****************************************************************/ 
 static const struct iio_info neuronspi_stm_ai_info = {
        .read_raw = neuronspi_iio_stm_ai_read_raw,
+#ifdef UNIPI_USE_DRIVER_MODULE
        .driver_module = THIS_MODULE,
+#endif
        .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,
+#ifdef UNIPI_USE_DRIVER_MODULE
        .driver_module = THIS_MODULE,
+#endif
        .attrs = &neuron_stm_ao_group,
 };
 
 static const struct iio_info neuronspi_sec_ai_info = {
        .read_raw = neuronspi_iio_sec_ai_read_raw,
+#ifdef UNIPI_USE_DRIVER_MODULE
        .driver_module = THIS_MODULE,
+#endif
        .attrs = &neuron_sec_ai_group,
 };
 
 static const struct iio_info neuronspi_sec_ao_info = {
        .write_raw = neuronspi_iio_sec_ao_write_raw,
+#ifdef UNIPI_USE_DRIVER_MODULE
        .driver_module = THIS_MODULE,
+#endif
        .read_raw = neuronspi_iio_sec_ao_read_raw,
        //.attrs = &neuron_sec_ao_group,
 };
index 56dc7fa6b36097265d620e5de3804145404d5088..425b26a60c9810a6da04aaaee760f51120380133 100644 (file)
@@ -1175,9 +1175,9 @@ static u32 NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4
 
 #define NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_FEATURES {   \
                .do_count =                                       0,    \
-               .ro_count =                                       6,    \
+               .ro_count =                                       5,    \
                .ds_count =                                       5,    \
-               .di_count =                                       5,    \
+               .di_count =                                       6,    \
                .led_count =                              0,    \
                .stm_ai_count =                           0,    \
                .stm_ao_count =                           0,    \
@@ -1396,7 +1396,7 @@ static u32 NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4
        .pwm_channel_count =              0,    \
        .wd_count =                               1,    \
        .extension_sys_count =            0,    \
-       .light_count =                            4,    \
+       .light_count =                            0,    \
        .owire_count =                            0,    \
 }
 
@@ -1412,6 +1412,175 @@ static u32 NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4
 }
 struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_DEFINITION};
 
+// E-4Ai4Ao_P-4Di5Ro (xS5x) 
+#define NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_DEFINITION_BLOCK_SIZE 50
+static u32 NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 23,  // 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
+               1000, 23, // 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_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_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                              // 1017
+               NEURONSPI_REGFUN_AI_VER2_MODE | 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_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC,                                                                             // 1021
+               NEURONSPI_REGFUN_RS485_ADDRESS | NEURONSPI_REGFLAG_ACC_6SEC                                                                             // 1022
+};
+
+#define NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_FEATURES {   \
+               .do_count =                                       0,    \
+               .ro_count =                                       5,    \
+               .ds_count =                                       4,    \
+               .di_count =                                       4,    \
+               .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_E4AI4AOP4DI5RO_HW_DEFINITION { \
+               .combination_board_id =         18, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_P4DI5RO_ID, \
+               .name_length =                          17, \
+               .combination_name =                     "E_4Ai4Ao_P_4Di5Ro", \
+               .block_count =                          NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_DEFINITION};
+
+// E-4Ai4Ao_U-4Di5Ro (L5x3)
+#define NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_DEFINITION_BLOCK_SIZE 50
+static u32 NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_DEFINITION_BLOCK[NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_DEFINITION_BLOCK_SIZE] = {
+               0, 24,  // 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
+               1000, 22, // 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_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_AI_VER2_MODE | NEURONSPI_REGFLAG_ACC_1HZ,                                                                                              // 1017
+               NEURONSPI_REGFUN_AI_VER2_MODE | 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_RS485_CONFIG | NEURONSPI_REGFLAG_ACC_6SEC                                                                                              // 1021
+};
+
+#define NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_FEATURES {   \
+       .do_count =                                       0,    \
+       .ro_count =                                       5,    \
+       .ds_count =                                       5,    \
+       .di_count =                                       4,    \
+       .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_E4AI4AOU4DI5RO_HW_DEFINITION { \
+               .combination_board_id =         15, \
+               .lower_board_id =                       NEURONSPI_BOARD_LOWER_E4AI4AO_ID, \
+               .upper_board_id =                       NEURONSPI_BOARD_UPPER_U4DI5RO_ID, \
+               .name_length =                          17, \
+               .combination_name =                     "E_4Ai4Ao_U_4Di5Ro", \
+               .block_count =                          NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_DEFINITION_BLOCK_SIZE, \
+               .blocks =                                       NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_DEFINITION_BLOCK, \
+               .features =                                     NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_FEATURES \
+}
+struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_COMBINATION[] = {NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_DEFINITION};
+
+
 /********************
  * Data Definitions *
  ********************/
@@ -1564,7 +1733,11 @@ struct neuronspi_board_entry NEURONSPI_BOARDTABLE[NEURONSPI_BOARDTABLE_LEN] = {
        {.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)
+                       .data_register_count = 28, .config_register_count = 24,   .definition = NEURONSPI_BOARD_E4AI4AOU6DI5RO_HW_COMBINATION},         // E-4Ai4Ao_U-6Di5Ro (M503)
+       {.index = 16, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_P4DI5RO_ID,
+                       .data_register_count = 23, .config_register_count = 23,   .definition = NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_COMBINATION},         // E-4Ai4Ao_P-4Di5Ro (xS5x)
+       {.index = 17, .lower_board_id = NEURONSPI_BOARD_LOWER_E4AI4AO_ID,       .upper_board_id = NEURONSPI_BOARD_UPPER_U4DI5RO_ID,
+                       .data_register_count = 24, .config_register_count = 22,   .definition = NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_COMBINATION}          // E-4Ai4Ao_U-4Di5Ro (M5x3)
 };
 
 // Module table
index 6f3def29cacb5d08fc6044bcbcb7be4710606cc4..9fe26703304588e558d656b0399b3777049c6234 100644 (file)
@@ -171,6 +171,8 @@ struct neuronspi_board_device_data {
 #define NEURONSPI_BOARD_UPPER_U14DI_ID         3
 #define NEURONSPI_BOARD_UPPER_P6DI5RO_ID       4
 #define NEURONSPI_BOARD_UPPER_U6DI5RO_ID       5
+#define NEURONSPI_BOARD_UPPER_P4DI5RO_ID       6
+#define NEURONSPI_BOARD_UPPER_U4DI5RO_ID       7
 
 // Register function codes
 // Digital Input Functions
@@ -291,6 +293,8 @@ extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP6DI5RO_HW_COMB
 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)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOP4DI5RO_HW_COMBINATION[];             // E-4Ai4Ao_P-4Di5Ro (xS5?)
+extern struct neuronspi_board_combination NEURONSPI_BOARD_E4AI4AOU4DI5RO_HW_COMBINATION[];             // E-4Ai4Ao_U-4Di5Ro (L5?3)
 
 // Model Definitions
 #define NEURONSPI_MODEL_S103_HW_DEFINITION_BOARD_SIZE 1
@@ -351,7 +355,7 @@ extern struct neuronspi_board_combination NEURONSPI_MODEL_L205_HW_DEFINITION_BOA
 extern struct neuronspi_board_combination NEURONSPI_MODEL_L505_HW_DEFINITION_BOARD[NEURONSPI_MODEL_L505_HW_DEFINITION_BOARD_SIZE];
 
 // Board table
-#define NEURONSPI_BOARDTABLE_LEN               16
+#define NEURONSPI_BOARDTABLE_LEN               18
 extern struct neuronspi_board_entry NEURONSPI_BOARDTABLE[];
 
 // Module table
index 2dfb1e247906f48b9fe72449e2c52b7e5edaeb47..d5e0d1170ce8bc1428ffda84793d7044efcf7b25 100644 (file)
@@ -17,6 +17,8 @@
 /************
  * Includes *
  ************/
+#include <linux/completion.h>
+#include <linux/cpufreq.h>
 
 #include "unipi_common.h"
 #include "unipi_sysfs.h"
@@ -26,6 +28,7 @@
 #include "unipi_iio.h"
 #include "unipi_misc.h"
 #include "unipi_spi.h"
+#include "unipi_uart.h"
 #include "unipi_tty.h"
 
 /* using trace_printk or printk ???*/
@@ -57,7 +60,8 @@ struct neuronspi_char_driver
 };
 
 
-struct mutex neuronspi_master_mutex;
+//struct mutex neuronspi_master_mutex;
+spinlock_t   unipi_spi_master_lock;
 struct mutex unipi_inv_speed_mutex;
 int neuronspi_model_id = -1;
 struct spi_device *neuronspi_s_dev[NEURONSPI_MAX_DEVS];  // global list of neuron spi devices
@@ -84,115 +88,261 @@ struct neuronspi_file_data
        u8                                      has_first_message;
 };
 
+
+#define UNIPISPI_PROBE_MESSAGE_LEN     16
+static u8 _probe_message_second[UNIPISPI_PROBE_MESSAGE_LEN] = 
+{   0x04, 0x00, 0xe8, 0x03, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x12, 0x16
+};
+
+static struct neuronspi_op_buffer UNIPISPI_PROBE_MESSAGE = {
+    first_message: {0x04, 0x0e, 0xe8, 0x03, 0xa0, 0xdd},
+    second_message: _probe_message_second,
+};
+
+
+static struct neuronspi_op_buffer UNIPISPI_IDLE_MESSAGE = {
+    first_message: {0xfa, 0x00, 0x55, 0x0e, 0xb6, 0x0a},
+    second_message: NULL,
+};
+
+
+/************************************************************
+
+  patches to other modules
+               - chip select on spi - monitor elpapsed time between operations
+               - cpu frequency setting - try to suppress changing freq during spi op
+
+***********************************************************/
+
+
+    static unsigned long loop_per_us = 24; 
+    u16 unipi_spi_master_flag = 0;
+    void (*unipi_spi_master_set_cs)(struct spi_device *spi, bool enable) = NULL;
+    //cycles_t unipi_spi_cs_cycles;
+       static struct cpufreq_policy * current_policy = NULL;
+
+static void unipi_spi_set_cs(struct spi_device *spi, bool enable)
+{
+    unsigned long udelta;
+    struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+    //if ((d_data->neuron_index < NEURONSPI_MAX_DEVS) && (neuronspi_s_dev[d_data->neuron_index] == spi)) {
+    //  
+    //}
+    cycles_t cs_cycles = get_cycles();
+    if (!enable && d_data) {
+        udelta = ((cs_cycles - d_data->last_cs_cycles) / loop_per_us);
+        unipi_spi_trace(KERN_INFO "UNIPISPI: enable=%d csdelta:%ld us\n", !enable, udelta);
+        if (udelta < NEURONSPI_LAST_TRANSFER_DELAY) {
+            udelay(NEURONSPI_LAST_TRANSFER_DELAY - udelta);
+        }
+    }
+       //current_policy = cpufreq_cpu_get_raw(task_cpu(current));
+       current_policy = cpufreq_cpu_get_raw(0);
+       if (current_policy && !enable) {
+ wait:
+        wait_event(current_policy->transition_wait, !current_policy->transition_ongoing);
+        spin_lock(&current_policy->transition_lock);
+        if (unlikely(current_policy->transition_ongoing)) {
+            spin_unlock(&current_policy->transition_lock);
+            goto wait;
+        }
+
+        current_policy->transition_ongoing = true;
+        current_policy->transition_task = current;
+        spin_unlock(&current_policy->transition_lock);
+       }
+
+       if (gpio_is_valid(-spi->cs_gpio)) {
+               gpio_set_value(-spi->cs_gpio, enable);
+        if ((unipi_spi_master_set_cs != NULL)  &&
+           (unipi_spi_master_flag & SPI_MASTER_GPIO_SS)) {
+            unipi_spi_master_set_cs(spi, enable);
+        }
+    } else {
+        if (unipi_spi_master_set_cs != NULL) 
+            unipi_spi_master_set_cs(spi, enable);
+    }
+    if (d_data) d_data->last_cs_cycles = cs_cycles;
+             
+       if (current_policy && enable) {
+        current_policy->transition_ongoing = false;
+        current_policy->transition_task = NULL;
+        wake_up(&current_policy->transition_wait);     
+       }
+
+}
+
+
 /************************
  * Non-static Functions *
  ************************/
-int _neuronspi_spi_send_op(struct spi_device* spi_dev, s32 trans_count, const struct neuronspi_op_buffer* send_buf,
+int neuronspi_spi_send_op(struct spi_device* spi_dev, struct neuronspi_op_buffer* send_buf,
                             struct neuronspi_op_buffer* recv_buf, s32 len, 
-                            s32 freq, s32 delay, s32 send_header, u8 lock_val, u16 crc2);
-
+                            s32 freq, s32 delay, s32 send_header, u8 lock_val);
 
-int neuronspi_spi_send_const_op(struct spi_device* spi_dev, const struct neuronspi_op_buffer* send_buf,
+int neuronspi_spi_send_const_op(struct spi_device* spi_dev, struct neuronspi_op_buffer* send_buf,
                             struct neuronspi_op_buffer* recv_buf, s32 len, 
                             s32 freq, s32 delay)
 {
-       s32 trans_count = (len-1) / NEURONSPI_MAX_TX + 3; // number of transmissions
-    return _neuronspi_spi_send_op(spi_dev,trans_count, send_buf,recv_buf,len,freq, delay, UNIPISPI_OP_MODE_SEND_HEADER, 0, 0);
+    return neuronspi_spi_send_op(spi_dev, send_buf, recv_buf, len, freq, delay, UNIPISPI_OP_MODE_SEND_HEADER, 0);
 }
 
+void unipi_spi_read_str(struct spi_device* spi, struct neuronspi_port* port);
 
-/*
- *  send_header: bits of UNIPISPI_OP_MODE_SEND_HEADER | UNIPISPI_OP_MODE_DO_CRC | UNIPISPI_OP_MODE_HAVE_CRC_SPACE
- *  len:         length of second message. If DO_CRC is not set, len includes crc
- *  buffers:     must be long enough if HAVE_CRC_SPACE is set  
- *  returns:     0 if success
- */
-int neuronspi_spi_send_op(struct spi_device* spi_dev, struct neuronspi_op_buffer* send_buf, struct neuronspi_op_buffer* recv_buf, s32 len, 
-                          s32 freq, s32 delay, s32 send_header, u8 lock_val)
+
+struct unipi_spi_context {
+    struct completion* unipi_spi_completion;
+    int len;
+    struct neuronspi_op_buffer* recv_buf;
+    struct neuronspi_port* string_op_port;
+    struct spi_message message;
+    //struct spi_transfer _transfer[]   
+};
+
+static struct neuronspi_port* unipi_spi_check_message(struct unipi_spi_context* context)
 {
-       u16 packet_crc = 0;
-       s32 trans_count = 2; // number of transmissions
+    struct neuronspi_op_buffer* recv_buf = context->recv_buf;
+    struct neuronspi_driver_data *d_data;// = context->d_data;
+    int len = context->len;
+    struct neuronspi_port* port = NULL;
+    u16 packet_crc, recv_crc;
+    u8 opcode;    
+    int portindex;
+    
+    d_data = spi_get_drvdata(context->message.spi);
+    
+    if (context->message.status != 0) {
+        // odeslani se nepovedlo z nejakeho duvodu
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Error spi transaction: txopcode:%d\n", recv_buf->first_message[0]);
+        goto err;
+    }
 
-    if (send_header & UNIPISPI_OP_MODE_SEND_HEADER) {
-               unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Write(op1) %8ph\n", send_buf->first_message);
-        if (send_header & UNIPISPI_OP_MODE_DO_CRC) {
-            packet_crc = neuronspi_spi_crc(send_buf->first_message, 4, 0);
-            *((u16*)(send_buf->first_message+4)) = packet_crc;
-        }
+    unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Read (op1) %8ph\n", recv_buf->first_message);
+    if (d_data && d_data->poll_enabled) {
+       // reschedule poll timer (pseudo interrupt)
+       hrtimer_start_range_ns(&d_data->poll_timer, 2000000, 4000000, HRTIMER_MODE_REL);
     }
+    // check crc on header
+       recv_crc = neuronspi_spi_crc(recv_buf->first_message, 4, 0);
+       packet_crc = *((u16*)(recv_buf->first_message+4));
+
+       if (recv_crc != packet_crc) {
+               unipi_spi_trace(KERN_INFO "UNIPISPI: SPI CRC1 Not Correct (Received: %04x Calculated: %04x)\n", packet_crc, recv_crc);
+        recv_buf->first_message[0] = 0;
+        goto err;
+    }
+    opcode = recv_buf->first_message[0];
+    if ((opcode >= 0x41)&&(opcode <= 0x44)) {
+        // Signal the UART to issue character reads
+        portindex = (opcode - 0x41);
+        if ((d_data != NULL) && d_data->uart_count && (portindex < d_data->uart_count)) {
+            unipi_spi_trace_1(KERN_INFO "UNIPISPI: Reading UART data for device %d, opcode=%02x\n", d_data->neuron_index, opcode);
+            port = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex;
+            // put one incomming character from UART
+            neuronspi_uart_handle_rx(port, 1, recv_buf->first_message+3);
+            // read queue length
+            port->rx_remain = (recv_buf->first_message[2]==0  ? 256 : recv_buf->first_message[2]) - 1;
+                        
+            unipi_spi_trace(KERN_INFO "UNIPISPI: UART Buffer:%d, ttyNS%d(%d:%d)\n", port->rx_remain, port->port.line, port->dev_index, port->dev_port);
+        }
+    } else if (opcode != 0xfa) {
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Err rx:%d\n",  opcode);
+        goto err;
+       }
 
     if (len > 0) {
-        if (send_header & UNIPISPI_OP_MODE_DO_CRC) {
-            packet_crc = neuronspi_spi_crc(send_buf->second_message, len, packet_crc);
-            if (send_header & UNIPISPI_OP_MODE_HAVE_CRC_SPACE) {
-                // crc can be placed into data buffer
-                send_buf->second_message[len] = packet_crc & 0xff;
-                send_buf->second_message[len+1] = packet_crc >> 8;
-                len += 2;
-            } else {
-                // crc needs own buffer and own chunk
-                //crc_send_buf[0] = packet_crc;
-                trans_count++;
+        // Check second message crc
+               recv_crc = neuronspi_spi_crc(recv_buf->second_message, len, recv_crc);
+        packet_crc = recv_buf->second_message[len] | (recv_buf->second_message[len+1] << 8);
+               unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Read - %d:\n\t%64ph\n\t%64ph\n\t%64ph\n\t%64ph\n", len, 
+                                        recv_buf->second_message, recv_buf->second_message + 64,
+                                        recv_buf->second_message+128, recv_buf->second_message+192);
+
+               if (recv_crc != packet_crc) {
+            unipi_spi_trace(KERN_INFO "UNIPISPI: SPI CRC2 Not Correct: %04x COMPUTED: %04x\n", packet_crc, recv_crc);
+            goto err;
+        }
+#ifdef UNIPISPI_USE_RX_THREAD
+        if (recv_buf->second_message[0] == 0x65) {
+            // this op can be invoked only from kernel_work rx_proc
+            portindex = 0; // second_message[2]; Overit ve firmware
+            if (d_data->uart_count && (portindex < d_data->uart_count)) {
+                port = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex;
+                port->rx_remain = recv_buf->second_message[3];
+                neuronspi_rx_queue_swap(port);
             }
         }
-               trans_count += (len-1) / NEURONSPI_MAX_TX + 1;
-               unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Write(%3d) %32ph\n", len, send_buf->second_message);
+#endif
     }
-    return _neuronspi_spi_send_op(spi_dev,trans_count, send_buf,recv_buf,len,freq, delay, send_header, lock_val, packet_crc);
+
+    return(port);
+
+err:
+    if (len>0) recv_buf->second_message[0] = 0;
+    recv_buf->first_message[0] = 0;
+
+    return(port);
 }
 
-int _neuronspi_spi_send_op(struct spi_device* spi_dev, s32 trans_count, const struct neuronspi_op_buffer* send_buf,
-                            struct neuronspi_op_buffer* recv_buf, s32 len, 
-                            s32 freq, s32 delay, s32 send_header, u8 lock_val, u16 crc2)
-{
-       s32 i = 0;
-    s32 remain;
-       int ret_code = 0;
-       u16 recv_crc1 = 0;
-       u16 recv_crc2;
-       u16 packet_crc;
-    u16 crc_send_buf[2];
-    u16 crc_recv_buf[2];
-    u8 opcode;
-    int portindex;
-    struct neuronspi_port* port;
 
 
-       struct neuronspi_driver_data *d_data;
-    struct spi_transfer* s_trans;
 
-       mutex_lock(&neuronspi_master_mutex);
-    d_data = spi_get_drvdata(spi_dev);
+#define clear_op_buffer(buffer, len)    { buffer->first_message[0] = 0;\
+                                if ((len > 0) && (buffer->second_message)) buffer->second_message[0] = 0; }
 
-    // Check if there are running reserved operations
-       if (d_data != NULL && d_data->reserved_device && lock_val != d_data->reserved_device) {
-               recv_buf->first_message[0] = 0;
-        if ((len > 0) && (recv_buf->second_message)) recv_buf->second_message[0] = 0;
-        if (d_data->poll_enabled) {
-            // reschedule poll timer
-            hrtimer_start_range_ns(&d_data->poll_timer, 2000000, 4000000, HRTIMER_MODE_REL);
-        }
-        mutex_unlock(&neuronspi_master_mutex);
-        return -1; // blocked by reservation
+
+struct unipi_spi_context* unipi_spi_setup_context(struct spi_device* spi_dev, struct neuronspi_op_buffer* send_buf,
+                            struct neuronspi_op_buffer* recv_buf, int len, 
+                            int freq, int delay, s32 send_header)
+{
+    //struct neuronspi_driver_data *d_data = spi_get_drvdata(spi_dev);
+       int trans_count, remain, i;
+       struct unipi_spi_context *context;
+    struct spi_transfer * s_trans;
+       u16 packet_crc = 0;
+
+    if (len == 0) {
+        trans_count = 2;
+    } else {
+        if (send_header & UNIPISPI_OP_MODE_DO_CRC) len += 2;
+        trans_count = ((len-1) / NEURONSPI_MAX_TX) + 3; // number of transmissions
+    }
+
+       context = kzalloc(sizeof(struct unipi_spi_context)      + trans_count * sizeof(struct spi_transfer), GFP_ATOMIC);
+       if (! context) {
+        return NULL;
        }
+    s_trans = (struct spi_transfer *)(context + 1);
+    spi_message_init_with_transfers(&context->message, s_trans, trans_count);
 
-       s_trans = kzalloc(sizeof(struct spi_transfer) * trans_count, GFP_ATOMIC);
        s_trans[0].delay_usecs = NEURONSPI_EDGE_DELAY;
        s_trans[0].bits_per_word = 8;
        s_trans[0].speed_hz = freq;
 
        s_trans[1].bits_per_word = 8;
        s_trans[1].speed_hz = freq;
-    if (send_header) {
+    if (send_header  & UNIPISPI_OP_MODE_SEND_HEADER) {
+               unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Write(op1) %8ph\n", send_buf->first_message);
+        if (send_header & UNIPISPI_OP_MODE_DO_CRC) {
+            packet_crc = neuronspi_spi_crc(send_buf->first_message, 4, 0);
+            *((u16*)(send_buf->first_message+4)) = packet_crc;
+        }
         s_trans[1].delay_usecs = delay;
         s_trans[1].len = NEURONSPI_FIRST_MESSAGE_LENGTH;
         s_trans[1].tx_buf = send_buf->first_message;
         s_trans[1].rx_buf = recv_buf->first_message;
     }
     if (len > 0) {
+        if (send_header & UNIPISPI_OP_MODE_DO_CRC) {
+            packet_crc = neuronspi_spi_crc(send_buf->second_message, len-2, packet_crc);
+            send_buf->second_message[len-2] = packet_crc & 0xff;
+            send_buf->second_message[len-1] = packet_crc >> 8;
+        }
+               unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Write(%3d) %32ph\n", len, send_buf->second_message);
                remain = len;
                for (i = 2; 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;
@@ -201,99 +351,382 @@ int _neuronspi_spi_send_op(struct spi_device* spi_dev, s32 trans_count, const st
                        s_trans[i].len = (remain > NEURONSPI_MAX_TX) ? NEURONSPI_MAX_TX : remain;
                        remain -= NEURONSPI_MAX_TX;
                }
-        // corrent last chunk 
-        s_trans[trans_count-1].delay_usecs = NEURONSPI_LAST_TRANSFER_DELAY;
-        if ((send_header & (UNIPISPI_OP_MODE_HAVE_CRC_SPACE | UNIPISPI_OP_MODE_DO_CRC)) == (UNIPISPI_OP_MODE_DO_CRC)) {
-            // crc2 is placed into own chunk
-            crc_recv_buf[0] = crc2;
-                       s_trans[trans_count-1].tx_buf = crc_send_buf;
-                       s_trans[trans_count-1].rx_buf = crc_recv_buf;
-                       s_trans[trans_count-1].len = 2;
-        } else {
-            // crc is in part of data chunk
-            // len is size of second message WITHOUT crc
-            len -= 2;
+        // len is size of second message WITHOUT crc
+        len -= 2;
+       }
+    
+    context->message.context = context;
+    context->message.spi = spi_dev;
+    context->len = len;
+    context->recv_buf = recv_buf;
+    return context;
+}
+
+/*
+static void unipi_spi_idle_op_complete(void *arg)
+{
+    struct unipi_spi_context* context = (struct unipi_spi_context*) arg;
+    struct neuronspi_port *port;
+
+    port = unipi_spi_check_message(context);
+    if (port && (port->rx_remain))  unipi_spi_read_str(context->message.spi, port);    
+    kfree(context->recv_buf);
+    kfree(context);
+}
+
+void unipi_spi_idle_op(struct spi_device* spi)
+{
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+    struct neuronspi_op_buffer* recv_op;// = &d_data->idle_recv_buf;
+       struct unipi_spi_context *context;
+    unsigned long flags;
+
+    unipi_spi_trace(KERN_INFO "UNIPISPI: Idle op\n");
+    recv_op = kzalloc(sizeof(struct neuronspi_op_buffer), GFP_ATOMIC);
+    clear_op_buffer(recv_op, 0);
+    
+    context = unipi_spi_setup_context(spi, &UNIPISPI_IDLE_MESSAGE, recv_op, 0, d_data->ideal_frequency, 0, UNIPISPI_OP_MODE_SEND_HEADER);
+    if (context == NULL) goto err; // no mem for kzalloc
+    
+    context->message.complete = unipi_spi_idle_op_complete;
+     
+    spin_lock_irqsave(&unipi_spi_master_lock, flags);
+    if  ((d_data->reserved_device)       // Running reserved operations
+         ||(spi_async(spi, &context->message) != 0)) {
+        spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+        kfree(context);
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Err=3 Idle op\n");
+        goto err;
+    }
+    spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+    return;
+    
+err:
+    kfree(recv_op);
+    if (d_data->poll_enabled) {
+        // reschedule poll timer
+        hrtimer_start_range_ns(&d_data->poll_timer, 2000000, 4000000, HRTIMER_MODE_REL);
+    }
+}
+*/
+
+/************************************************************************************
+ * 
+ *    unipi_spi_read_str()
+ *      can be called only from spi thread
+ *      for particular port can be only one read_str operation in progress
+ */
+static void unipi_spi_read_str_complete(void *arg)
+{
+    struct unipi_spi_context* context = (struct unipi_spi_context*) arg;
+    struct neuronspi_op_buffer* recv_buf = context->recv_buf;
+    struct neuronspi_driver_data *d_data = spi_get_drvdata(context->message.spi);
+    struct neuronspi_port *port, *port2;
+    int portindex2;
+
+    port = unipi_spi_check_message(context);
+    context->string_op_port->rx_in_progress = 0;
+    if (recv_buf->second_message[0] == 0x65) {
+        // this op can be invoked only from kernel_work rx_proc
+        portindex2 = 0; // second_message[2]; Overit ve firmware
+        if (d_data->uart_count && (portindex2 < d_data->uart_count)) {
+            port2 = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex2;
+            if (port && (port == port2)) {
+                port = NULL;
+            }
+            neuronspi_uart_handle_rx(port2, recv_buf->second_message[1], recv_buf->second_message+4);
+            port2->rx_remain = recv_buf->second_message[3];
+            if (port2->rx_remain) unipi_spi_read_str(context->message.spi, port2);
         }
+    }
+
+    if (port && (port->rx_remain))  unipi_spi_read_str(context->message.spi, port);
+    
+    kfree(context);
+}
+
+void unipi_spi_read_str(struct spi_device* spi, struct neuronspi_port* port)
+{
+       struct neuronspi_op_buffer* send_op = &port->rx_send_buf;
+       struct neuronspi_op_buffer* recv_op = &port->rx_recv_buf;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+       struct unipi_spi_context *context;
+       int transmit_len, len, locked;
+    unsigned long flags;
+
+    spin_lock_irqsave(&port->rx_in_progress_lock, flags);
+    locked = port->rx_in_progress;
+    if (!locked) port->rx_in_progress = 1;
+    spin_unlock_irqrestore(&port->rx_in_progress_lock, flags);
+    if (locked) return;
+
+    len = port->rx_remain;
+       if (len < 246) {
+               len = (len+4);
+       } else {
+               len = 250;
        }
+       transmit_len = (len & 1 ? len+1 : len) + 4;  // transmit_length must be even
 
-    // Call SPI transaction
-       ret_code = spi_sync_transfer(spi_dev, s_trans, trans_count);
-       kfree(s_trans);
+       send_op->first_message[1] = transmit_len;     //
+       send_op->first_message[2] = 0;
+       send_op->first_message[3] = port->dev_port;
+       send_op->first_message[0] = 0x65;
+       send_op->second_message[0] = 0x65;
 
-       if (ret_code != 0) {
-        mutex_unlock(&neuronspi_master_mutex);
-        unipi_spi_trace(KERN_INFO "UNIPISPI: Err=3 txopcode:%d\n", send_buf->first_message[0]);
-        return 3;  // spi_tranfer error
+    unipi_spi_trace(KERN_INFO "UNIPISPI: Read string ttyNS%d, len=%d\n", port->port.line, transmit_len-4);
+
+    clear_op_buffer(recv_op, len);
+    
+    context = unipi_spi_setup_context(spi, send_op, recv_op, transmit_len, d_data->ideal_frequency, 20, UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC);
+    if (context == NULL) goto err; // no mem for kzalloc
+    
+    context->message.complete = unipi_spi_read_str_complete;
+    context->string_op_port = port;
+     
+    spin_lock_irqsave(&unipi_spi_master_lock, flags);
+    if  ((d_data->reserved_device) ||        // Running reserved operations
+         (spi_async(spi, &context->message) != 0)) {
+        spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+        kfree(context);
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Err=3 on Read string\n");
+        goto err;
+    }
+    spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+    return;
+    
+err:
+    port->rx_in_progress = 0;
+}
+
+/************************************************************************************
+ * 
+ *    unipi_spi_write_str()
+ *      
+ *      for particular port can be only one write_str operation in progress
+ */
+static void unipi_spi_write_str_complete(void *arg)
+{
+    struct unipi_spi_context* context = (struct unipi_spi_context*) arg;
+    //struct neuronspi_op_buffer* recv_buf = context->recv_buf;
+    //struct neuronspi_driver_data *d_data = spi_get_drvdata(context->message.spi);
+    unsigned long flags;
+    struct neuronspi_port *port;
+
+    port = unipi_spi_check_message(context);
+    if (port && (port->rx_remain))  unipi_spi_read_str(context->message.spi, port);
+       context->string_op_port->tx_fifo_len += context->len;
+
+       spin_lock_irqsave(&context->string_op_port->port.lock, flags);
+    unipi_uart_handle_tx(context->string_op_port, CB_WRITESTRING);
+       spin_unlock_irqrestore(&context->string_op_port->port.lock, flags);
+    
+    kfree(context);
+}
+
+int unipi_spi_write_str(struct spi_device* spi, struct neuronspi_port* port, int length)
+{
+       struct neuronspi_op_buffer* send_op = &port->tx_send_buf;
+       struct neuronspi_op_buffer* recv_op = &port->tx_recv_buf;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+       struct unipi_spi_context *context;
+       int transmit_len;
+    unsigned long flags;
+
+       unipi_spi_trace(KERN_INFO "UNIPISPI: SPI Write string ttyNS%d, len:%d\n", port->port.line, length);
+       if ((length <= 0) || (length > 256)) return 1;
+
+    send_op->first_message[2] = 0;
+    send_op->first_message[3] = port->dev_port;
+       if (length == 1) {
+               send_op->first_message[0] = 0x41;
+               send_op->first_message[1] = port->tx_send_msg[0];
+        transmit_len = 0;
+       } else {
+               send_op->first_message[0] = 0x64;                           //NEURONSPI_SPI_UART_LONG_MESSAGE[0];
+               send_op->first_message[1] = length == 256 ? 0 : length;     // special case length==256
+               transmit_len = length & 1 ? length+1 : length;              // transmit_length must be even
+    }
+    clear_op_buffer(recv_op, transmit_len);
+
+    context = unipi_spi_setup_context(spi, send_op, recv_op, transmit_len, d_data->ideal_frequency, 20, UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC);
+    if (context == NULL) goto err; // no mem for kzalloc
+    
+    context->message.complete = unipi_spi_write_str_complete;
+    context->string_op_port = port;
+
+    spin_lock_irqsave(&unipi_spi_master_lock, flags);
+    if  ((d_data->reserved_device) ||        // Running reserved operations
+         (spi_async(spi, &context->message) != 0)) {
+        spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+        kfree(context);
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Err=3 in Write string\n");
+        goto err;
+    }
+    spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+    return 0;
+    
+err:
+    return 1;
+}
+
+/************************************************************************************
+ * 
+ *    unipi_spi_get_tx_fifo()
+ *      
+ *      for particular port can be only one get_tx_fifo or write_str operation in progress
+ */
+static void unipi_spi_get_tx_fifo_complete(void *arg)
+{
+    struct unipi_spi_context* context = (struct unipi_spi_context*) arg;
+    u8 * recv_msg = context->string_op_port->tx_recv_msg;
+    //struct neuronspi_driver_data *d_data = spi_get_drvdata(context->message.spi);
+    struct neuronspi_port *port;
+    unsigned long flags;
+
+    port = unipi_spi_check_message(context);
+    if (port && (port->rx_remain))  unipi_spi_read_str(context->message.spi, port);
+
+    unipi_spi_trace("UNIPISPI: get_tx_fifo_complete recv_msg: %16ph\n", recv_msg);
+       if (recv_msg[0] == 0x03) {
+               context->string_op_port->tx_fifo_len = recv_msg[4] + ((recv_msg[5]) << 8);
        }
+       spin_lock_irqsave(&context->string_op_port->port.lock, flags);
+    unipi_uart_handle_tx(context->string_op_port, CB_GETTXFIFO);
+    spin_unlock_irqrestore(&context->string_op_port->port.lock, flags);
+    
+    kfree(context);
+}
+
+int unipi_spi_get_tx_fifo(struct spi_device* spi, struct neuronspi_port* port)
+{
+       struct neuronspi_op_buffer* send_op = &port->tx_send_buf;
+       struct neuronspi_op_buffer* recv_op = &port->tx_recv_buf;
+       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
+       struct unipi_spi_context *context;
+    unsigned long flags;
+
+       unipi_spi_trace(KERN_INFO "UNIPISPI: SPI Get TX fifo length ttyNS%d\n", port->port.line);
+
+    send_op->first_message[0] = 0x03;
+    send_op->first_message[1] = 4+2;
+    *((u16*)(send_op->first_message + 2)) = port->tx_fifo_reg;
+       memcpy(send_op->second_message, send_op->first_message, 4);
+    clear_op_buffer(recv_op, (4+2));
+
+    context = unipi_spi_setup_context(spi, send_op, recv_op, 4+2, d_data->ideal_frequency, 35, UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC);
+    if (context == NULL) goto err; // no mem for kzalloc
+    
+    context->message.complete = unipi_spi_get_tx_fifo_complete;
+    context->string_op_port = port;
+
+    spin_lock_irqsave(&unipi_spi_master_lock, flags);
+    if  ((d_data->reserved_device) ||        // Running reserved operations
+         (spi_async(spi, &context->message) != 0)) {
+        spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+        kfree(context);
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Err=3 in Get Tx fifo\n");
+        goto err;
+    }
+    spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+    return 0;
+    
+err:
+    return 1;
+}
+
+/* 
+ * Callback from spi thread
+ * invoked after transaction inserted by async_spi_send() is finished
+ */
+static void unipi_spi_firmware_op_complete(void *arg)
+{
+    struct unipi_spi_context* context = (struct unipi_spi_context*) arg;
+    //struct neuronspi_op_buffer* recv_buf = context->recv_buf;
+
+    // Don't check crc on firmware operation
+       unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Firmware op len=%d:\n\t%64ph\n", context->len, context->recv_buf->second_message);
+    complete(context->unipi_spi_completion);
+    kfree(context);
+}
+
+
+static void unipi_spi_send_op_complete(void *arg)
+{
+    struct unipi_spi_context* context = (struct unipi_spi_context*) arg;
+    struct neuronspi_port* port;
+
+    port = unipi_spi_check_message(context);
+    if (port && (port->rx_remain)) unipi_spi_read_str(context->message.spi, port);
+
+    if (context->unipi_spi_completion) 
+        complete(context->unipi_spi_completion);
+    kfree(context);
+}
+
+/*
+ *  send_header: bits of UNIPISPI_OP_MODE_SEND_HEADER | UNIPISPI_OP_MODE_DO_CRC
+ *  len:         length of second message. If DO_CRC is not set, len includes crc
+ *  buffers:     must be long enough to calc crc  
+ *  returns:     0 if success
+ */
+int neuronspi_spi_send_op(struct spi_device* spi_dev, struct neuronspi_op_buffer* send_buf,
+                            struct neuronspi_op_buffer* recv_buf, s32 len, 
+                            s32 freq, s32 delay, s32 send_header, u8 lock_val)
+{
+       int ret_code = 0;
+       struct neuronspi_driver_data *d_data;
+       struct unipi_spi_context *context;
+    unsigned long flags;
+    DECLARE_COMPLETION_ONSTACK(done); //struct completion done;
+
+    unipi_spi_trace(KERN_INFO "UNIPISPI: SPI Send op=%d len=%d\n", send_buf->first_message[0], len);
+    clear_op_buffer(recv_buf, len);
+    d_data = spi_get_drvdata(spi_dev);
+
+    context = unipi_spi_setup_context(spi_dev, send_buf, recv_buf, len, freq, delay, send_header);
+    if (context == NULL) {
+        ret_code = -3; // no mem for kzalloc
+        goto err;
+    }
+
+    init_completion(&done);
+    context->unipi_spi_completion = &done;
     if (send_header & UNIPISPI_OP_MODE_SEND_HEADER) {
-        unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Read (op1) %8ph\n", recv_buf->first_message);
-        if (d_data && d_data->poll_enabled) {
-            // reschedule poll timer
-            hrtimer_start_range_ns(&d_data->poll_timer, 2000000, 4000000, HRTIMER_MODE_REL);
-        }
-               recv_crc1 = neuronspi_spi_crc(recv_buf->first_message, 4, 0);
-               packet_crc = *((u16*)(recv_buf->first_message+4));
-
-               if (recv_crc1 == packet_crc) {
-            unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI CRC1 Correct (=%04x)", packet_crc);
-            opcode = recv_buf->first_message[0];
-            if (d_data != NULL) {
-                if ((opcode >= 0x41)&&(opcode <= 0x44)) {
-                    // Signal the UART to issue character reads
-                    portindex = (opcode==0x43) ? 0 : (opcode - 0x41);
-                    if (d_data->uart_count && (portindex < d_data->uart_count)) {
-                        unipi_spi_trace(KERN_INFO "UNIPISPI: Reading UART data for device %d, opcode=%02x\n", d_data->neuron_index, opcode);
-                        port = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex;
-                        if (opcode != 0x43) {
-                            // read one incomming character from UART
-                            neuronspi_rx_queue_add(port, recv_buf->first_message[3]);
-                        }
-                        // read queue length
-                        port->rx_remain = recv_buf->first_message[2];
-                        unipi_spi_trace(KERN_INFO "UNIPISPI: UART Buffer:%d, ttyNS%d(%d:%d)\n", port->rx_remain, port->port.line, port->dev_index, port->dev_port);
-                        //kthread_queue_work(&neuronspi_uart_data_global->kworker, &port->rx_work);
-                        kthread_queue_work(d_data->primary_worker, &port->rx_work);
-                    }
-                } else if (opcode != 0xfa) {
-                               mutex_unlock(&neuronspi_master_mutex);
-                    unipi_spi_trace(KERN_INFO "UNIPISPI: Err txopcode:%d, rx:%d\n", send_buf->first_message[0], opcode);
-                                       return 1; // op code error - probably uncatched crc
-                               }
-                       }
-               } else {
-            recv_buf->first_message[0] = 0;
-                       unipi_spi_trace(KERN_INFO "UNIPISPI: SPI CRC1 Not Correct (Received: %04x Calculated: %04x)\n", packet_crc, recv_crc1);
-               }
+        context->message.complete = unipi_spi_send_op_complete;
+    } else {
+        context->message.complete = unipi_spi_firmware_op_complete;
     }
-    if (len > 0) {
-        // Check second message crc
-               recv_crc2 = neuronspi_spi_crc(recv_buf->second_message, len, recv_crc1);
-        if ((send_header & (UNIPISPI_OP_MODE_HAVE_CRC_SPACE | UNIPISPI_OP_MODE_DO_CRC)) == (UNIPISPI_OP_MODE_DO_CRC)) {
-            packet_crc = crc_recv_buf[0];
-        } else {
-            packet_crc = recv_buf->second_message[len] | (recv_buf->second_message[len+1] << 8);
-        }
-               unipi_spi_trace_1(KERN_INFO "UNIPISPI: SPI Master Read - %d:\n\t%64ph\n\t%64ph\n\t%64ph\n\t%64ph\n", len, 
-                                        recv_buf->second_message, recv_buf->second_message + 64,
-                                        recv_buf->second_message+128, recv_buf->second_message+192);
 
-               if (recv_crc2 != packet_crc) {
-            unipi_spi_trace(KERN_INFO "UNIPISPI: SPI CRC2 Not Correct: %04x COMPUTED: %04x\n", packet_crc, recv_crc2);
-            if (send_header & UNIPISPI_OP_MODE_SEND_HEADER) 
-                recv_buf->second_message[0] = 0;
-            ret_code = 1;
+    spin_lock_irqsave(&unipi_spi_master_lock, flags);
+    // Check if there are running reserved operations
+       if (d_data != NULL && d_data->reserved_device && lock_val != d_data->reserved_device) {
+        ret_code = -1; // blocked by reservation
+        goto errcontext;
+       }
 
-               } else if (recv_buf->second_message[0] == 0x65) {
-            // this op can be invoked only from kernel_work rx_proc
-            portindex = 0; // second_message[2]; Overit ve firmware
-            if (d_data->uart_count && (portindex < d_data->uart_count)) {
-                port = neuronspi_uart_data_global->p + d_data->uart_pindex + portindex;
-                port->rx_remain = recv_buf->second_message[3];
-                neuronspi_rx_queue_swap(port);
-            }
-        }
+    ret_code = spi_async(spi_dev, &context->message);
+    if (ret_code != 0) {
+        unipi_spi_trace(KERN_INFO "UNIPISPI: Err=3 txopcode:%d\n", send_buf->first_message[0]);
+        goto errcontext;
     }
-    mutex_unlock(&neuronspi_master_mutex);
+    spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+
+    wait_for_completion(&done);
+    //cycles_t ct2 = get_cycles(); ktime_t t2 = ktime_get();
+    //unipi_spi_trace(KERN_INFO "UNIPISPI: deltatime:%lldus cycles:%ld\n", ((long long) ktime_to_ns(ktime_sub(t2,t1)))/1000, ct2-ct1);
+    return ret_code;
+
+errcontext:
+    spin_unlock_irqrestore(&unipi_spi_master_lock, flags);
+    kfree(context);
+
+err:
     return ret_code;
 }
 
@@ -503,102 +936,6 @@ ssize_t neuronspi_write (struct file *file_p, const char *buffer, size_t len, lo
  *  Interface used by kernel - UnipiSpi operations 
  */
 
-s32 neuronspi_spi_uart_write(struct spi_device *spi, u8 *send_buf, int length, u8 uart_index)
-{
-       u8 *message_buf;
-       u8 *recv_buf;
-       s32 transmit_len;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
-       struct neuronspi_op_buffer send_op;
-       struct neuronspi_op_buffer recv_op;
-       s32 frequency = NEURONSPI_DEFAULT_FREQ;
-       if (d_data) {
-               frequency = d_data->ideal_frequency;
-       }
-
-       unipi_spi_trace(KERN_INFO "UNIPISPI: SPI uart write, dev:%d, len:%d\n", uart_index, length);
-       if ((length == 0) || (length > 256)) {
-               return -1;
-       }
-       if (d_data->reserved_device) {
-               return 0;
-       }
-
-       if (length == 1) {
-               transmit_len = 0;
-               send_op.first_message[0] = 0x41;
-               send_op.first_message[1] = send_buf[0];
-               send_op.first_message[2] = 0;
-               send_op.first_message[3] = uart_index;
-               //neuronspi___spi_send_message_crc(spi, &send_op, &recv_op, transmit_len, frequency, 65);
-               neuronspi_spi_send_op(spi, &send_op, &recv_op, transmit_len, frequency, 20, UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
-       } else {
-               transmit_len = length & 1 ? length+1 : length;  // transmit_length must be even
-               send_op.first_message[0] = 0x64;                //NEURONSPI_SPI_UART_LONG_MESSAGE[0];
-               send_op.first_message[1] = length == 256 ? 0 : length;           // special case length==256
-               send_op.first_message[2] = 0;
-               send_op.first_message[3] = uart_index;
-               message_buf = kzalloc(transmit_len+16, GFP_ATOMIC);
-               memcpy(message_buf, send_buf, length);
-               recv_buf = kzalloc(transmit_len+16, GFP_ATOMIC);
-               memset(recv_buf+transmit_len, 0xff, 16);
-        
-        recv_op.second_message = recv_buf;
-        send_op.second_message = message_buf;
-               neuronspi_spi_send_op(spi, &send_op, &recv_op, transmit_len, frequency, 20, UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
-               //neuronspi___spi_send_message_crc(spi, &send_op, &recv_op, transmit_len, frequency, 65);
-
-               kfree(message_buf);
-               kfree(recv_buf);
-       }
-       return 0;
-}
-
-void neuronspi_spi_uart_read(struct spi_device* spi, u8 *recv_buf, s32 len, u8 uart_index)
-{
-       s32 transmit_len;
-       struct neuronspi_op_buffer send_op;
-       struct neuronspi_op_buffer recv_op;
-    u8 *send_buf;
-       struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
-       s32 frequency = NEURONSPI_DEFAULT_FREQ;
-       if (d_data) {
-               frequency = d_data->ideal_frequency;
-       }
-
-       unipi_spi_trace(KERN_INFO "UNIPISPI: SPI uart read, dev:%d, len:%d\n", uart_index, len);
-       if (len < 246) {
-               len = (len+4);
-       } else {
-               len = 250;
-       }
-       transmit_len = (len & 1 ? len+1 : len) + 4;  // transmit_length must be even
-
-       send_op.first_message[1] = transmit_len;     //
-       send_op.first_message[2] = 0;
-       send_op.first_message[3] = uart_index;
-
-       send_buf = kzalloc(transmit_len+64/*safety space*/, GFP_ATOMIC);
-
-#if 1
-       send_op.first_message[0] = 0x65;
-#else
-       send_op.first_message[0] =  (NEURON_FIRMWARE_VERSION(d_data) < 0x518) ? 0x65 : 0x68;
-#endif
-       send_buf[0] = 0x65;
-
-    send_op.second_message = send_buf;
-    recv_op.second_message = recv_buf;
-
-       unipi_spi_trace(KERN_INFO "UNIPISPI: UART Device Read len:%d\n", transmit_len);
-
-       if (!d_data->reserved_device) {
-               neuronspi_spi_send_op(spi, &send_op, &recv_op, transmit_len, frequency, 20, 
-                                UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
-       }
-    kfree(send_buf);
-}
-
 int unipispi_modbus_read_register(struct spi_device* spi_dev, u16 reg, u16* value)
 {
     struct neuronspi_op_buffer send_buf;
@@ -621,7 +958,7 @@ int unipispi_modbus_read_register(struct spi_device* spi_dev, u16 reg, u16* valu
        send_data[1] = 1;
 
        ret_code = neuronspi_spi_send_op(spi_dev, &send_buf, &recv_buf, 4+2, frequency, 35,
-                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
+                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC, 0);
        if (ret_code == 0) {
         if ((recv_data[0] == 0x03) && (recv_data[1]==1)) {  // check opcode and register count
             *value = *((u16*)(recv_data + 4));
@@ -656,7 +993,7 @@ int unipispi_modbus_read_u32(struct spi_device* spi_dev, u16 reg, u32* value)
        send_data[1] = 2;
     
        ret_code = neuronspi_spi_send_op(spi_dev, &send_buf, &recv_buf, 4+4, frequency, 35,
-                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
+                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC, 0);
        if (ret_code == 0) {
         if ((recv_data[0] == 0x03) && (recv_data[1]==2)) {
             *value = *((u32*)(recv_data + 4));
@@ -699,7 +1036,7 @@ int unipispi_modbus_write_register(struct spi_device* spi_dev, u16 reg, u16 valu
     *((u16*)(send_data + 4)) = value;
     
        ret_code = neuronspi_spi_send_op(spi_dev, &send_buf, &recv_buf, 4+2, frequency, 35,
-                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
+                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC, 0);
        if (ret_code == 0) {
         if ((recv_data[0] != 0x06) || (recv_data[1]!=1)) {
             //unipi_spi_trace("Write reg: %d %8ph\n", reg, recv_data);
@@ -733,7 +1070,7 @@ int unipispi_modbus_write_u32(struct spi_device* spi_dev, u16 reg, u32 value)
     *((u32*)(send_data + 4)) = value;
     
        ret_code = neuronspi_spi_send_op(spi_dev, &send_buf, &recv_buf, 4+4, frequency, 35,
-                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
+                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC, 0);
        if (ret_code == 0) {
         if ((recv_data[0] != 0x06) || (recv_data[1]!=2)) {
             ret_code = 2;
@@ -766,7 +1103,7 @@ int unipispi_modbus_write_coil(struct spi_device* spi_dev, u16 coil, int value)
     *((u16*)(send_buf.first_message + 2)) = coil;
     
        ret_code = neuronspi_spi_send_op(spi_dev, &send_buf, &recv_buf, 0, frequency, 25,
-                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC|UNIPISPI_OP_MODE_HAVE_CRC_SPACE, 0);
+                                    UNIPISPI_OP_MODE_SEND_HEADER|UNIPISPI_OP_MODE_DO_CRC, 0);
     return ret_code;
 }
 
@@ -796,9 +1133,11 @@ void neuronspi_irq_proc(struct kthread_work *ws)
 static enum hrtimer_restart neuronspi_poll_timer_func(struct hrtimer *timer)
 {
     struct neuronspi_driver_data* n_spi = ((container_of((timer), struct neuronspi_driver_data, poll_timer)));
-
+    struct spi_device *spi = neuronspi_s_dev [n_spi->neuron_index];
+    
        unipi_spi_trace_1(KERN_INFO "UNIPISPI: nspi%d POLL IRQ\n", n_spi->neuron_index);
        kthread_queue_work(n_spi->primary_worker, &n_spi->irq_work);
+    //unipi_spi_idle_op(spi);
        return HRTIMER_NORESTART;
 }
 
@@ -811,7 +1150,7 @@ irqreturn_t neuronspi_spi_irq(s32 irq, void *dev_id)
 
        unipi_spi_trace(KERN_INFO "UNIPISPI: nspi%d SPI IRQ\n", n_spi->neuron_index);
        kthread_queue_work(n_spi->primary_worker, &n_spi->irq_work);
-
+    //unipi_spi_idle_op(spi);
        return IRQ_HANDLED;
 }
 
@@ -826,6 +1165,7 @@ void neuronspi_enable_uart_interrupt(struct neuronspi_port* n_port)
         n_spi->poll_enabled = 1;
         // invoke first probe -> which invokes hrtimer
         kthread_queue_work(n_spi->primary_worker, &n_spi->irq_work);
+        //unipi_spi_idle_op(spi);
     }
 }
 
@@ -850,6 +1190,7 @@ s32 neuronspi_spi_probe(struct spi_device *spi)
     u32 probe_always_succeeds;
        u32 always_create_uart;
     struct kthread_worker   *worker;
+       struct sched_param rt_param = { .sched_priority = MAX_RT_PRIO - 1 };
 
        unsigned long flags;
     
@@ -951,6 +1292,21 @@ s32 neuronspi_spi_probe(struct spi_device *spi)
                return ret;
        }
 
+       // Set rt priority to spi controller
+       //dev_info(&ctlr->dev, "will run message pump with realtime priority\n");
+       if (spi->controller->kworker_task)
+               sched_setscheduler(spi->controller->kworker_task, SCHED_FIFO, &rt_param);
+
+    if (spi->controller->set_cs != unipi_spi_set_cs) {
+        unipi_spi_master_set_cs = spi->controller->set_cs;
+        unipi_spi_master_flag = spi->controller->flags;
+        spi->controller->set_cs = unipi_spi_set_cs;
+        spi->controller->flags |= SPI_MASTER_GPIO_SS;
+    }
+    if (gpio_is_valid(spi->cs_gpio)) {
+        spi->cs_gpio = -spi->cs_gpio;
+    }
+        
     // Prepare worker for interrupt, LEDs, UARTs
     worker = kthread_create_worker(0, "unipispi%d", n_spi->neuron_index);
        if (IS_ERR(worker)) {
@@ -1033,6 +1389,16 @@ s32 neuronspi_spi_remove(struct spi_device *spi)
        struct neuronspi_driver_data *n_spi = spi_get_drvdata(spi);
 
     if (n_spi) {
+        if ((spi->cs_gpio < 0) && (spi->cs_gpio != -ENOENT)) { spi->cs_gpio = -spi->cs_gpio; }
+        if (spi->controller->set_cs == unipi_spi_set_cs) {
+            spi->controller->set_cs = unipi_spi_master_set_cs;
+            if (unipi_spi_master_flag & SPI_MASTER_GPIO_SS) {
+                spi->controller->flags |= SPI_MASTER_GPIO_SS;
+            } else {
+                spi->controller->flags &= ~SPI_MASTER_GPIO_SS;
+            }
+        }
+
         neuron_index = n_spi->neuron_index; 
                if (n_spi->no_irq) {
             hrtimer_cancel(&n_spi->poll_timer);
@@ -1142,15 +1508,21 @@ struct spi_driver neuronspi_spi_driver =
 
 MODULE_ALIAS("spi:unipispi");
 
+
+
 static s32 __init neuronspi_init(void)
 {
        s32 ret = 0;
 
        neuronspi_probe_spinlock = kzalloc(sizeof(struct spinlock), GFP_ATOMIC);
        spin_lock_init(neuronspi_probe_spinlock);
-       mutex_init(&neuronspi_master_mutex);
+       spin_lock_init(&unipi_spi_master_lock);
+       //mutex_init(&neuronspi_master_mutex);
        mutex_init(&unipi_inv_speed_mutex);
 
+    loop_per_us = ((loops_per_jiffy) * HZ )/ 1000000;
+    if (loop_per_us == 0) loop_per_us = 1;
+
     // clear global neuron spi devices list
        memset(&neuronspi_s_dev, 0, sizeof(neuronspi_s_dev));
        ret = spi_register_driver(&neuronspi_spi_driver);
index 7f1c85b978304a64f6c0cdc8c15fb94415fcfc34..68522037e021b7d21b75d53bbdf0c8d5b37e8612 100644 (file)
@@ -47,20 +47,6 @@ static const struct neuronspi_frequecy_map NEURONSPI_FREQUENCY_MAP[NEURONSPI_FRE
        {model:0x0000, mask:0x0000, frequency:NEURONSPI_COMMON_FREQ}
 };
 
-#define UNIPISPI_PROBE_MESSAGE_LEN                                             16
-static u8 _probe_message_second[UNIPISPI_PROBE_MESSAGE_LEN] = 
-          {0x04, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x16};
-static const struct neuronspi_op_buffer UNIPISPI_PROBE_MESSAGE = {
-    first_message: {0x04, 0x0e, 0xe8, 0x03, 0xa0, 0xdd},
-    second_message: _probe_message_second,
-};
-
-
-static const struct neuronspi_op_buffer UNIPISPI_IDLE_MESSAGE = {
-    first_message: {0xfa, 0x00, 0x55, 0x0e, 0xb6, 0x0a},
-    second_message: NULL,
-};
-
 
 #define NEURONSPI_CRC16TABLE_LEN                                               256
 static const u16 NEURONSPI_CRC16TABLE[NEURONSPI_CRC16TABLE_LEN] = {
@@ -138,6 +124,8 @@ int unipispi_modbus_write_register(struct spi_device* spi_dev, u16 reg, u16 valu
 int unipispi_modbus_write_u32(struct spi_device* spi_dev, u16 reg, u32 value);
 int unipispi_modbus_write_many(struct spi_device* spi_dev, u16 reg, u16* value, int register_count);
 int unipispi_modbus_write_coil(struct spi_device* spi_dev, u16 coil, int value);
+int unipi_spi_write_str(struct spi_device* spi, struct neuronspi_port* port, int length);
+int unipi_spi_get_tx_fifo(struct spi_device* spi, struct neuronspi_port* port);
 
 void neuronspi_enable_uart_interrupt(struct neuronspi_port* n_port);
 
index 2c946c7c6518728a59ef502decd94763044f4383..e0817c21dd8a832721e09d5b7ca40592cd40f5ef 100644 (file)
@@ -153,8 +153,12 @@ void neuronspi_uart_flush_buffer(struct uart_port* port)
 u32 neuronspi_uart_tx_empty(struct uart_port *port)
 {
        struct neuronspi_port *n_port = to_neuronspi_port(port, port);
-       unipi_uart_trace("ttyNS%d Tx empty? %s\n", port->line, (n_port->tx_fifo_len==0)?"Yes":"No");
-       return (n_port->tx_fifo_len==0) ? TIOCSER_TEMT : 0;
+    int len = n_port->tx_fifo_len;
+    if (len > 0) {
+        unipi_spi_get_tx_fifo(neuronspi_s_dev[n_port->dev_index], n_port);
+    }
+       unipi_uart_trace("ttyNS%d Tx empty? %s\n", port->line, (len==0)?"Yes":"No");
+       return (len==0) ? TIOCSER_TEMT : 0;
 }
 
 u32 neuronspi_uart_get_mctrl(struct uart_port *port)
@@ -273,16 +277,7 @@ s32 neuronspi_uart_request_port(struct uart_port *port)
 }
 
 
-void neuronspi_uart_start_tx(struct uart_port *port)
-{
-       struct neuronspi_port *n_port = to_neuronspi_port(port,port);
-       unipi_uart_trace("Start TX\n");
-
-       if (!kthread_queue_work(n_port->n_spi->primary_worker, &n_port->tx_work)) {
-               //unipi_uart_trace("TX WORK OVERFLOW\n");
-       }
-}
-
+/*
 // set port->tx_fifo_len by reading modbus register
 // return 0 if success, 1 if couldnt read register - fifo len has old value
 int static neuronspi_uart_read_tx_fifo_len(struct neuronspi_port *port) 
@@ -294,8 +289,8 @@ int static neuronspi_uart_read_tx_fifo_len(struct neuronspi_port *port)
     if (port->tx_fifo_reg) {
         spi = neuronspi_s_dev[port->dev_index];
         if (unipispi_modbus_read_register(spi, port->tx_fifo_reg, &read_length16) == 0) {
-            port->tx_fifo_len = read_length16;
             ret = 0;
+            port->tx_fifo_len = read_length16;
         }
        } else {
         // unknown port!
@@ -305,53 +300,20 @@ int static neuronspi_uart_read_tx_fifo_len(struct neuronspi_port *port)
        unipi_uart_trace("ttyNS%d Get tx fifo len:%d err:%d\n", port->port.line, read_length16, ret);
        return ret;
 }
+*/
 
-
-void neuronspi_rx_queue_clear(struct neuronspi_port *port, u8 data)
-{
-    port->rx_qlen_secondary = 0;
-}
-
-int neuronspi_rx_queue_add(struct neuronspi_port *port, u8 data)
-{
-       unsigned long flags;
-    int ret = 1;
-    spin_lock_irqsave(&port->rx_queue_lock, flags);
-    if (port->rx_qlen_primary < MAX_RX_QUEUE_LEN) {
-        port->rx_queue_primary[port->rx_qlen_primary++] = data;
-        ret = 0;
-    }
-    spin_unlock_irqrestore(&port->rx_queue_lock, flags);
-    return ret;
-}
-
-void neuronspi_rx_queue_swap(struct neuronspi_port *port)
-{
-       unsigned long flags;
-    u8* x;
-    
-    spin_lock_irqsave(&port->rx_queue_lock, flags);
-    x = port->rx_queue_primary;
-    port->rx_queue_primary = port->rx_queue_secondary;
-    port->rx_queue_secondary = x;
-    port->rx_qlen_secondary = port->rx_qlen_primary;
-    port->rx_qlen_primary = 0;
-    spin_unlock_irqrestore(&port->rx_queue_lock, flags);
-}
-
-static void neuronspi_uart_handle_rx(struct neuronspi_port *port, int rxlen, u8* pbuf)
+void neuronspi_uart_handle_rx(struct neuronspi_port *port, int rxlen, u8* pbuf)
 {
        unsigned long flags;
-       u32 ch, flag, bytes_read, i;
+       u32 ch, flag, i;
     
     unipi_uart_trace("ttyNS%d Insert Chars (%d): %16ph\n", port->port.line, rxlen, pbuf);
 
-       while (rxlen) {
-               bytes_read = rxlen;
+       if (rxlen) {
                spin_lock_irqsave(&port->port.lock, flags);
                port->port.icount.rx++;
                flag = TTY_NORMAL;
-               for (i = 0; i < bytes_read; ++i) {
+               for (i = 0; i < rxlen; ++i) {
 
                        ch = *pbuf;
             pbuf++;
@@ -360,7 +322,6 @@ static void neuronspi_uart_handle_rx(struct neuronspi_port *port, int rxlen, u8*
 
                        uart_insert_char(&port->port, 0, 0, ch, flag);
                }
-               rxlen -= bytes_read;
                spin_unlock_irqrestore(&port->port.lock, flags);
        }
        tty_flip_buffer_push(&port->port.state->port);
@@ -370,7 +331,7 @@ static void neuronspi_uart_handle_rx(struct neuronspi_port *port, int rxlen, u8*
 #define start_tx_timer(port, lowlimit, delta) hrtimer_start_range_ns(&port->tx_timer, lowlimit * port->one_char_nsec, delta*port->one_char_nsec, HRTIMER_MODE_REL)
 
 #define MAX_TXLEN      (NEURONSPI_FIFO_SIZE >> 1)
-
+/*
 void neuronspi_uart_handle_tx(struct neuronspi_port *port)
 {
        int to_send, to_send_packet, ret, need;
@@ -429,8 +390,8 @@ void neuronspi_uart_handle_tx(struct neuronspi_port *port)
                     return;
                 }
         }
-            
-               /* Read data from tty buffer and send it to spi */
+        
+               // Read data from tty buffer and send it to spi
         spin_lock_irqsave(&port->port.lock, flags);
                port->port.icount.tx += to_send_packet;
                new_tail = (xmit->tail + to_send_packet) & (UART_XMIT_SIZE - 1);
@@ -464,71 +425,137 @@ void neuronspi_uart_handle_tx(struct neuronspi_port *port)
         }
        }
 }
+*/
 
-// callback of tx_timer. Schedule port->tx_work
-static enum hrtimer_restart neuronspi_uart_timer_func(struct hrtimer *timer)
+
+void unipi_uart_handle_tx(struct neuronspi_port *port, int calling) /* new async ver */
 {
-    struct neuronspi_port* n_port = ((container_of((timer), struct neuronspi_port, tx_timer)));
+       int to_send, to_send_packet, need;
+       //unsigned long flags;
+       struct circ_buf *xmit;
+       int new_tail;
+       struct spi_device *spi = neuronspi_s_dev[port->dev_index];
+       //struct neuronspi_driver_data *d_data = spi_get_drvdata(spi);
 
-       kthread_queue_work(n_port->n_spi->primary_worker, &n_port->tx_work);
-       return HRTIMER_NORESTART;
-}
+    //port->port.lock taken, This call must not sleep
 
+       if (unlikely(port->port.x_char)) {
+        // zatim nevim, co s tim
+               port->port.icount.tx++;
+               port->port.x_char = 0;
+       }
 
-void neuronspi_uart_tx_proc(struct kthread_work *ws)
+       xmit = &port->port.state->xmit;
+       //spin_lock_irqsave(&port->port.lock, flags);
+       // Get length of data pending in circular buffer
+       to_send = uart_circ_chars_pending(xmit);
+    unipi_uart_trace("ttyNS%d Handle TX. to_send=%d calling=%d\n", port->port.line, to_send, calling);
+       if ((to_send == 0) || uart_tx_stopped(&port->port)) {
+               port->pending_txop = 0;
+               //spin_unlock_irqrestore(&port->port.lock, flags);
+        // check tx_fifo status
+        if (port->tx_fifo_len) {
+            unipi_uart_trace_1("ttyNS%d Handle TX. Start timer=%llu", port->port.line, port->tx_fifo_len * port->one_char_nsec);
+            start_tx_timer(port, port->tx_fifo_len, 2);
+        }
+               return;
+       }
+   
+    // Limit to size of (TX FIFO / 2)
+    to_send_packet = (to_send > MAX_TXLEN) ? MAX_TXLEN : to_send;
+    need = to_send_packet - (NEURONSPI_FIFO_SIZE - port->tx_fifo_len);
+    if (need > 0) {
+               //spin_unlock_irqrestore(&port->port.lock, flags);
+        if (calling!=CB_GETTXFIFO) {
+            if (unipi_spi_get_tx_fifo(spi, port) == 0) return;
+               }
+        // reschedule work with pause
+               port->pending_txop = 0;
+        start_tx_timer(port, need, NEURONSPI_FIFO_SIZE/4);
+        return;
+    }
+            
+    // Read data from tty buffer and send it to spi
+    //spin_lock_irqsave(&port->port.lock, flags);
+    port->port.icount.tx += to_send_packet;
+    new_tail = (xmit->tail + to_send_packet) & (UART_XMIT_SIZE - 1);
+    if (new_tail <= xmit->tail) {
+        memcpy(port->tx_send_msg, xmit->buf+xmit->tail, UART_XMIT_SIZE - xmit->tail);
+        memcpy(port->tx_send_msg+UART_XMIT_SIZE - xmit->tail, xmit->buf, new_tail);
+    } else {
+        memcpy(port->tx_send_msg, xmit->buf+xmit->tail, to_send_packet);
+    }
+    xmit->tail = new_tail;
+    //spin_unlock_irqrestore(&port->port.lock, flags);
+
+    unipi_uart_trace("ttyNS%d Handle TX Send: %d %16ph\n", port->port.line, to_send_packet, port->tx_send_msg);
+    if (unipi_spi_write_str(spi, port, to_send_packet) != 0) {
+               //ERROR, try later
+               port->pending_txop = 0;
+        start_tx_timer(port, 10, NEURONSPI_FIFO_SIZE/4);
+       } else if ((to_send-to_send_packet) < WAKEUP_CHARS) {
+        uart_write_wakeup(&port->port);
+    }
+}
+
+void unipi_uart_start_tx(struct uart_port *port)
 {
-       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);
+       struct neuronspi_port *n_port = to_neuronspi_port(port,port);
+       unsigned long flags;
+       unipi_uart_trace("Start TX. is_pending=%d\n", n_port->pending_txop);
+
+       if (!n_port->pending_txop) {
+               spin_lock_irqsave(&n_port->txop_lock, flags);
+               if (!n_port->pending_txop) {
+                       n_port->pending_txop = 1;
+                       spin_unlock_irqrestore(&n_port->txop_lock, flags);
+                       unipi_uart_handle_tx(n_port, START_TX);
+                       return;
+               }
+               spin_unlock_irqrestore(&n_port->txop_lock, flags);
        }
-*/
-       neuronspi_uart_handle_tx(port);
 }
 
-void neuronspi_uart_rx_proc(struct kthread_work *ws)
+
+// callback of tx_timer. Schedule port->tx_work
+static enum hrtimer_restart unipi_uart_timer_func(struct hrtimer *timer)
 {
-       struct neuronspi_port *n_port = to_neuronspi_port(ws, rx_work);
+    struct neuronspi_port* n_port = ((container_of((timer), struct neuronspi_port, tx_timer)));
        struct spi_device *spi = neuronspi_s_dev[n_port->dev_index];
+       unsigned long flags;
+       
+       if (!n_port->pending_txop) {
+               spin_lock_irqsave(&n_port->txop_lock, flags);
+               if (!n_port->pending_txop) {
+                       n_port->pending_txop = 1;
+                       spin_unlock_irqrestore(&n_port->txop_lock, flags);
+                       if (unipi_spi_get_tx_fifo(spi, n_port) != 0) {
+                               n_port->pending_txop = 0; // ERROR
+                       }
+                       return HRTIMER_NORESTART;
+               }
+               spin_unlock_irqrestore(&n_port->txop_lock, flags);
+       }
+       return HRTIMER_NORESTART;
+}
 
-       u8 *recv_buf = kzalloc(NEURONSPI_BUFFER_MAX, GFP_ATOMIC);
-
-    if (n_port->rx_qlen_secondary) {
-        //send to tty and clear secondary queue
-        neuronspi_uart_handle_rx(n_port, n_port->rx_qlen_secondary, n_port->rx_queue_secondary);
-        n_port->rx_qlen_secondary = 0;
-    }
-    
-    #if NEURONSPI_DETAILED_DEBUG > 0
-        memset(recv_buf, 0, NEURONSPI_BUFFER_MAX); 
-    #endif
+/*
+// callback of tx_timer. Schedule port->tx_work
+static enum hrtimer_restart neuronspi_uart_timer_func(struct hrtimer *timer)
+{
+    struct neuronspi_port* n_port = ((container_of((timer), struct neuronspi_port, tx_timer)));
 
-    neuronspi_spi_uart_read(spi, recv_buf, n_port->rx_remain, n_port->dev_port);
+       kthread_queue_work(n_port->n_spi->primary_worker, &n_port->tx_work);
+       return HRTIMER_NORESTART;
+}
 
-    if (recv_buf[0] == 0x65) {
-        if (n_port->rx_qlen_secondary) {
-            neuronspi_uart_handle_rx(n_port, n_port->rx_qlen_secondary, n_port->rx_queue_secondary);
-            n_port->rx_qlen_secondary = 0;
-        }
-               if (recv_buf[1] > 0) {
-            // send string to tty
-            neuronspi_uart_handle_rx(n_port,  recv_buf[1], recv_buf+4);
-        }
-    }
-    neuronspi_rx_queue_swap(n_port);
-    if (n_port->rx_qlen_secondary) {
-        //send to tty and clear secondary queue
-        neuronspi_uart_handle_rx(n_port, n_port->rx_qlen_secondary, n_port->rx_queue_secondary);
-        n_port->rx_qlen_secondary = 0;
-    }
 
-    if (n_port->rx_remain > 0) {
-               kthread_queue_work(n_port->n_spi->primary_worker, &n_port->rx_work);
-    }
-       kfree(recv_buf);
+void neuronspi_uart_tx_proc(struct kthread_work *ws)
+{
+       struct neuronspi_port *n_port = to_neuronspi_port(ws, tx_work);
+       neuronspi_uart_handle_tx(n_port);
 }
-
+*/
 
 // Initialise the driver - called once on open
 s32 neuronspi_uart_startup(struct uart_port *port)
@@ -562,12 +589,9 @@ void neuronspi_uart_remove(struct spi_device* spi)
         port = neuronspi_uart_data_global->p + i + n_spi->uart_pindex;
         hrtimer_cancel(&port->tx_timer);
                uart_remove_one_port(neuronspi_uart_driver_global, &port->port);
-        kthread_flush_work(&(port->rx_work));
-        kthread_flush_work(&(port->tx_work));
+        //kthread_flush_work(&(port->tx_work));
 
                neuronspi_uart_power(&port->port, 0);
-        kfree(port->rx_queue_primary);
-        kfree(port->rx_queue_secondary);
         printk(KERN_INFO "UNIPIUART: Serial port ttyNS%d removed\n", i + n_spi->uart_pindex);
        }
 }
@@ -579,7 +603,7 @@ static const struct uart_ops neuronspi_uart_ops =
        .set_mctrl                      = neuronspi_uart_set_mctrl,
        .get_mctrl                      = neuronspi_uart_get_mctrl,
        .stop_tx                        = neuronspi_uart_null_void,
-       .start_tx                       = neuronspi_uart_start_tx,
+       .start_tx                       = unipi_uart_start_tx,
        .stop_rx                        = neuronspi_uart_null_void,
        .flush_buffer           = neuronspi_uart_flush_buffer,
        .break_ctl                      = neuronspi_uart_break_ctl,
@@ -624,10 +648,14 @@ int neuronspi_uart_probe(struct spi_device* spi, struct neuronspi_driver_data *n
             port->port.ops     = &neuronspi_uart_ops;
             spin_lock_init(&port->port.lock);
 
-            spin_lock_init(&port->rx_queue_lock);
-            port->rx_queue_primary = kzalloc(MAX_RX_QUEUE_LEN, GFP_ATOMIC);   
-            port->rx_queue_secondary = kzalloc(MAX_RX_QUEUE_LEN, GFP_ATOMIC); 
+            spin_lock_init(&port->rx_in_progress_lock);
+            port->rx_send_buf.second_message = port->rx_send_msg;
+            port->rx_recv_buf.second_message = port->rx_recv_msg;
 
+            spin_lock_init(&port->txop_lock);
+            port->tx_send_buf.second_message = port->tx_send_msg;
+            port->tx_recv_buf.second_message = port->tx_recv_msg;
+            
             port->tx_fifo_len = 0x7fff; //set it to big number; invoke reading current value from Neuron
             if (n_spi && (n_spi->firmware_version >= 0x0519) ) {
                 port->tx_fifo_reg = port_to_uartregs(i,NEURONSPI_UART_FIFO_REGISTER);        // define modbus register
@@ -636,10 +664,9 @@ int neuronspi_uart_probe(struct spi_device* spi, struct neuronspi_driver_data *n
             }
 
             hrtimer_init(&port->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-            port->tx_timer.function = neuronspi_uart_timer_func;
+            port->tx_timer.function = unipi_uart_timer_func;
             
-            kthread_init_work(&(port->tx_work), neuronspi_uart_tx_proc);
-            kthread_init_work(&(port->rx_work), neuronspi_uart_rx_proc);
+            //kthread_init_work(&(port->tx_work), neuronspi_uart_tx_proc);
             uart_add_one_port(neuronspi_uart_driver_global, &port->port);
             printk(KERN_INFO "UNIPIUART: Serial port ttyNS%d on UniPi Board nspi%d port:%d created\n", neuronspi_uart_data_global->p_count, port->dev_index, port->dev_port);
             unipi_uart_trace("Probe cflag:%08x\n", neuronspi_spi_uart_get_cflag(spi, i));
index 636515aae1fb2e4348f9292aff4bb0033bc0ae51..14b3980605cd2bcbdcd4bc33d0a7ecaeb84d0f80 100644 (file)
@@ -33,6 +33,9 @@
 
 int neuronspi_rx_queue_add(struct neuronspi_port *port, u8 data);
 void neuronspi_rx_queue_swap(struct neuronspi_port *port);
+void neuronspi_uart_handle_rx(struct neuronspi_port *port, int rxlen, u8* pbuf);
+void unipi_uart_handle_tx(struct neuronspi_port *port, int calling);
+
 
 int neuronspi_uart_driver_init(void);
 int neuronspi_uart_driver_exit(void);