bt: hci driver over spi: BlueNRG-MS read until IRQ pin goes low

According to BlueNRG-MS ref manual, SPI master shoul read  from
controller as long as IRQ pin is high.
Introduce a new loop within spi_rx_thread to do so. Since
it is now possible to enter read loop with nothing to read, set
a max attempts limit to be sure to exit the loop.

Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
Signed-off-by: Christophe Priouzeau <christophe.priouzeau@st.com>
This commit is contained in:
Christophe Priouzeau 2018-06-26 13:30:26 +02:00 committed by Carles Cufí
commit 7b02e6dc55

View file

@ -99,6 +99,11 @@ void spi_dump_message(const u8_t *pre, u8_t *buf, u8_t size) {}
#if defined(CONFIG_BT_SPI_BLUENRG)
static struct device *cs_dev;
/* Define a limit when reading IRQ high */
/* It can be required to be increased for */
/* some particular cases. */
#define IRQ_HIGH_MAX_READ 3
static u8_t attempts;
#endif /* CONFIG_BT_SPI_BLUENRG */
static struct device *spi_dev;
@ -168,7 +173,7 @@ static void bt_spi_handle_vendor_evt(u8_t *rxmsg)
* know the amount of byte to read.
* (See section 5.2 of BlueNRG-MS datasheet)
*/
static int bt_spi_configure_cs(void)
static int configure_cs(void)
{
cs_dev = device_get_binding(CONFIG_BT_SPI_CHIP_SELECT_DEV_NAME);
if (!cs_dev) {
@ -184,20 +189,50 @@ static int bt_spi_configure_cs(void)
return 0;
}
static void bt_spi_kick_cs(void)
static void kick_cs(void)
{
gpio_pin_write(cs_dev, GPIO_CS_PIN, 1);
gpio_pin_write(cs_dev, GPIO_CS_PIN, 0);
}
static void bt_spi_release_cs(void)
static void release_cs(void)
{
gpio_pin_write(cs_dev, GPIO_CS_PIN, 1);
}
static bool irq_pin_high(void)
{
u32_t pin_state;
gpio_pin_read(irq_dev, GPIO_IRQ_PIN, &pin_state);
BT_DBG("IRQ Pin: %d", pin_state);
return pin_state;
}
static void init_irq_high_loop(void)
{
attempts = IRQ_HIGH_MAX_READ;
}
static bool exit_irq_high_loop(void)
{
/* Limit attempts on BlueNRG-MS as we might */
/* enter this loop with nothing to read */
attempts--;
return attempts;
}
#else
#define bt_spi_configure_cs(...) 0
#define bt_spi_kick_cs(...)
#define bt_spi_release_cs(...)
#define configure_cs(...) 0
#define kick_cs(...)
#define release_cs(...)
#define irq_pin_high(...) 0
#define init_irq_high_loop(...)
#define exit_irq_high_loop(...) 1
#endif
static void bt_spi_rx_thread(void)
@ -220,69 +255,75 @@ static void bt_spi_rx_thread(void)
BT_DBG("");
do {
bt_spi_kick_cs();
ret = bt_spi_transceive(header_master, 5,
header_slave, 5);
} while ((header_slave[STATUS_HEADER_TOREAD] == 0 ||
header_slave[STATUS_HEADER_TOREAD] == 0xFF) && !ret);
if (!ret) {
size = header_slave[STATUS_HEADER_TOREAD];
init_irq_high_loop();
do {
ret = bt_spi_transceive(&txmsg, size,
&rxmsg, size);
} while (rxmsg[0] == 0 && ret == 0);
}
kick_cs();
ret = bt_spi_transceive(header_master, 5,
header_slave, 5);
} while ((((header_slave[STATUS_HEADER_TOREAD] == 0 ||
header_slave[STATUS_HEADER_TOREAD] == 0xFF) &&
!ret)) && exit_irq_high_loop());
bt_spi_release_cs();
gpio_pin_enable_callback(irq_dev, GPIO_IRQ_PIN);
k_sem_give(&sem_busy);
if (!ret) {
size = header_slave[STATUS_HEADER_TOREAD];
if (ret) {
BT_ERR("Error %d", ret);
continue;
}
spi_dump_message("RX:ed", rxmsg, size);
switch (rxmsg[PACKET_TYPE]) {
case HCI_EVT:
switch (rxmsg[EVT_HEADER_EVENT]) {
case BT_HCI_EVT_VENDOR:
/* Vendor events are currently unsupported */
bt_spi_handle_vendor_evt(rxmsg);
continue;
case BT_HCI_EVT_CMD_COMPLETE:
case BT_HCI_EVT_CMD_STATUS:
buf = bt_buf_get_cmd_complete(K_FOREVER);
break;
default:
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
break;
do {
ret = bt_spi_transceive(&txmsg, size,
&rxmsg, size);
} while (rxmsg[0] == 0 && ret == 0);
}
net_buf_add_mem(buf, &rxmsg[1],
rxmsg[EVT_HEADER_SIZE] + 2);
break;
case HCI_ACL:
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
memcpy(&acl_hdr, &rxmsg[1], sizeof(acl_hdr));
net_buf_add_mem(buf, &acl_hdr, sizeof(acl_hdr));
net_buf_add_mem(buf, &rxmsg[5],
sys_le16_to_cpu(acl_hdr.len));
break;
default:
BT_ERR("Unknown BT buf type %d", rxmsg[0]);
continue;
}
release_cs();
gpio_pin_enable_callback(irq_dev, GPIO_IRQ_PIN);
k_sem_give(&sem_busy);
if (rxmsg[PACKET_TYPE] == HCI_EVT &&
bt_hci_evt_is_prio(rxmsg[EVT_HEADER_EVENT])) {
bt_recv_prio(buf);
} else {
bt_recv(buf);
}
if (ret) {
BT_ERR("Error %d", ret);
continue;
}
spi_dump_message("RX:ed", rxmsg, size);
switch (rxmsg[PACKET_TYPE]) {
case HCI_EVT:
switch (rxmsg[EVT_HEADER_EVENT]) {
case BT_HCI_EVT_VENDOR:
/* Vendor events are currently unsupported */
bt_spi_handle_vendor_evt(rxmsg);
continue;
case BT_HCI_EVT_CMD_COMPLETE:
case BT_HCI_EVT_CMD_STATUS:
buf = bt_buf_get_cmd_complete(K_FOREVER);
break;
default:
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
break;
}
net_buf_add_mem(buf, &rxmsg[1],
rxmsg[EVT_HEADER_SIZE] + 2);
break;
case HCI_ACL:
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
memcpy(&acl_hdr, &rxmsg[1], sizeof(acl_hdr));
net_buf_add_mem(buf, &acl_hdr, sizeof(acl_hdr));
net_buf_add_mem(buf, &rxmsg[5],
sys_le16_to_cpu(acl_hdr.len));
break;
default:
BT_ERR("Unknown BT buf type %d", rxmsg[0]);
continue;
}
if (rxmsg[PACKET_TYPE] == HCI_EVT &&
bt_hci_evt_is_prio(rxmsg[EVT_HEADER_EVENT])) {
bt_recv_prio(buf);
} else {
bt_recv(buf);
}
/* On BlueNRG-MS, host is expected to read */
/* as long as IRQ pin is high */
} while (irq_pin_high());
}
}
@ -326,7 +367,7 @@ static int bt_spi_send(struct net_buf *buf)
/* Poll sanity values until device has woken-up */
do {
bt_spi_kick_cs();
kick_cs();
ret = bt_spi_transceive(header, 5, rxmsg, 5);
/*
@ -348,7 +389,7 @@ static int bt_spi_send(struct net_buf *buf)
} while (rxmsg[0] == 0 && !ret);
}
bt_spi_release_cs();
release_cs();
if (ret) {
BT_ERR("Error %d", ret);
@ -384,6 +425,9 @@ static int bt_spi_open(void)
/* Configure IRQ pin and the IRQ call-back/handler */
gpio_pin_configure(irq_dev, GPIO_IRQ_PIN,
#if defined(CONFIG_BT_SPI_BLUENRG)
GPIO_PUD_PULL_DOWN |
#endif
GPIO_DIR_IN | GPIO_INT |
GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH);
@ -431,7 +475,7 @@ static int _bt_spi_init(struct device *unused)
return -EIO;
}
if (bt_spi_configure_cs()) {
if (configure_cs()) {
return -EIO;
}