diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 9b37b0fb756..0cc1135d914 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -46,7 +46,7 @@ #define GPIO_IRQ_PIN CONFIG_BT_SPI_IRQ_PIN #define GPIO_RESET_PIN CONFIG_BT_SPI_RESET_PIN #if defined(CONFIG_BT_SPI_BLUENRG) -#define GPIO_CS_PIN CONFIG_BT_SPI_CHIP_SELECT_PIN +#define GPIO_CS_PIN CONFIG_BT_SPI_CHIP_SELECT_PIN #endif /* CONFIG_BT_SPI_BLUENRG */ /* Max SPI buffer length for transceive operations. @@ -61,9 +61,6 @@ static u8_t rxmsg[SPI_MAX_MSG_LEN]; static u8_t txmsg[SPI_MAX_MSG_LEN]; -#if defined(CONFIG_BT_SPI_BLUENRG) -static struct device *cs_dev; -#endif /* CONFIG_BT_SPI_BLUENRG */ static struct device *irq_dev; static struct device *rst_dev; @@ -100,32 +97,12 @@ static inline void spi_dump_message(const u8_t *pre, u8_t *buf, u8_t size) {} #endif -/* - * SPI driver shim. - * - * This can be removed and this driver further improved when the - * legacy SPI API is gone. (For example, the chip select handling done - * under CONFIG_BT_SPI_BLUENRG could be done with a struct - * spi_cs_control instead). - */ -static struct device *spi_dev; -#if defined(CONFIG_SPI_LEGACY_API) -static struct spi_config spi_conf = { - .config = SPI_WORD(8), - .max_sys_freq = CONFIG_BT_SPI_MAX_CLK_FREQ, -}; +#if defined(CONFIG_BT_SPI_BLUENRG) +static struct device *cs_dev; +#endif /* CONFIG_BT_SPI_BLUENRG */ -static inline int bt_spi_dev_configure(void) -{ - return spi_configure(spi_dev, &spi_conf); -} +static struct device *spi_dev; -static inline int bt_spi_transceive(const void *tx, u32_t tx_len, - void *rx, u32_t rx_len) -{ - return spi_transceive(spi_dev, tx, tx_len, rx, rx_len); -} -#else /* !defined(CONFIG_SPI_LEGACY_API) */ static struct spi_config spi_conf = { .frequency = CONFIG_BT_SPI_MAX_CLK_FREQ, .operation = (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | @@ -144,11 +121,6 @@ static const struct spi_buf_set spi_rx = { .count = 1 }; -static inline int bt_spi_dev_configure(void) -{ - return 0; -} - static inline int bt_spi_transceive(void *tx, u32_t tx_len, void *rx, u32_t rx_len) { @@ -158,7 +130,6 @@ static inline int bt_spi_transceive(void *tx, u32_t tx_len, spi_rx_buf.len = (size_t)rx_len; return spi_transceive(spi_dev, &spi_conf, &spi_tx, &spi_rx); } -#endif /* CONFIG_SPI_LEGACY_API */ static inline u16_t bt_spi_get_cmd(u8_t *txmsg) { @@ -171,8 +142,10 @@ static inline u16_t bt_spi_get_evt(u8_t *rxmsg) } static void bt_spi_isr(struct device *unused1, struct gpio_callback *unused2, - unsigned int unused3) + unsigned int unused3) { + BT_DBG(""); + k_sem_give(&sem_request); } @@ -186,13 +159,55 @@ static void bt_spi_handle_vendor_evt(u8_t *rxmsg) } } +#if defined(CONFIG_BT_SPI_BLUENRG) +/* BlueNRG has a particuliar way to wake up from sleep and be ready. + * All is done through its CS line: + * If it is in sleep mode, the first transaction will not return ready + * status. At this point, it's necessary to release the CS and retry + * within 2ms the same transaction. And again when it's required to + * know the amount of byte to read. + * (See section 5.2 of BlueNRG-MS datasheet) + */ +static int bt_spi_configure_cs(void) +{ + cs_dev = device_get_binding(CONFIG_BT_SPI_CHIP_SELECT_DEV_NAME); + if (!cs_dev) { + BT_ERR("Failed to initialize GPIO driver: %s", + CONFIG_BT_SPI_CHIP_SELECT_DEV_NAME); + return -EIO; + } + + gpio_pin_configure(cs_dev, GPIO_CS_PIN, + GPIO_DIR_OUT | GPIO_PUD_PULL_UP); + gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); + + return 0; +} + +static void bt_spi_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) +{ + gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); +} +#else +#define bt_spi_configure_cs(...) 0 +#define bt_spi_kick_cs(...) +#define bt_spi_release_cs(...) +#endif + static void bt_spi_rx_thread(void) { struct net_buf *buf; u8_t header_master[5] = { SPI_READ, 0x00, 0x00, 0x00, 0x00 }; u8_t header_slave[5]; struct bt_hci_acl_hdr acl_hdr; - u8_t size; + u8_t size = 0; + int ret; memset(&txmsg, 0xFF, SPI_MAX_MSG_LEN); @@ -202,26 +217,33 @@ static void bt_spi_rx_thread(void) gpio_pin_disable_callback(irq_dev, GPIO_IRQ_PIN); k_sem_take(&sem_busy, K_FOREVER); - do { -#if defined(CONFIG_BT_SPI_BLUENRG) - gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); - gpio_pin_write(cs_dev, GPIO_CS_PIN, 0); -#endif /* CONFIG_BT_SPI_BLUENRG */ - bt_spi_transceive(header_master, 5, header_slave, 5); - } while (header_slave[STATUS_HEADER_TOREAD] == 0 || - header_slave[STATUS_HEADER_TOREAD] == 0xFF); + BT_DBG(""); - size = header_slave[STATUS_HEADER_TOREAD]; do { - bt_spi_transceive(&txmsg, size, &rxmsg, size); - } while (rxmsg[0] == 0); + 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]; + + do { + ret = bt_spi_transceive(&txmsg, size, + &rxmsg, size); + } while (rxmsg[0] == 0 && ret == 0); + } + + bt_spi_release_cs(); gpio_pin_enable_callback(irq_dev, GPIO_IRQ_PIN); -#if defined(CONFIG_BT_SPI_BLUENRG) - gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); -#endif /* CONFIG_BT_SPI_BLUENRG */ k_sem_give(&sem_busy); + if (ret) { + BT_ERR("Error %d", ret); + continue; + } + spi_dump_message("RX:ed", rxmsg, size); switch (rxmsg[PACKET_TYPE]) { @@ -268,6 +290,9 @@ static int bt_spi_send(struct net_buf *buf) { u8_t header[5] = { SPI_WRITE, 0x00, 0x00, 0x00, 0x00 }; u32_t pending; + int ret; + + BT_DBG(""); /* Buffer needs an additional byte for type */ if (buf->len >= SPI_MAX_MSG_LEN) { @@ -301,31 +326,35 @@ static int bt_spi_send(struct net_buf *buf) /* Poll sanity values until device has woken-up */ do { -#if defined(CONFIG_BT_SPI_BLUENRG) - gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); - gpio_pin_write(cs_dev, GPIO_CS_PIN, 0); -#endif /* CONFIG_BT_SPI_BLUENRG */ - bt_spi_transceive(header, 5, rxmsg, 5); + bt_spi_kick_cs(); + ret = bt_spi_transceive(header, 5, rxmsg, 5); /* * RX Header (rxmsg) must contain a sanity check Byte and size * information. If it does not contain BOTH then it is * sleeping or still in the initialisation stage (waking-up). */ - } while (rxmsg[STATUS_HEADER_READY] != READY_NOW || - (rxmsg[1] | rxmsg[2] | rxmsg[3] | rxmsg[4]) == 0); + } while ((rxmsg[STATUS_HEADER_READY] != READY_NOW || + (rxmsg[1] | rxmsg[2] | rxmsg[3] | rxmsg[4]) == 0) && !ret); - /* Transmit the message */ - do { - bt_spi_transceive(buf->data, buf->len, rxmsg, buf->len); - } while (rxmsg[0] == 0); -#if defined(CONFIG_BT_SPI_BLUENRG) - /* Deselect chip */ - gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); -#endif /* CONFIG_BT_SPI_BLUENRG */ k_sem_give(&sem_busy); + if (!ret) { + /* Transmit the message */ + do { + ret = bt_spi_transceive(buf->data, buf->len, + rxmsg, buf->len); + } while (rxmsg[0] == 0 && !ret); + } + + bt_spi_release_cs(); + + if (ret) { + BT_ERR("Error %d", ret); + goto out; + } + spi_dump_message("TX:ed", buf->data, buf->len); #if defined(CONFIG_BT_SPI_BLUENRG) @@ -340,10 +369,10 @@ static int bt_spi_send(struct net_buf *buf) k_sem_take(&sem_initialised, K_FOREVER); } #endif /* CONFIG_BT_SPI_BLUENRG */ - +out: net_buf_unref(buf); - return 0; + return ret; } static int bt_spi_open(void) @@ -353,15 +382,6 @@ static int bt_spi_open(void) GPIO_DIR_OUT | GPIO_PUD_PULL_UP); gpio_pin_write(rst_dev, GPIO_RESET_PIN, 0); - bt_spi_dev_configure(); - -#if defined(CONFIG_BT_SPI_BLUENRG) - /* Configure the CS (Chip Select) pin */ - gpio_pin_configure(cs_dev, GPIO_CS_PIN, - GPIO_DIR_OUT | GPIO_PUD_PULL_UP); - gpio_pin_write(cs_dev, GPIO_CS_PIN, 1); -#endif /* CONFIG_BT_SPI_BLUENRG */ - /* Configure IRQ pin and the IRQ call-back/handler */ gpio_pin_configure(irq_dev, GPIO_IRQ_PIN, GPIO_DIR_IN | GPIO_INT | @@ -411,14 +431,9 @@ static int _bt_spi_init(struct device *unused) return -EIO; } -#if defined(CONFIG_BT_SPI_BLUENRG) - cs_dev = device_get_binding(CONFIG_BT_SPI_CHIP_SELECT_DEV_NAME); - if (!cs_dev) { - BT_ERR("Failed to initialize GPIO driver: %s", - CONFIG_BT_SPI_CHIP_SELECT_DEV_NAME); + if (bt_spi_configure_cs()) { return -EIO; } -#endif /* CONFIG_BT_SPI_BLUENRG */ irq_dev = device_get_binding(CONFIG_BT_SPI_IRQ_DEV_NAME); if (!irq_dev) { @@ -436,6 +451,9 @@ static int _bt_spi_init(struct device *unused) bt_hci_driver_register(&drv); + + BT_DBG("BT SPI initialized"); + return 0; }