in regmap/regmap-spi-avmm.c [365:500]
static int br_do_rx_and_pkt_phy_parse(struct spi_avmm_bridge *br)
{
bool eop_found = false, channel_found = false, esc_found = false;
bool valid_word = false, last_try = false;
struct device *dev = &br->spi->dev;
char *pb, *tb_limit, *tb = NULL;
unsigned long poll_timeout;
int ret, i;
tb_limit = br->trans_buf + ARRAY_SIZE(br->trans_buf);
pb = br->phy_buf;
poll_timeout = jiffies + SPI_AVMM_XFER_TIMEOUT;
while (tb < tb_limit) {
ret = spi_read(br->spi, pb, br->word_len);
if (ret)
return ret;
/* reorder the word back */
if (br->swap_words)
br->swap_words(pb, br->word_len);
valid_word = false;
for (i = 0; i < br->word_len; i++) {
/* drop everything before first SOP */
if (!tb && pb[i] != PKT_SOP)
continue;
/* drop PHY_IDLE */
if (pb[i] == PHY_IDLE)
continue;
valid_word = true;
/*
* We don't support multiple channels, so error out if
* a non-zero channel number is found.
*/
if (channel_found) {
if (pb[i] != 0) {
dev_err(dev, "%s channel num != 0\n",
__func__);
return -EFAULT;
}
channel_found = false;
continue;
}
switch (pb[i]) {
case PKT_SOP:
/*
* reset the parsing if a second SOP appears.
*/
tb = br->trans_buf;
eop_found = false;
channel_found = false;
esc_found = false;
break;
case PKT_EOP:
/*
* No special char is expected after ESC char.
* No special char (except ESC & PHY_IDLE) is
* expected after EOP char.
*
* The special chars are all dropped.
*/
if (esc_found || eop_found)
return -EFAULT;
eop_found = true;
break;
case PKT_CHANNEL:
if (esc_found || eop_found)
return -EFAULT;
channel_found = true;
break;
case PKT_ESC:
case PHY_ESC:
if (esc_found)
return -EFAULT;
esc_found = true;
break;
default:
/* Record the normal byte in trans_buf. */
if (esc_found) {
*tb++ = pb[i] ^ 0x20;
esc_found = false;
} else {
*tb++ = pb[i];
}
/*
* We get the last normal byte after EOP, it is
* time we finish. Normally the function should
* return here.
*/
if (eop_found) {
br->trans_len = tb - br->trans_buf;
return 0;
}
}
}
if (valid_word) {
/* update poll timeout when we get valid word */
poll_timeout = jiffies + SPI_AVMM_XFER_TIMEOUT;
last_try = false;
} else {
/*
* We timeout when rx keeps invalid for some time. But
* it is possible we are scheduled out for long time
* after a spi_read. So when we are scheduled in, a SW
* timeout happens. But actually HW may have worked fine and
* has been ready long time ago. So we need to do an extra
* read, if we get a valid word then we could continue rx,
* otherwise real a HW issue happens.
*/
if (last_try)
return -ETIMEDOUT;
if (time_after(jiffies, poll_timeout))
last_try = true;
}
}
/*
* We have used out all transfer layer buffer but cannot find the end
* of the byte stream.
*/
dev_err(dev, "%s transfer buffer is full but rx doesn't end\n",
__func__);
return -EFAULT;
}