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:
parent
0ba41f5b46
commit
7b02e6dc55
1 changed files with 110 additions and 66 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue