#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, \
.pwm_channel_count = 0, \
.wd_count = 1, \
.extension_sys_count = 0, \
- .light_count = 4, \
+ .light_count = 0, \
.owire_count = 0, \
}
}
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 *
********************/
{.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
/************
* Includes *
************/
+#include <linux/completion.h>
+#include <linux/cpufreq.h>
#include "unipi_common.h"
#include "unipi_sysfs.h"
#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 ???*/
};
-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
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(¤t_policy->transition_lock);
+ if (unlikely(current_policy->transition_ongoing)) {
+ spin_unlock(¤t_policy->transition_lock);
+ goto wait;
+ }
+
+ current_policy->transition_ongoing = true;
+ current_policy->transition_task = current;
+ spin_unlock(¤t_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(¤t_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;
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;
}
* 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;
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));
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));
*((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);
*((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;
*((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;
}
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;
}
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;
}
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);
}
}
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;
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)) {
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);
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);
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)
}
-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)
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!
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++;
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);
#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;
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);
}
}
}
+*/
-// 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)
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);
}
}
.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,
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
}
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));