From 7d272d889974175d2c1c66057bdb2f06284e05b6 Mon Sep 17 00:00:00 2001 From: Miroslav Ondra Date: Wed, 27 Mar 2019 16:49:22 +0100 Subject: [PATCH] rework spi to use async calling and RT kthread --- debian/changelog | 6 + debian/neuron-kernel.changelog | 12 + modules/unipi/src/unipi_common.h | 32 +- modules/unipi/src/unipi_iio.c | 124 ++-- modules/unipi/src/unipi_platform.c | 181 +++++- modules/unipi/src/unipi_platform.h | 6 +- modules/unipi/src/unipi_spi.c | 884 ++++++++++++++++++++--------- modules/unipi/src/unipi_spi.h | 16 +- modules/unipi/src/unipi_uart.c | 257 +++++---- modules/unipi/src/unipi_uart.h | 3 + 10 files changed, 1075 insertions(+), 446 deletions(-) diff --git a/debian/changelog b/debian/changelog index 61da8c2..393998b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +unipi-kernel-modules (1.21) unstable; urgency=medium + + * rework spi to use async calling and RT kthread + + -- Miroslav Ondra Wed, 27 Mar 2019 16:43:52 +0100 + unipi-kernel-modules (1.20) unstable; urgency=medium * fix line discipline setting on standard uarts diff --git a/debian/neuron-kernel.changelog b/debian/neuron-kernel.changelog index 84ace88..03f3552 100644 --- a/debian/neuron-kernel.changelog +++ b/debian/neuron-kernel.changelog @@ -1,3 +1,15 @@ +unipi-kernel-modules (1.21.1.20190215-1) unstable; urgency=medium + + * Compiled for raspberrypi-kernel 1.20190215-1 + + -- Miroslav Ondra 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 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 diff --git a/modules/unipi/src/unipi_common.h b/modules/unipi/src/unipi_common.h index 92b6b88..cad9e6e 100644 --- a/modules/unipi/src/unipi_common.h +++ b/modules/unipi/src/unipi_common.h @@ -46,12 +46,13 @@ /*************** * 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 #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; }; diff --git a/modules/unipi/src/unipi_iio.c b/modules/unipi/src/unipi_iio.c index 59691b9..1eb2820 100644 --- a/modules/unipi/src/unipi_iio.c +++ b/modules/unipi/src/unipi_iio.c @@ -26,29 +26,68 @@ * 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, }; diff --git a/modules/unipi/src/unipi_platform.c b/modules/unipi/src/unipi_platform.c index 56dc7fa..425b26a 100644 --- a/modules/unipi/src/unipi_platform.c +++ b/modules/unipi/src/unipi_platform.c @@ -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 diff --git a/modules/unipi/src/unipi_platform.h b/modules/unipi/src/unipi_platform.h index 6f3def2..9fe2670 100644 --- a/modules/unipi/src/unipi_platform.h +++ b/modules/unipi/src/unipi_platform.h @@ -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 diff --git a/modules/unipi/src/unipi_spi.c b/modules/unipi/src/unipi_spi.c index 2dfb1e2..d5e0d11 100644 --- a/modules/unipi/src/unipi_spi.c +++ b/modules/unipi/src/unipi_spi.c @@ -17,6 +17,8 @@ /************ * Includes * ************/ +#include +#include #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(¤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; @@ -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); diff --git a/modules/unipi/src/unipi_spi.h b/modules/unipi/src/unipi_spi.h index 7f1c85b..6852203 100644 --- a/modules/unipi/src/unipi_spi.h +++ b/modules/unipi/src/unipi_spi.h @@ -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); diff --git a/modules/unipi/src/unipi_uart.c b/modules/unipi/src/unipi_uart.c index 2c946c7..e0817c2 100644 --- a/modules/unipi/src/unipi_uart.c +++ b/modules/unipi/src/unipi_uart.c @@ -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)); diff --git a/modules/unipi/src/unipi_uart.h b/modules/unipi/src/unipi_uart.h index 636515a..14b3980 100644 --- a/modules/unipi/src/unipi_uart.h +++ b/modules/unipi/src/unipi_uart.h @@ -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); -- 2.34.1