/* * Copyright (C) 2021-23 Texas Instruments Incorporated * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPgResS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include static struct endat_priv endat_priv; /* * check 2.2 command case with 2.2 capability in encoder, can live w/o as endat_get_command * will handle and it is assumed that functions, * endat_recvd_organize() * endat_recvd_format() * endat_recvd_validate() * endat_recvd_print() * will normally be called after endat_get_command */ static int32_t endat_recvd_organize(int32_t cmd, struct endat_priv *priv, struct endat_data *endat_data) { uint32_t word0, word1, word2, word3; uint32_t pos_bits, shift; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; memset(endat_data, 0, sizeof(*endat_data)); word0 = pruss_xchg->ch[priv->channel].pos_word0; word1 = pruss_xchg->ch[priv->channel].pos_word1; word2 = pruss_xchg->ch[priv->channel].pos_word2; word3 = pruss_xchg->ch[priv->channel].pos_word3; switch(cmd) { case 2: case 3: case 4: case 5: case 7: case 14: endat_data->recvd1 = word0; break; case 6: shift = ENDAT_RX_46BITS % (sizeof(unsigned) * 8); endat_data->recvd1 = (uint64_t) word0 << shift | word1; break; case 1: pos_bits = priv->pos_res + ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1; if(pos_bits <= sizeof(unsigned) * 8) { endat_data->recvd1 = word0; } else { shift = pos_bits % (sizeof(unsigned) * 8); endat_data->recvd1 = (uint64_t) word0 << shift | word1; } break; case 8: case 9: case 10: case 11: case 12: case 13: pos_bits = priv->pos_res + ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1 + ENDAT_NUM_BITS_F2; if(pos_bits <= sizeof(unsigned) * 8) { endat_data->recvd1 = word0; } else { shift = pos_bits % (sizeof(unsigned) * 8); endat_data->recvd1 = (uint64_t) word0 << shift | word1; } if(priv->flags.info1 || priv->flags.info2) { endat_data->recvd2 = word2; } if(priv->flags.info1 && priv->flags.info2) { endat_data->recvd3 = word3; } break; default: return -EINVAL; break; } return 0; } /* value to be reflected should be aligned to lsb, relected value would be aligned to lsb */ static uint64_t endat_reflect_ull_nbits(uint64_t input, uint32_t n) { uint32_t i; uint64_t val = 0; /* val initialized to 0 above to handle n = 0 case, otherwise garbage would be returned */ for(i = 0; i < n; i++) { val <<= 1; if(input & ((uint64_t) 1 << i)) { val |= 1; } } return val; } static int64_t endat_recvd_format(int32_t cmd, struct endat_priv *priv, struct endat_data *endat_data, union endat_format_data *u) { uint64_t pos, rev; switch(cmd) { case 2: case 3: case 4: case 5: case 7: case 14: u->addr_params.params = (endat_data->recvd1 >> ENDAT_NUM_BITS_POSITION_CRC) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); u->addr_params.address = (endat_data->recvd1 >> (ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_PARAMETER)) & ((1 << ENDAT_NUM_BITS_ADDRESS) - 1); u->addr_params.crc = endat_data->recvd1 & ((1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); break; case 6: u->test.value = (endat_data->recvd1 >> ENDAT_NUM_BITS_POSITION_CRC) & ((( uint64_t)1 << 40) - 1); u->test.f1 = (endat_data->recvd1 >> (ENDAT_NUM_BITS_POSITION_CRC + 40)) & 1; u->test.crc = endat_data->recvd1 & ((1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); break; case 1: pos = endat_data->recvd1 >> ENDAT_NUM_BITS_POSITION_CRC; pos = pos & (((uint64_t) 1 << priv->pos_res) - 1); /* mask F1 */ pos = endat_reflect_ull_nbits(pos, priv->pos_res); rev = (pos & (((uint64_t) 1 << priv->pos_res) - 1)) >> priv->single_turn_res; pos = pos & (((uint64_t) 1 << priv->single_turn_res) - 1); u->position_addinfo.position.position = pos; u->position_addinfo.position.revolution = rev; u->position_addinfo.position.f1 = (endat_data->recvd1 >> (ENDAT_NUM_BITS_POSITION_CRC + priv->pos_res)) & 1; u->position_addinfo.position.crc = endat_data->recvd1 & (( 1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); break; case 8: case 9: case 10: case 11: case 12: case 13: pos = endat_data->recvd1 >> ENDAT_NUM_BITS_POSITION_CRC; pos = pos & (((uint64_t) 1 << priv->pos_res) - 1); /* mask F1/F2 */ pos = endat_reflect_ull_nbits(pos, priv->pos_res); rev = (pos & (((uint64_t) 1 << priv->pos_res) - 1)) >> priv->single_turn_res; pos = pos & (((uint64_t) 1 << priv->single_turn_res) - 1); u->position_addinfo.position.position = pos; u->position_addinfo.position.revolution = rev; u->position_addinfo.position.f1 = (endat_data->recvd1 >> (ENDAT_NUM_BITS_POSITION_CRC + priv->pos_res + 1)) & 1; u->position_addinfo.position.f2 = (endat_data->recvd1 >> (ENDAT_NUM_BITS_POSITION_CRC + priv->pos_res)) & 1; u->position_addinfo.position.crc = endat_data->recvd1 & (( 1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); if(priv->flags.info1 || priv->flags.info2) { if(endat_priv.flags.info2) { u->position_addinfo.addinfo2.addinfo = (endat_data->recvd2 >> ENDAT_NUM_BITS_POSITION_CRC) & ((1 << 24) - 1); u->position_addinfo.addinfo2.crc = endat_data->recvd2 & (( 1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); } else { u->position_addinfo.addinfo1.addinfo = (endat_data->recvd2 >> ENDAT_NUM_BITS_POSITION_CRC) & ((1 << 24) - 1); u->position_addinfo.addinfo1.crc = endat_data->recvd2 & (( 1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); } } if(priv->flags.info1 && priv->flags.info2) { u->position_addinfo.addinfo1.addinfo = (endat_data->recvd3 >> ENDAT_NUM_BITS_POSITION_CRC) & ((1 << 24) - 1); u->position_addinfo.addinfo1.crc = endat_data->recvd3 & (( 1 << ENDAT_NUM_BITS_POSITION_CRC) - 1); } break; default: return -EINVAL; break; } return 0; } int32_t endat_recvd_process(struct endat_priv *priv, int32_t cmd, union endat_format_data *u) { struct endat_data endat_data; int32_t ret; ret = endat_recvd_organize(cmd, priv, &endat_data); if(ret < 0) { return ret; } return endat_recvd_format(cmd, priv, &endat_data, u); } #define ENDAT_USE_OTF_CRC_STATUS #ifndef ENDAT_USE_OTF_CRC_STATUS static uint32_t make_crc_norm(uint32_t param8, uint32_t param16) { /* state of the 5 flip-flops */ uint32_t ff[5]; /* data bit array */ uint32_t code[24]; /* Auxiliary variable */ uint32_t ex; /* dtetermined CRC code */ uint32_t crc = 0; /* controlled variable for looping */ int32_t i; /* set all flip-flops to 1 */ for(i = 0; i < 5; i++) { ff[i] = 1; } /* read 8 bit parameter into code array and convert bit sequence */ for(i = 0; i < 8; i++) { code[i] = (param8 & 0x0080) ? 1 : 0; param8 <<= 1; } /* read 16 bit parameter into code array and convert bit sequence */ for(i = 8; i < 24; i++) { code[i] = (param16 & 0x8000) ? 1 : 0; param16 <<= 1; } /* calculate crc analog to described h/w generator */ for(i = 0; i < 24; i++) { ex = ff[4] ^ code[i]; ff[4] = ff[3]; ff[3] = ff[2] ^ ex; ff[2] = ff[1]; ff[1] = ff[0] ^ ex; ff[0] = ex; } /* store crc in variable */ for(i = 4; i >= 0; i--) { ff[i] = ff[i] ? 0 : 1; crc <<= 1; crc |= ff[i]; } return crc; } static uint32_t make_crc_pos(uint32_t clocks, uint32_t error1, uint32_t error2, uint32_t endat22, uint64_t highpos, uint64_t lowpos) { /* state of the 5 flip-flops */ uint32_t ff[5]; /* data bit array */ uint32_t code[66]; /* Auxiliary variable */ uint32_t ex; /* dtetermined CRC code */ uint32_t crc = 0; /* controlled variable for looping */ int32_t i; /* set all flip-flops to 1 */ for(i = 0; i < 5; i++) { ff[i] = 1; } /* transfer alarm bits to code array */ if(endat22) { code[0] = error1; code[1] = error2; } else { code[1] = error1; } /* transfer low pos bits to array */ for(i = 2; i < 34; i++) { code[i] = (lowpos & 0x00000001L) ? 1 : 0; lowpos >>= 1; } /* transfer high pos bits to array */ for(i = 34; i < 66; i++) { code[i] = (highpos & 0x00000001L) ? 1 : 0; highpos >>= 1; } /* calculate crc analog to described h/w generator */ for(i = (endat22 ? 0 : 1); i <= (clocks + 1); i++) { ex = ff[4] ^ code[i]; ff[4] = ff[3]; ff[3] = ff[2] ^ ex; ff[2] = ff[1]; ff[1] = ff[0] ^ ex; ff[0] = ex; } /* store crc in variable */ for(i = 4; i >= 0; i--) { ff[i] = ff[i] ? 0 : 1; crc <<= 1; crc |= ff[i]; } return crc; } #endif /* return crc status: bit0 - position/address params/test, bit1 - additional info1, bit2 - additional info2. return -EINVAL on failure */ uint32_t endat_recvd_validate(struct endat_priv *priv, int32_t cmd, union endat_format_data *u) { uint32_t status = 0; #ifdef ENDAT_USE_OTF_CRC_STATUS uint8_t val; #else uint32_t crc; uint64_t highpos, lowpos; uint64_t test; #endif #ifdef ENDAT_USE_OTF_CRC_STATUS val = priv->pruss_xchg->ch[priv->channel].crc.status; if(priv->flags.info2) { status = val & 0x1; /* move bit 1 to bit 2 */ status |= (val & 0x2) << 1; if(priv->flags.info1) { /* move bit 2 to bit 1 */ status |= (val & 0x4) >> 1; } } else { /* either additional info1 only present or no additional info present */ status = val & 0x3; } #else switch(cmd) { case 1: lowpos = (u->position_addinfo.position.revolution << priv->single_turn_res | u->position_addinfo.position.position) & 0xFFFFFFFF; highpos = (u->position_addinfo.position.revolution << priv->single_turn_res | u->position_addinfo.position.position) >> 32; crc = make_crc_pos(priv->pos_res, u->position_addinfo.position.f1, 0, 0, highpos, lowpos); if(u->position_addinfo.position.crc == crc) { status = 0x1; } break; case 6: test = endat_reflect_ull_nbits(u->test.value, 40); lowpos = test & 0xFFFFFFFF; highpos = test >> 32; crc = make_crc_pos(40, u->position_addinfo.position.f1, 0, 0, highpos, lowpos); if(u->test.crc == crc) { status = 0x1; } break; case 8: case 9: case 10: case 11: case 12: case 13: lowpos = (u->position_addinfo.position.revolution << priv->single_turn_res | u->position_addinfo.position.position) & 0xFFFFFFFF; highpos = (u->position_addinfo.position.revolution << priv->single_turn_res | u->position_addinfo.position.position) >> 32; crc = make_crc_pos(priv->pos_res, u->position_addinfo.position.f1, u->position_addinfo.position.f2, 1, highpos, lowpos); if(u->position_addinfo.position.crc == crc) { status = 0x1; } if(priv->flags.info1) { crc = make_crc_norm((u->position_addinfo.addinfo1.addinfo >> 16) & 0xFF, u->position_addinfo.addinfo1.addinfo & 0xFFFF); if(u->position_addinfo.addinfo1.crc == crc) { status |= 0x1 << 1; } } if(priv->flags.info2) { crc = make_crc_norm((u->position_addinfo.addinfo2.addinfo >> 16) & 0xFF, u->position_addinfo.addinfo2.addinfo & 0xFFFF); if(u->position_addinfo.addinfo2.crc == crc) { status |= 0x1 << 2; } } break; case 2: case 3: case 4: case 5: case 7: crc = make_crc_norm(u->addr_params.address, u->addr_params.params); if(u->addr_params.crc == crc) { status = 0x1; } break; default: break; } #endif return status; } /* * XXX: check 2.2 command case with 2.2 capability in encoder, can live w/o as endat_get_command * will handle and it is assumed that this function will be called either after endat_get_command * or by diagnostic initialization code where it is only 2.1 commands used */ int32_t endat_command_build(struct endat_priv *priv, int32_t cmd, struct cmd_supplement *cmd_supplement) { uint32_t info; struct endat_pruss_xchg *endat_pruss_xchg = priv->pruss_xchg; info = 0, priv->flags.info1 ? info++ : 0, priv->flags.info2 ? info++ : 0 ; /*first clear command parameters to be safe */ memset(&endat_pruss_xchg->cmd, 0, sizeof(endat_pruss_xchg->cmd)); switch(cmd) { case 1: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSITION_VALUES; endat_pruss_xchg->cmd[0].word1 = priv->pos_rx_bits_21_RTUPRU | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_POSITION) << 16); if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSITION_VALUES; endat_pruss_xchg->cmd[1].word1 = priv->pos_rx_bits_21_PRU | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_POSITION) << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSITION_VALUES; endat_pruss_xchg->cmd[2].word1 = priv->pos_rx_bits_21_TXPRU | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_POSITION) << 16); } /* command build for ch1 and ch2 in load share mode*/ break; case 2: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEL_MEM_AREA; endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); /*build separate command for all three channel in loadshare mode*/ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEL_MEM_AREA; endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEL_MEM_AREA; endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); } break; case 3: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_RECEIVE_PARAMETERS; endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->data & 0x8000) >> 7) | (((cmd_supplement->data << 1) & 0xFF00) << 8) | (((cmd_supplement->data << 9) & 0xFE00) << 16); endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); /*build separate command for all three channel in loadshare mode*/ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_RECEIVE_PARAMETERS; endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->data & 0x8000) >> 7) | (((cmd_supplement->data << 1) & 0xFF00) << 8) | (((cmd_supplement->data << 9) & 0xFE00) << 16); endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_RECEIVE_PARAMETERS; endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->data & 0x8000) >> 7) | (((cmd_supplement->data << 1) & 0xFF00) << 8) | (((cmd_supplement->data << 9) & 0xFE00) << 16); endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); } break; case 4: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_PARAMETERS; endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); /*build separate command for all three channel in loadshare mode */ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_PARAMETERS; endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_PARAMETERS; endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); } break; case 5: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_RECEIVE_RESET; endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); /*build separate command for all three channel in loadshare mode*/ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_RECEIVE_RESET; endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_RECEIVE_RESET; endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); } break; case 6: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_TEST_VALUES; endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_46BITS | (ENDAT_TX_6BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); /*build separate command for all three channel in loadshare mode*/ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_TEST_VALUES; endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_46BITS | (ENDAT_TX_6BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_TEST_VALUES; endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_46BITS | (ENDAT_TX_6BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); } break; case 7: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_RECEIVE_TEST_COMMAND; endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); /*build separate command for all three channel in loadshare mode*/ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_RECEIVE_TEST_COMMAND; endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_RECEIVE_TEST_COMMAND; endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | (ENDAT_CMDTYP_NO_SUPPLEMENT << 16); } break; case 8: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSVAL_WITH_DATA; /* * Though this is not 2.1 command, fw expects it to be ENDAT_CMDTYP_2_1. Ideally macro should * have been named ENDAT_CMDTYPE_HAVE_2_2_SUPPLEMENT instead of ENDAT_CMDTYP_2_[12] for readability */ endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); /*build separate command for all three channel in loadshare mode*/ if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSVAL_WITH_DATA; /* * Though this is not 2.1 command, fw expects it to be ENDAT_CMDTYP_2_1. Ideally macro should * have been named ENDAT_CMDTYPE_HAVE_2_2_SUPPLEMENT instead of ENDAT_CMDTYP_2_[12] for readability */ endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSVAL_WITH_DATA; /* * Though this is not 2.1 command, fw expects it to be ENDAT_CMDTYP_2_1. Ideally macro should * have been named ENDAT_CMDTYPE_HAVE_2_2_SUPPLEMENT instead of ENDAT_CMDTYP_2_[12] for readability */ endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); } if(priv->flags.info1) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; } } if(priv->flags.info2) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; } } break; case 9: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_MEMSEL; if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_MEMSEL; endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_MEMSEL; } if(cmd_supplement->has_block_address) { endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16) | (1 << 24); endat_pruss_xchg->cmd[0].word2 = cmd_supplement->address | (cmd_supplement->block << 24); if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16) | (1 << 24); endat_pruss_xchg->cmd[1].word2 = cmd_supplement->address | (cmd_supplement->block << 24); endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16) | (1 << 24); endat_pruss_xchg->cmd[2].word2 = cmd_supplement->address | (cmd_supplement->block << 24); } } else { endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[0].word2 = cmd_supplement->address; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[1].word2 = cmd_supplement->address; endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word2 = cmd_supplement->address; } } if(priv->flags.info1) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; } } if(priv->flags.info2) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; } } break; case 10: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_PARAM; endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[0].word2 = cmd_supplement->address; /* data MSByte should be @((char *)word2 + 1) and LSByte @((char *)word2 + 2) */ endat_pruss_xchg->cmd[0].word2 |= ((cmd_supplement->data & 0xFF) << 16) | (cmd_supplement->data & 0xFF00); if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_PARAM; endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[1].word2 = cmd_supplement->address; /* data MSByte should be @((char *)word2 + 1) and LSByte @((char *)word2 + 2) */ endat_pruss_xchg->cmd[1].word2 |= ((cmd_supplement->data & 0xFF) << 16) | (cmd_supplement->data & 0xFF00); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_PARAM; endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word2 = cmd_supplement->address; /* data MSByte should be @((char *)word2 + 1) and LSByte @((char *)word2 + 2) */ endat_pruss_xchg->cmd[2].word2 |= ((cmd_supplement->data & 0xFF) << 16) | (cmd_supplement->data & 0xFF00); } if(priv->flags.info1) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; } } if(priv->flags.info2) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; } } break; case 11: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSVAL_SEND_PARAM; endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[0].word2 = cmd_supplement->address; if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSVAL_SEND_PARAM; endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[1].word2 = cmd_supplement->address; endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSVAL_SEND_PARAM; endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word2 = cmd_supplement->address; } if(priv->flags.info1) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; } } if(priv->flags.info2) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; } } break; case 12: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_ERR_RST; endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_ERR_RST; endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_ERR_RST; endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); } if(priv->flags.info1) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; } } if(priv->flags.info2) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; } } break; case 13: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_TESTCMD; endat_pruss_xchg->cmd[0].word1 = (priv->pos_rx_bits_22_RTUPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[0].word2 = cmd_supplement->address; if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_TESTCMD; endat_pruss_xchg->cmd[1].word1 = (priv->pos_rx_bits_22_PRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[1].word2 = cmd_supplement->address; endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_SEND_POSVAL_RECEIVE_TESTCMD; endat_pruss_xchg->cmd[2].word1 = (priv->pos_rx_bits_22_TXPRU + info * ENDAT_ADDITIONAL_INFO_RX_BITS) | (ENDAT_TX_6BITS << 8) | ((ENDAT_CMDTYP_POSITION | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word2 = cmd_supplement->address; } if(priv->flags.info1) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO1) << 16; } } if(priv->flags.info2) { endat_pruss_xchg->cmd[0].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; if(priv->load_share) { endat_pruss_xchg->cmd[1].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; endat_pruss_xchg->cmd[2].word1 |= (ENDAT_CMDTYP_HAS_ADDINFO2) << 16; } } break; case 14: endat_pruss_xchg->cmd[0].word0 = ENDAT_CMD_RECEIVE_COMMUNICATION_CMD; endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[0].word0 |= ((cmd_supplement->data & 0x8000) >> 7) | (((cmd_supplement->data << 1) & 0xFF00) << 8) | (((cmd_supplement->data << 9) & 0xFE00) << 16); endat_pruss_xchg->cmd[0].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_ENDAT22) << 16); if(priv->load_share) { endat_pruss_xchg->cmd[1].word0 = ENDAT_CMD_RECEIVE_COMMUNICATION_CMD; endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[1].word0 |= ((cmd_supplement->data & 0x8000) >> 7) | (((cmd_supplement->data << 1) & 0xFF00) << 8) | (((cmd_supplement->data << 9) & 0xFE00) << 16); endat_pruss_xchg->cmd[1].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_ENDAT22) << 16); endat_pruss_xchg->cmd[2].word0 = ENDAT_CMD_RECEIVE_COMMUNICATION_CMD; endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->address & 0x80) >> 7) | (((cmd_supplement->address << 1) & 0xFE) << 8); endat_pruss_xchg->cmd[2].word0 |= ((cmd_supplement->data & 0x8000) >> 7) | (((cmd_supplement->data << 1) & 0xFF00) << 8) | (((cmd_supplement->data << 9) & 0xFE00) << 16); endat_pruss_xchg->cmd[2].word1 = ENDAT_RX_29BITS | (ENDAT_TX_30BITS << 8) | ((ENDAT_CMDTYP_NO_SUPPLEMENT | ENDAT_CMDTYP_ENDAT22) << 16); } break; default: cmd = -EINVAL; break; } return cmd; } void endat_command_send(struct endat_priv *priv) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /*for load share mode set mask for all connected channels*/ if(priv->load_share) { pruss_xchg->config[0].trigger = pruss_xchg->config[0].channel==1?0x1:0; pruss_xchg->config[1].trigger = pruss_xchg->config[1].channel==2?0x1:0; pruss_xchg->config[2].trigger = pruss_xchg->config[2].channel==4?0x1:0; } else { pruss_xchg->config[0].trigger = 0x1; } } void endat_command_wait(struct endat_priv *priv) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; if(priv->load_share) { /*waiting till host trigger bits has not clear for all enabled channels*/ while((pruss_xchg->config[0].trigger&0x1) || (pruss_xchg->config[1].trigger &0x1) || (pruss_xchg->config[2].trigger&0x1)) ; } else { while(pruss_xchg->config[0].trigger & 0x1) ; } } void endat_recovery_time_conversion(struct endat_priv *priv) { /* RT: convert cycle to ns */ priv->pruss_xchg->endat_ch0_rt = priv->pruss_xchg->endat_ch0_rt * ((float)(1000000000)/priv->pruss_xchg->icssg_clk); priv->pruss_xchg->endat_ch1_rt = priv->pruss_xchg->endat_ch1_rt * ((float)(1000000000)/priv->pruss_xchg->icssg_clk); priv->pruss_xchg->endat_ch2_rt = priv->pruss_xchg->endat_ch2_rt * ((float)(1000000000)/priv->pruss_xchg->icssg_clk); } int32_t endat_command_process(struct endat_priv *priv, int32_t cmd, struct cmd_supplement *cmd_supplement) { cmd = endat_command_build(priv, cmd, cmd_supplement); if(cmd < 0) { return cmd; } endat_command_send(priv); endat_command_wait(priv); /* RT configuration(convert cycle to ns time ) for command 2.2*/ if( cmd > 7 && cmd < 15 ) { endat_recovery_time_conversion(priv); } return cmd; } int32_t endat_get_2_2_angle(struct endat_priv *priv) { int32_t pos; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; int32_t ch = priv->channel; if(!(pruss_xchg->ch[ch].crc.status & ENDAT_CRC_DATA)) { return -1; } pos = pruss_xchg->ch[ch].pos_word0; #ifdef __TI_ARM__ pos = __rbit(pos); #else asm("rbit %0,%1" : "=r"(pos) : "r"(pos)); #endif /* verify F1 = 0 & F2 = 1 */ if((pos & 0x3) != 0x2) { return -1; } /* discard F1, F2 */ pos >>= 2; /* mask non-angular bits */ pos &= (1 << priv->single_turn_res) - 1; return pos; } static int32_t endat_get_pos_res(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 0 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE0; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw, absence of delay here resulted in wrong values for pos_res */ ClockP_usleep(1000 * 12); /* send parameter for word13 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_13; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 2); word = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & (( 1 << ENDAT_NUM_BITS_PARAMETER) - 1); return word &= (1 << ENDAT_NUM_BITS_VALID_PAGE0_WORD13) - 1; } static int32_t endat_get_multi_turn_res(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 0 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE1; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 12); /* send parameter for word1 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_1; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 2); word = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & (( 1 << ENDAT_NUM_BITS_PARAMETER) - 1); return word &= (1 << ENDAT_NUM_BITS_VALID_PAGE1_WORD1) - 1; } static int32_t endat_get_id(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word0, word1, word2; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 1 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE1; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 12); /* send parameter for word8 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_8; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } word0 = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* delay copied from fw */ ClockP_usleep(1000 * 2); /* send parameter for word9 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_9; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } word1 = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* delay copied from fw */ ClockP_usleep(1000 * 2); /* send parameter for word10 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_10; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } word2 = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* delay copied from fw */ ClockP_usleep(1000 * 2); priv->id.binary = word1 | word2 << 16; /* swap the two ascii's so that printing as string will give what is required */ priv->id.ascii = ((word0 & 0xFF) << 8) | ((word0 & 0xFF00) >> 8); return 0; } static int32_t endat_get_sn(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word0, word1, word2; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 1 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE1; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 12); /* send parameter for word11 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_11; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } word0 = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* delay copied from fw */ ClockP_usleep(1000 * 2); /* send parameter for word12 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_12; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } word1 = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* delay copied from fw */ ClockP_usleep(1000 * 2); /* send parameter for word13 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_13; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } word2 = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* delay copied from fw */ ClockP_usleep(1000 * 2); priv->sn.ascii_lsb = word0 & 0xFF; priv->sn.binary = ((word0 & 0xFF00) >> 8) | (word1 << 8) | (( word2 & 0xFF) << 24); priv->sn.ascii_msb = (word2 & 0xFF00) >> 8; return 0; } static int32_t endat_get_command_set(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 2 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE2; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 12); /* send parameter for word5 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_5; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 2); word = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & (( 1 << ENDAT_NUM_BITS_PARAMETER) - 1); priv->cmd_set_2_2 = (word & 0x1) && !(word & 0x2); priv->has_safety = (word & 0x4) && !(word & 0x8); return 0; } static int32_t endat_get_type(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 0 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE0; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw, absence of delay here resulted in wrong values for pos_res */ ClockP_usleep(1000 * 12); /* send parameter for word13 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_14; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 2); word = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & (( 1 << ENDAT_NUM_BITS_PARAMETER) - 1); priv->type = (word & (1 << 15)) ? rotary : linear; return 0; } static int32_t endat_get_step(struct endat_priv *priv) { int32_t cmd; struct cmd_supplement cmd_supplement; uint32_t word; int32_t ch = priv->channel; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /* select memory area encoder manufacturer page 0 */ cmd = 2, cmd_supplement.address = MRS_CODE_PARAM_ENCODER_MANUFACTURER_PAGE1; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 12); /* send parameter for word4 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_4; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 2); word = (pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & (( 1 << ENDAT_NUM_BITS_PARAMETER) - 1); /* send parameter for word5 */ cmd = 4, cmd_supplement.address = APP_ENDAT_WORD_5; if(endat_command_process(priv, cmd, &cmd_supplement) < 0) { return -EINVAL; } /* delay copied from fw */ ClockP_usleep(1000 * 2); word |= ((pruss_xchg->ch[ch].pos_word0 >> (ENDAT_NUM_BITS_POSITION_CRC)) & ((1 << ENDAT_NUM_BITS_PARAMETER) - 1)) << 16; return word; } int32_t endat_get_encoder_info(struct endat_priv *priv) { int32_t ret; priv->pos_res = endat_get_pos_res(priv); if(priv->pos_res < 0) { return priv->pos_res; } priv->multi_turn_res = endat_get_multi_turn_res(priv); if(priv->multi_turn_res < 0) { return priv->multi_turn_res; } else if(!priv->multi_turn_res) { priv->single_turn_res = priv->pos_res; } else { priv->multi_turn_res = log2(priv->multi_turn_res); priv->single_turn_res = priv->pos_res - priv->multi_turn_res; } priv->step = endat_get_step(priv); if(priv->step < 0) { return priv->step; } /*calaculate rx frame size for all three channels and store in different variables*/ if(!priv->load_share) { priv->pos_rx_bits_21_RTUPRU = priv->pos_res + ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1; priv->pos_rx_bits_22_RTUPRU = priv->pos_rx_bits_21_RTUPRU + ENDAT_NUM_BITS_F2; } else if(priv->channel==0) /*ch0*/ { priv->pos_rx_bits_21_RTUPRU = priv->pos_res + ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1; priv->pos_rx_bits_22_RTUPRU = priv->pos_rx_bits_21_RTUPRU + ENDAT_NUM_BITS_F2; } else if(priv->channel==1) /*ch1*/ { priv->pos_rx_bits_21_PRU = priv->pos_res + ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1; priv->pos_rx_bits_22_PRU = priv->pos_rx_bits_21_PRU + ENDAT_NUM_BITS_F2;} else { priv->pos_rx_bits_21_TXPRU = priv->pos_res + ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1; priv->pos_rx_bits_22_TXPRU = priv->pos_rx_bits_21_TXPRU + ENDAT_NUM_BITS_F2; } /*ch2*/ ret = endat_get_id(priv); if(ret) { return ret; } ret = endat_get_sn(priv); if(ret) { return ret; } ret = endat_get_type(priv); if(ret) { return ret; } ret = endat_get_command_set(priv); if(ret) { return ret; } return 0; } uint32_t endat_get_prop_delay(struct endat_priv *priv) { return priv->pruss_xchg->ch[priv->channel].prop_delay; } void endat_addinfo_track(struct endat_priv *priv, int32_t cmd, struct cmd_supplement *cmd_supplement) { int32_t c7_c4, c3_c0; /* reset stops additional info's */ if(cmd == 5) { priv->flags.info1 = FALSE, priv->flags.info2 = FALSE; } if(cmd != 9) { return; } c7_c4 = (cmd_supplement->address & ENDAT_MRS_MASK_SELECT_ADDITIONAL_INFO) >> ENDAT_MRS_SHIFT_C7_C4; c3_c0 = cmd_supplement->address & ENDAT_MRS_MASK_STOP_ADDITIONAL_INFO; if(c7_c4 == ENDAT_MRS_VAL_C7_C4_SELECT_ADDITIONAL_INFO1) { if(c3_c0 == ENDAT_MRS_VAL_STOP_ADDITIONAL_INFO) { priv->flags.info1 = FALSE; } else { priv->flags.info1 = TRUE; } } c7_c4 = (cmd_supplement->address & ENDAT_MRS_MASK_SELECT_ADDITIONAL_INFO) >> ENDAT_MRS_SHIFT_C7_C4; c3_c0 = cmd_supplement->address & ENDAT_MRS_MASK_STOP_ADDITIONAL_INFO; if(c7_c4 == ENDAT_MRS_VAL_C7_C4_SELECT_ADDITIONAL_INFO2) { if(c3_c0 == ENDAT_MRS_VAL_STOP_ADDITIONAL_INFO) { priv->flags.info2 = FALSE; } else { priv->flags.info2 = TRUE; } } } static void endat_config_global_rx_arm_cnt(struct endat_priv *priv, uint16_t val) { void *pruss_cfg = priv->pruss_cfg; if(priv->pruicss_slicex) { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH0CFG1REGISTER + 2, val); HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH1CFG1REGISTER + 2, val); HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH2CFG1REGISTER + 2, val); } else { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH0CFG1REGISTER + 2, val); HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH1CFG1REGISTER + 2, val); HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH2CFG1REGISTER + 2, val); } } void endat_config_rx_arm_cnt(struct endat_priv *priv, uint16_t val) { void *pruss_cfg = priv->pruss_cfg; int32_t ch = priv->channel; if(priv->pruicss_slicex) { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH0CFG1REGISTER + ch * 8 + 2, val); } else { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH0CFG1REGISTER + ch * 8 + 2, val); } } void endat_config_wire_delay(struct endat_priv *priv, uint16_t val) { void *pruss_cfg = priv->pruss_cfg; int32_t ch = priv->channel; uint16_t regval; if(priv->pruicss_slicex) { regval = HW_RD_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH0CFG0REGISTER + ch * 8); } else { regval = HW_RD_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH0CFG0REGISTER + ch * 8); } /* clear wire delay bits, keep other bits as is */ regval &= 0xF800; /* restrict wire delay to wire delay bits only */ val &= 0x7FF; regval |= val; if(priv->pruicss_slicex) { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH0CFG0REGISTER + ch * 8, regval); } else { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH0CFG0REGISTER + ch * 8, regval); } } void endat_config_clock(struct endat_priv *priv, struct endat_clk_cfg *clk_cfg) { void *pruss_cfg = priv->pruss_cfg; /* Set PRU1_ED_RX_SB_POL polarity bit, required for ICSSG (don't care for ICSSM) */ if(priv->pruicss_slicex) { HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1RXCFGREGISTER, clk_cfg->rx_div << 16 | 0x8 | clk_cfg->rx_div_attr); HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER + 2, clk_cfg->tx_div); } else { HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0RXCFGREGISTER, clk_cfg->rx_div << 16 | 0x8 | clk_cfg->rx_div_attr); HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER + 2, clk_cfg->tx_div); } } void endat_config_tst_delay(struct endat_priv *priv, uint16_t delay) { void *pruss_cfg = priv->pruss_cfg; int32_t ch = priv->channel; if(priv->pruicss_slicex==1) { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH0CFG1REGISTER + ch * 8, delay); } else { HW_WR_REG16((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH0CFG1REGISTER + ch * 8, delay); } } void endat_config_rx_clock_disable(struct endat_priv *priv, uint16_t val) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; int32_t ch = priv->channel; pruss_xchg->ch[ch].rx_clk_less = val; } static void endat_set_continuous_mode(struct endat_priv *priv) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; if(priv->load_share) { pruss_xchg->config[0].trigger |= pruss_xchg->config[0].channel==1?(0x1 << 7 | 0x1):0; pruss_xchg->config[1].trigger |= pruss_xchg->config[1].channel==2?(0x1 << 7 | 0x1):0; pruss_xchg->config[2].trigger |= pruss_xchg->config[2].channel==4?(0x1 << 7 | 0x1):0; } else { pruss_xchg->config[0].trigger |= (0x1 << 7 | 0x1); } } static void endat_clear_continuous_mode(struct endat_priv *priv) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; if(priv->load_share) { pruss_xchg->config[0].trigger &= ~(0x1 << 7); pruss_xchg->config[1].trigger &= ~(0x1 << 7); pruss_xchg->config[2].trigger &= ~(0x1 << 7); } else { pruss_xchg->config[0].trigger &= ~(0x1 << 7); } } int32_t endat_start_continuous_mode(struct endat_priv *priv) { int32_t cmd; cmd = endat_command_build(priv, 1, NULL); if(cmd < 0) { return cmd; } endat_set_continuous_mode(priv); return cmd; } void endat_stop_continuous_mode(struct endat_priv *priv) { endat_clear_continuous_mode(priv); endat_command_wait(priv); } void endat_config_host_trigger(struct endat_priv *priv) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /*for loadshare mode trigger set based on connected channels*/ if(priv->load_share) { pruss_xchg->config[0].opmode=(pruss_xchg->config[0].channel&(1<<0))?0x1:0; pruss_xchg->config[1].opmode=(pruss_xchg->config[1].channel&(1<<1))?0x1:0; pruss_xchg->config[2].opmode=(pruss_xchg->config[2].channel&(1<<2))?0x1:0; } else { pruss_xchg->config[0].opmode = 0x1; } } void endat_config_periodic_trigger(struct endat_priv *priv) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; /*for loadshare mode trigger set based on connected channels*/ if(priv->load_share) { pruss_xchg->config[0].opmode=(pruss_xchg->config[0].channel&(1<<0))?0x0:pruss_xchg->config[0].opmode; pruss_xchg->config[1].opmode=(pruss_xchg->config[1].channel&(1<<1))?0x0:pruss_xchg->config[0].opmode; pruss_xchg->config[2].opmode=(pruss_xchg->config[2].channel&(1<<2))?0x0:pruss_xchg->config[0].opmode; } else { pruss_xchg->config[0].opmode = 0; } } void endat_config_channel(struct endat_priv *priv, int32_t ch) { struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; pruss_xchg->config[0].channel = 1 << ch; priv->channel = ch; } void endat_config_multi_channel_mask(struct endat_priv *priv, uint8_t mask, uint8_t loadshare) { priv->load_share = loadshare; if(loadshare) { priv->pruss_xchg->config[0].channel = mask&(1<<0); priv->pruss_xchg->config[1].channel = mask&(1<<1); priv->pruss_xchg->config[2].channel = mask&(1<<2); endat_config_primary_core_mask(priv, mask);/*select primary core for global configuration*/ endat_config_syn_bits(priv, mask); /* configure syn bits for synchronization before any global config*/ endat_enable_load_share_mode(priv); /*ENABLE SHARE MODE*/ } else { priv->pruss_xchg->config[0].channel = mask; } } void endat_config_syn_bits(struct endat_priv *priv, uint8_t mask) { priv->pruss_xchg->endat_ch0_syn_bit=mask&(1<<0)?0x1:0; priv->pruss_xchg->endat_ch1_syn_bit=mask&(1<<1)?0x2:0; priv->pruss_xchg->endat_ch2_syn_bit=mask&(1<<2)?0x4:0; } void endat_enable_load_share_mode(struct endat_priv *priv) { void *pruss_cfg = priv->pruss_cfg; //HW_WR_REG32(0x30026104) |= 0x0800; uint32_t rgval; if(priv->pruicss_slicex) { rgval = HW_RD_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER); rgval |= CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ENDAT_SHARE_EN_MASK; HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER, rgval); } else { rgval = HW_RD_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER); rgval |= CSL_ICSSCFG_EDPRU0TXCFGREGISTER_PRU0_ENDAT_SHARE_EN_MASK; HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER, rgval); } } void endat_config_primary_core_mask(struct endat_priv *priv, uint8_t mask) { switch (mask) { case 1: /*only channel0 connected*/ priv->pruss_xchg->endat_primary_core_mask=0x1; break; case 2: /*channel1 connected*/ priv->pruss_xchg->endat_primary_core_mask=0x2; break; case 3: /*channel0 and channel1 connected*/ priv->pruss_xchg->endat_primary_core_mask=0x1; break; case 4: /*channel2 connected*/ priv->pruss_xchg->endat_primary_core_mask=0x4; break; case 5: /*channel0 and channel2 connnected*/ priv->pruss_xchg->endat_primary_core_mask=0x4; break; case 6: /*channel1 and channel2 connected*/ priv->pruss_xchg->endat_primary_core_mask=0X4; break; case 7: /*all three channel connected*/ priv->pruss_xchg->endat_primary_core_mask=0x4; break; } } uint8_t endat_multi_channel_detected(struct endat_priv *priv) { if(priv->load_share) return (priv->pruss_xchg->config[0].channel|priv->pruss_xchg->config[1].channel|priv->pruss_xchg->config[2].channel); else return priv->pruss_xchg->config[0].channel; } void endat_multi_channel_set_cur(struct endat_priv *priv, int32_t ch) { priv->channel = ch; if(priv->load_share) { if(priv->channel == 0) { priv->pos_res = priv->pos_rx_bits_21_RTUPRU - (ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1); } else if(priv->channel == 1) { priv->pos_res = priv->pos_rx_bits_21_PRU - (ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1); } else { priv->pos_res = priv->pos_rx_bits_21_TXPRU - (ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1); } } else { priv->pos_res = priv->pos_rx_bits_21_RTUPRU - (ENDAT_NUM_BITS_POSITION_CRC + ENDAT_NUM_BITS_F1); } } int32_t endat_wait_initialization(struct endat_priv *priv, uint32_t timeout, uint8_t mask) { int32_t i; struct endat_pruss_xchg *pruss_xchg = priv->pruss_xchg; for(i = 0; i < timeout; i++) { if(priv->load_share) /* for loadshare mode*/ { switch (mask) { case 1: /*channel 0 connected*/ if((pruss_xchg->config[0].status & 1)) return 0; break; case 2: /*channel 1 connected*/ if((pruss_xchg->config[1].status & 1)) return 0; break; case 3: /*channel 0 and 1 connected*/ if((pruss_xchg->config[0].status & 1)&&(pruss_xchg->config[1].status & 1)) return 0; break; case 4: /*channel 2 connected*/ if((pruss_xchg->config[2].status & 1)) return 0; break; case 5: /*channel 0 and 2 connnected*/ if((pruss_xchg->config[0].status & 1)&&(pruss_xchg->config[2].status & 1)) return 0; break; case 6: /*channel 1 and 2 connected*/ if((pruss_xchg->config[1].status & 1)&&(pruss_xchg->config[2].status & 1)) return 0; break; case 7: /*all three channel connected*/ if((pruss_xchg->config[0].status & 1)&&(pruss_xchg->config[1].status & 1)&&( pruss_xchg->config[2].status & 1)) return 0; break; } ClockP_usleep(1000 * 1); } else if(pruss_xchg->config[0].status & 1) { break; } else { ClockP_usleep(1000 * 1); } } if(i == timeout) { return -1; } return 0; } static inline void endat_config_clr_cfg0(struct endat_priv *priv) { void *pruss_cfg = priv->pruss_cfg; if(priv->pruicss_slicex) { HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH0CFG0REGISTER, 0); HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH1CFG0REGISTER, 0); HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU1CH2CFG0REGISTER, 0); } else { HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH0CFG0REGISTER, 0); HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH1CFG0REGISTER, 0); HW_WR_REG32((uint8_t *)pruss_cfg + CSL_ICSSCFG_EDPRU0CH2CFG0REGISTER, 0); } } static inline void endat_config_endat_mode(struct endat_priv *priv) { void *pruss_cfg = priv->pruss_cfg; if(priv->pruicss_slicex) { HW_WR_REG8((uint8_t *)pruss_cfg + CSL_ICSSCFG_GPCFG1 + 3, 4); } else { HW_WR_REG8((uint8_t *)pruss_cfg + CSL_ICSSCFG_GPCFG0 + 3, 4); } } static void endat_hw_init(struct endat_priv *priv) { struct endat_clk_cfg clk_cfg; /* set initial clock to 200KHz */ /* 192MHz / 200KHz - 1 */ clk_cfg.tx_div = 959; /* 192MHz / 200KHz / 8 - 1 */ clk_cfg.rx_div = 119; /* 2T */ clk_cfg.rx_en_cnt = 10000; /* sample size 8 */ clk_cfg.rx_div_attr = 7; endat_config_endat_mode(priv); endat_config_clock(priv, &clk_cfg); endat_config_global_rx_arm_cnt(priv, clk_cfg.rx_en_cnt); endat_config_clr_cfg0(priv); } struct endat_priv *endat_init(struct endat_pruss_xchg *pruss_xchg, void *pruss_cfg, void* pruss_iep, int32_t slice) { endat_priv.pruss_xchg = pruss_xchg; endat_priv.pruss_cfg = pruss_cfg; endat_priv.pruicss_slicex = slice; endat_priv.pruss_iep = pruss_iep; endat_hw_init(&endat_priv); return &endat_priv; } uint32_t endat_get_recovery_time(struct endat_priv *priv) { if(priv->channel == 0) { return priv->pruss_xchg->endat_ch0_rt; } else if (priv->channel == 1) { return priv->pruss_xchg->endat_ch1_rt; } else { return priv->pruss_xchg->endat_ch2_rt; } }