diff --git a/arch/arm/src/tiva/Kconfig b/arch/arm/src/tiva/Kconfig index 1da4d326896..b6f8efc3e0b 100644 --- a/arch/arm/src/tiva/Kconfig +++ b/arch/arm/src/tiva/Kconfig @@ -416,7 +416,7 @@ config TIVA_TIMER bool default n -# Periperhal Selections +# Peripheral Selections config TIVA_ADC0 bool "ADC0" @@ -487,53 +487,387 @@ config TIVA_I2C9 depends on TIVA_HAVE_I2C9 select TIVA_I2C -config TIVA_UART0 - bool "UART0" +config TIVA_HCIUART + bool default n + +choice + prompt "UART0 Driver Configuration" + default TIVA_UART0_NONE + +config TIVA_UART0_NONE + bool "Not selected" + +config TIVA_UART0 + bool "Standard serial driver" select UART0_SERIALDRIVER +config TIVA_UART0_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART0 Driver Configuration + +if TIVA_UART0_HCIUART +config TIVA_HCIUART0_RXBUFSIZE + int "HCI UART0 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART0_TXBUFSIZE + int "HCI UART0 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART0_BAUD + int "HCI UART0 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART0_HCIUART + +choice + prompt "UART1 Driver Configuration" + default TIVA_UART1_NONE + +config TIVA_UART1_NONE + bool "Not selected" + config TIVA_UART1 - bool "UART1" - default n - depends on TIVA_HAVE_UART1 + bool "Standard serial driver" select UART1_SERIALDRIVER +config TIVA_UART1_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART1 Driver Configuration + +if TIVA_UART1_HCIUART +config TIVA_HCIUART1_RXBUFSIZE + int "HCI UART1 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART1_TXBUFSIZE + int "HCI UART1 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART1_BAUD + int "HCI UART1 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART1_HCIUART + +choice + prompt "UART2 Driver Configuration" + default TIVA_UART2_NONE + +config TIVA_UART2_NONE + bool "Not selected" + config TIVA_UART2 - bool "UART2" - default n - depends on TIVA_HAVE_UART2 + bool "Standard serial driver" select UART2_SERIALDRIVER +config TIVA_UART2_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART2 Driver Configuration + +if TIVA_UART2_HCIUART +config TIVA_HCIUART2_RXBUFSIZE + int "HCI UART2 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART2_TXBUFSIZE + int "HCI UART2 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART2_BAUD + int "HCI UART2 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART2_HCIUART + +choice + prompt "UART3 Driver Configuration" + default TIVA_UART3_NONE + +config TIVA_UART3_NONE + bool "Not selected" + config TIVA_UART3 - bool "UART3" - default n - depends on TIVA_HAVE_UART3 + bool "Standard serial driver" select UART3_SERIALDRIVER +config TIVA_UART3_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART3 Driver Configuration + +if TIVA_UART3_HCIUART +config TIVA_HCIUART3_RXBUFSIZE + int "HCI UART3 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART3_TXBUFSIZE + int "HCI UART3 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART3_BAUD + int "HCI UART3 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART3_HCIUART + +choice + prompt "UART4 Driver Configuration" + default TIVA_UART4_NONE + +config TIVA_UART4_NONE + bool "Not selected" + config TIVA_UART4 - bool "UART4" - default n - depends on TIVA_HAVE_UART4 + bool "Standard serial driver" select UART4_SERIALDRIVER +config TIVA_UART4_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART4 Driver Configuration + +if TIVA_UART4_HCIUART +config TIVA_HCIUART4_RXBUFSIZE + int "HCI UART4 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART4_TXBUFSIZE + int "HCI UART4 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART4_BAUD + int "HCI UART4 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART4_HCIUART + +choice + prompt "UART5 Driver Configuration" + default TIVA_UART5_NONE + +config TIVA_UART5_NONE + bool "Not selected" + config TIVA_UART5 - bool "UART5" - default n - depends on TIVA_HAVE_UART5 + bool "Standard serial driver" select UART5_SERIALDRIVER +config TIVA_UART5_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART5 Driver Configuration + +if TIVA_UART5_HCIUART +config TIVA_HCIUART5_RXBUFSIZE + int "HCI UART5 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART5_TXBUFSIZE + int "HCI UART5 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART5_BAUD + int "HCI UART5 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART5_HCIUART + +choice + prompt "UART6 Driver Configuration" + default TIVA_UART6_NONE + +config TIVA_UART6_NONE + bool "Not selected" + config TIVA_UART6 - bool "UART6" - default n - depends on TIVA_HAVE_UART6 + bool "Standard serial driver" select UART6_SERIALDRIVER +config TIVA_UART6_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART6 Driver Configuration + +if TIVA_UART6_HCIUART +config TIVA_HCIUART6_RXBUFSIZE + int "HCI UART6 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART6_TXBUFSIZE + int "HCI UART6 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART6_BAUD + int "HCI UART6 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART6_HCIUART + +choice + prompt "UART7 Driver Configuration" + default TIVA_UART7_NONE + +config TIVA_UART7_NONE + bool "Not selected" + config TIVA_UART7 - bool "UART7" - default n - depends on TIVA_HAVE_UART7 + bool "Standard serial driver" select UART7_SERIALDRIVER +config TIVA_UART7_HCIUART + bool "Bluetooth HCI-UART" + select TIVA_HCIUART + depends on WIRELESS_BLUETOOTH + +endchoice # UART7 Driver Configuration + +if TIVA_UART7_HCIUART +config TIVA_HCIUART7_RXBUFSIZE + int "HCI UART7 Rx buffer size" + default 80 + ---help--- + Characters are buffered as they are received. This specifies + the size of the receive buffer. Ideally this should be at least + the size of the largest frame that can be received + +config TIVA_HCIUART7_TXBUFSIZE + int "HCI UART7 Transmit buffer size" + default 80 + ---help--- + Characters are buffered before being sent. This specifies + the size of the transmit buffer. Ideally this should be at least + the size of the largest frame that can be sent + +config TIVA_HCIUART7_BAUD + int "HCI UART7 initial BAUD rate" + default 115200 + ---help--- + The configured initial BAUD of the HCI UART used during bringup. + In most cases this initial rate can be increased by the upper half + HCI UART driver using vendor-specifi HCI UART commands. + +endif # TIVA_UART7_HCIUART + +menu "HCI UART Driver Configuration" + depends on TIVA_HCIUART + +config TIVA_HCIUART_SW_RXFLOW + bool "Use Software UART RTS flow control" + default n + ---help--- + Enable UART RTS flow control using Software. + +config TIVA_HCIUART_SW_TXFLOW + bool "Use Software UART CTS flow control" + default n + ---help--- + Enable UART CTS flow control using Software. + +endmenu # HCI UART Driver Configuration + config TIVA_SSI0 bool "SSI0" default n diff --git a/arch/arm/src/tiva/Make.defs b/arch/arm/src/tiva/Make.defs index b5980f423d1..60b18f54bdd 100644 --- a/arch/arm/src/tiva/Make.defs +++ b/arch/arm/src/tiva/Make.defs @@ -161,6 +161,10 @@ ifeq ($(CONFIG_TIVA_EEPROM),y) CHIP_CSRCS += tiva_eeprom.c endif +ifeq ($(CONFIG_TIVA_HCIUART),y) +CHIP_CSRCS += tiva_hciuart.c +endif + # Paths to source files VPATH += chip/common diff --git a/arch/arm/src/tiva/common/tiva_hciuart.c b/arch/arm/src/tiva/common/tiva_hciuart.c new file mode 100644 index 00000000000..c17acd2a99b --- /dev/null +++ b/arch/arm/src/tiva/common/tiva_hciuart.c @@ -0,0 +1,1874 @@ +/**************************************************************************** + * arch/arm/src/tiva/tiva_hciuart.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name NuttX 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 EXPRESS 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "up_arch.h" +#include "up_internal.h" + +#include "chip.h" +#include "tiva_hciuart.h" +#include "tiva_enablepwr.h" +#include "tiva_enableclks.h" +#include "tiva_periphrdy.h" +#include "tiva_gpio.h" +#include "hardware/tiva_pinmap.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* All interrupts */ + +#define HCIUART_ALLINTS (UART_IM_TXIM | UART_IM_RXIM | UART_IM_RTIM) +#define HCIUART_RXHANDLED (1 << 0) +#define HCIUART_TXHANDLED (1 << 1) + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_TIVA_PM_SERIAL_ACTIVITY) +# define CONFIG_TIVA_PM_SERIAL_ACTIVITY 10 +#endif + +#if defined(CONFIG_PM) +# define PM_IDLE_DOMAIN 0 /* Revisit */ +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure is the variable state of the HCI UART */ + +struct hciuart_state_s +{ + /* Registered Rx callback */ + + btuart_rxcallback_t callback; /* Rx callback function */ + void *arg; /* Rx callback argument */ + + /* Rx/Tx circular buffer management */ + + sem_t rxwait; /* Supports wait for more Rx data */ + sem_t txwait; /* Supports wait for space in Tx buffer */ + + uint32_t baud; /* Current BAUD selection */ + volatile uint16_t rxhead; /* Head and tail index of the Rx buffer */ + uint16_t rxtail; + uint16_t txhead; /* Head and tail index of the Tx buffer */ + volatile uint16_t txtail; + volatile bool rxwaiting; /* A thread is waiting for more Rx data */ + volatile bool txwaiting; /* A thread is waiting for space in the Tx buffer */ + uint32_t im; /* Saved IM value */ +}; + +/* This structure is the constant configuration of the HCI UART */ + +struct hciuart_config_s +{ + struct btuart_lowerhalf_s lower; /* Generic HCI-UART lower half */ + struct hciuart_state_s *state; /* Reference to variable state */ + uint8_t *rxbuffer; /* Rx buffer start */ + uint8_t *txbuffer; /* Tx buffer start */ + uint16_t rxbufsize; /* Size of the Rx buffer */ + uint16_t txbufsize; /* Size of the tx buffer */ + + uint8_t irq; /* IRQ associated with this UART */ + uint32_t baud; /* Configured baud */ + uint32_t id; /* UART identifier */ + uint32_t uartbase; /* Base address of UART registers */ + uint32_t tx_gpio; /* UART TX GPIO pin configuration */ + uint32_t rx_gpio; /* UART RX GPIO pin configuration */ + uint32_t cts_gpio; /* UART CTS GPIO pin configuration */ + uint32_t rts_gpio; /* UART RTS GPIO pin configuration */ + uint32_t shutd_gpio; /* */ + + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ + bool stopbits2; /* true: Configure 2 stop bits instead of 1 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t hciuart_getreg32(const struct hciuart_config_s *config, + unsigned int offset); +static inline void hciuart_putreg32(const struct hciuart_config_s *config, + unsigned int offset, uint32_t value); +static void hciuart_enableints(const struct hciuart_config_s *config, + uint32_t intset); +static void hciuart_disableints(const struct hciuart_config_s *config, + uint32_t intset); +static bool hciuart_isenabled(const struct hciuart_config_s *config, + uint32_t intset); +static inline bool hciuart_rxenabled(const struct hciuart_config_s *config); + +static uint16_t hciuart_rxinuse(const struct hciuart_config_s *config); +static ssize_t hciuart_copytorxbuffer(const struct hciuart_config_s *config); +static ssize_t hciuart_copyfromrxbuffer(const struct hciuart_config_s *config, + uint8_t *dest, size_t destlen); +static ssize_t hciuart_copytotxfifo(const struct hciuart_config_s *config); +static void hciuart_line_configure(const struct hciuart_config_s *config); +static int hciuart_configure(const struct hciuart_config_s *config); +static int hciuart_interrupt(int irq, void *context, void *arg); + +/* HCI-UART Lower-Half Methods */ + +static void hciuart_rxattach(const struct btuart_lowerhalf_s *lower, + btuart_rxcallback_t callback, void *arg); +static void hciuart_rxenable(const struct btuart_lowerhalf_s *lower, + bool enable); +static int hciuart_setbaud(const struct btuart_lowerhalf_s *lower, + uint32_t baud); +static ssize_t hciuart_read(const struct btuart_lowerhalf_s *lower, + void *buffer, size_t buflen); +static ssize_t hciuart_write(const struct btuart_lowerhalf_s *lower, + const void *buffer, size_t buflen); +static ssize_t hciuart_rxdrain(const struct btuart_lowerhalf_s *lower); + +#ifdef CONFIG_PM +static void hciuart_pm_notify(struct pm_callback_s *cb, int dowmin, + enum pm_state_e pmstate); +static int hciuart_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This describes the state of the TIVA UART0 port. */ + +#ifdef CONFIG_TIVA_UART0_HCIUART +/* I/O buffers */ + +static uint8_t g_uart0_rxbuffer[CONFIG_TIVA_HCIUART0_RXBUFSIZE]; +static uint8_t g_uart0_txbuffer[CONFIG_TIVA_HCIUART0_TXBUFSIZE]; + +/* HCI UART0 variable state information */ + +static struct hciuart_state_s g_hciuart0_state; + +/* HCI UART0 constant configuration information */ + +static const struct hciuart_config_s g_hciuart0_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart0_state, + + .rxbuffer = g_uart0_rxbuffer, + .txbuffer = g_uart0_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART0_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART0_TXBUFSIZE, + + .irq = TIVA_IRQ_UART0, + .baud = CONFIG_TIVA_HCIUART0_BAUD, + .id = 0, + .uartbase = TIVA_UART0_BASE, + .tx_gpio = GPIO_UART0_TX, + .rx_gpio = GPIO_UART0_RX, + .cts_gpio = UART0_GPIO_CTS, + .rts_gpio = UART0_GPIO_RTS, + .shutd_gpio = UART0_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART1 port. */ + +#ifdef CONFIG_TIVA_UART1_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart1_rxbuffer[CONFIG_TIVA_HCIUART1_RXBUFSIZE]; +static uint8_t g_uart1_txbuffer[CONFIG_TIVA_HCIUART1_TXBUFSIZE]; + +/* HCI UART1 variable state information */ + +static struct hciuart_state_s g_hciuart1_state; + +/* HCI UART1 constant configuration information */ + +static const struct hciuart_config_s g_hciuart1_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart1_state, + + .rxbuffer = g_uart1_rxbuffer, + .txbuffer = g_uart1_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART1_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART1_TXBUFSIZE, + + .irq = TIVA_IRQ_UART1, + .baud = CONFIG_TIVA_HCIUART1_BAUD, + .id = 1, + .uartbase = TIVA_UART1_BASE, + .tx_gpio = GPIO_UART1_TX, + .rx_gpio = GPIO_UART1_RX, + .cts_gpio = UART1_GPIO_CTS, + .rts_gpio = UART1_GPIO_RTS, + .shutd_gpio = UART1_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART2 port. */ + +#ifdef CONFIG_TIVA_UART2_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart2_rxbuffer[CONFIG_TIVA_HCIUART2_RXBUFSIZE]; +static uint8_t g_uart2_txbuffer[CONFIG_TIVA_HCIUART2_TXBUFSIZE]; + +/* HCI UART2 variable state information */ + +static struct hciuart_state_s g_hciuart2_state; + +/* HCI UART2 constant configuration information */ + +static const struct hciuart_config_s g_hciuart2_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart2_state, + + .rxbuffer = g_uart2_rxbuffer, + .txbuffer = g_uart2_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART2_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART2_TXBUFSIZE, + + .irq = TIVA_IRQ_UART2, + .baud = CONFIG_TIVA_HCIUART2_BAUD, + .id = 2, + .uartbase = TIVA_UART2_BASE, + .tx_gpio = GPIO_UART2_TX, + .rx_gpio = GPIO_UART2_RX, + .cts_gpio = UART2_GPIO_CTS, + .rts_gpio = UART2_GPIO_RTS, + .shutd_gpio = UART2_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART3 port. */ + +#ifdef CONFIG_TIVA_UART3_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart3_rxbuffer[CONFIG_TIVA_HCIUART3_RXBUFSIZE]; +static uint8_t g_uart3_txbuffer[CONFIG_TIVA_HCIUART3_TXBUFSIZE]; + +/* HCI UART3 variable state information */ + +static struct hciuart_state_s g_hciuart3_state; + +/* HCI UART3 constant configuration information */ + +static const struct hciuart_config_s g_hciuart3_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart3_state, + + .rxbuffer = g_uart3_rxbuffer, + .txbuffer = g_uart3_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART3_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART3_TXBUFSIZE, + + .irq = TIVA_IRQ_UART3, + .baud = CONFIG_TIVA_HCIUART3_BAUD, + .id = 3, + .uartbase = TIVA_UART3_BASE, + .tx_gpio = GPIO_UART3_TX, + .rx_gpio = GPIO_UART3_RX, + .cts_gpio = UART3_GPIO_CTS, + .rts_gpio = UART3_GPIO_RTS, + .shutd_gpio = UART3_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART4 port. */ + +#ifdef CONFIG_TIVA_UART4_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart4_rxbuffer[CONFIG_TIVA_HCIUART4_RXBUFSIZE]; +static uint8_t g_uart4_txbuffer[CONFIG_TIVA_HCIUART4_TXBUFSIZE]; + +/* HCI UART4 variable state information */ + +static struct hciuart_state_s g_hciuart4_state; + +/* HCI UART4 constant configuration information */ + +static const struct hciuart_config_s g_hciuart4_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart4_state, + + .rxbuffer = g_uart4_rxbuffer, + .txbuffer = g_uart4_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART4_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART4_TXBUFSIZE, + + .irq = TIVA_IRQ_UART4, + .baud = CONFIG_TIVA_HCIUART4_BAUD, + .id = 4, + .uartbase = TIVA_UART4_BASE, + .tx_gpio = GPIO_UART4_TX, + .rx_gpio = GPIO_UART4_RX, + .cts_gpio = UART4_GPIO_CTS, + .rts_gpio = UART4_GPIO_RTS, + .shutd_gpio = UART4_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART5 port. */ + +#ifdef CONFIG_TIVA_UART5_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart5_rxbuffer[CONFIG_TIVA_HCIUART5_RXBUFSIZE]; +static uint8_t g_uart5_txbuffer[CONFIG_TIVA_HCIUART5_TXBUFSIZE]; + +/* HCI UART5 variable state information */ + +static struct hciuart_state_s g_hciuart5_state; + +/* HCI UART5 constant configuration information */ + +static const struct hciuart_config_s g_hciuart5_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart5_state, + + .rxbuffer = g_uart5_rxbuffer, + .txbuffer = g_uart5_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART5_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART5_TXBUFSIZE, + + .irq = TIVA_IRQ_UART5, + .baud = CONFIG_TIVA_HCIUART5_BAUD, + .id = 5, + .uartbase = TIVA_UART5_BASE, + .tx_gpio = GPIO_UART5_TX, + .rx_gpio = GPIO_UART5_RX, + .cts_gpio = UART5_GPIO_CTS, + .rts_gpio = UART5_GPIO_RTS, + .shutd_gpio = UART5_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART6 port. */ + +#ifdef CONFIG_TIVA_UART6_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart6_rxbuffer[CONFIG_TIVA_HCIUART6_RXBUFSIZE]; +static uint8_t g_uart6_txbuffer[CONFIG_TIVA_HCIUART6_TXBUFSIZE]; + +/* HCI UART6 variable state information */ + +static struct hciuart_state_s g_hciuart6_state; + +/* HCI UART6 constant configuration information */ + +static const struct hciuart_config_s g_hciuart6_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart6_state, + + .rxbuffer = g_uart6_rxbuffer, + .txbuffer = g_uart6_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART6_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART6_TXBUFSIZE, + + .irq = TIVA_IRQ_UART6, + .baud = CONFIG_TIVA_HCIUART6_BAUD, + .id = 6, + .uartbase = TIVA_UART6_BASE, + .tx_gpio = GPIO_UART6_TX, + .rx_gpio = GPIO_UART6_RX, + .cts_gpio = UART6_GPIO_CTS, + .rts_gpio = UART6_GPIO_RTS, + .shutd_gpio = UART6_GPIO_NSHUTD +}; +#endif + +/* This describes the state of the TIVA UART7 port. */ + +#ifdef CONFIG_TIVA_UART7_HCIUART + +/* I/O buffers */ + +static uint8_t g_uart7_rxbuffer[CONFIG_TIVA_HCIUART7_RXBUFSIZE]; +static uint8_t g_uart7_txbuffer[CONFIG_TIVA_HCIUART7_TXBUFSIZE]; + +/* HCI UART7 variable state information */ + +static struct hciuart_state_s g_hciuart7_state; + +/* HCI UART7 constant configuration information */ + +static const struct hciuart_config_s g_hciuart7_config = +{ + .lower = + { + .rxattach = hciuart_rxattach, + .rxenable = hciuart_rxenable, + .setbaud = hciuart_setbaud, + .read = hciuart_read, + .write = hciuart_write, + .rxdrain = hciuart_rxdrain, + }, + + .state = &g_hciuart7_state, + + .rxbuffer = g_uart7_rxbuffer, + .txbuffer = g_uart7_txbuffer, + .rxbufsize = CONFIG_TIVA_HCIUART7_RXBUFSIZE, + .txbufsize = CONFIG_TIVA_HCIUART7_TXBUFSIZE, + + .irq = TIVA_IRQ_UART7, + .baud = CONFIG_TIVA_HCIUART7_BAUD, + .id = 7, + .uartbase = TIVA_UART7_BASE, + .tx_gpio = GPIO_UART7_TX, + .rx_gpio = GPIO_UART7_RX, + .cts_gpio = UART7_GPIO_CTS, + .rts_gpio = UART7_GPIO_RTS, + .shutd_gpio = UART7_GPIO_NSHUTD +}; +#endif + +/* This table lets us iterate over the configured UARTs */ + +static const struct hciuart_config_s * const g_hciuarts[] = +{ +#ifdef CONFIG_TIVA_UART0_HCIUART + &g_hciuart0_config, /* HCI UART on TIVA UART0 */ +#endif +#ifdef CONFIG_TIVA_UART1_HCIUART + &g_hciuart1_config, /* HCI UART on TIVA UART1 */ +#endif +#ifdef CONFIG_TIVA_UART2_HCIUART + &g_hciuart2_config, /* HCI UART on TIVA UART2 */ +#endif +#ifdef CONFIG_TIVA_UART3_HCIUART + &g_hciuart3_config, /* HCI UART on TIVA UART3 */ +#endif +#ifdef CONFIG_TIVA_UART4_HCIUART + &g_hciuart4_config, /* HCI UART on TIVA UART4 */ +#endif +#ifdef CONFIG_TIVA_UART5_HCIUART + &g_hciuart5_config, /* HCI UART on TIVA UART5 */ +#endif +#ifdef CONFIG_TIVA_UART6_HCIUART + &g_hciuart6_config, /* HCI UART on TIVA UART6 */ +#endif +#ifdef CONFIG_TIVA_UART7_HCIUART + &g_hciuart7_config, /* HCI UART on TIVA UART7 */ +#endif +}; + +#ifdef CONFIG_PM +static struct pm_callback_s g_serialcb = +{ + .notify = hciuart_pm_notify, + .prepare = hciuart_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hciuart_getreg32 + ****************************************************************************/ + +static inline uint32_t hciuart_getreg32(const struct hciuart_config_s *config, + unsigned int offset) +{ + return getreg32(config->uartbase + offset); +} + +/**************************************************************************** + * Name: hciuart_putreg32 + ****************************************************************************/ + +static inline void hciuart_putreg32(const struct hciuart_config_s *config, + unsigned int offset, uint32_t value) +{ + putreg32(value, config->uartbase + offset); +} + +/**************************************************************************** + * Name: hciuart_enableints + * + * Description: + * Enable interrupts as specified by bits in the 'intset' argument + * + * NOTE: This operation is not atomic. This function should be called + * only from within a critical section. + * + ****************************************************************************/ + +static void hciuart_enableints(const struct hciuart_config_s *config, + uint32_t intset) +{ + config->state->im |= intset; + + hciuart_putreg32(config, TIVA_UART_IM_OFFSET, config->state->im); +} + +/**************************************************************************** + * Name: hciuart_disableints + * + * Description: + * Disable interrupts as specified by bits in the 'intset' argument + * + * NOTE: This operation is not atomic. This function should be called + * only from within a critical section. + * + ****************************************************************************/ + +static void hciuart_disableints(const struct hciuart_config_s *config, + uint32_t intset) +{ + config->state->im &= ~intset; + + hciuart_putreg32(config, TIVA_UART_IM_OFFSET, config->state->im); +} + +/**************************************************************************** + * Name: hciuart_isenabled + * + * Description: + * Return true if any any of the interrupts specified in the 'intset' + * argument are enabled. + * + ****************************************************************************/ + +static bool hciuart_isenabled(const struct hciuart_config_s *config, + uint32_t intset) +{ + if ((config->state->im & intset) != 0) + { + return true; + } + + return false; +} + +/**************************************************************************** + * Name: hciuart_rxenabled + * + * Description: + * Check if Rx interrupts are enabled. + * + ****************************************************************************/ + +static inline bool hciuart_rxenabled(const struct hciuart_config_s *config) +{ + return hciuart_isenabled(config, UART_MIS_RXMIS | UART_MIS_RTMIS); +} + +/**************************************************************************** + * Name: hciuart_rxinuse + * + * Description: + * Return the number of bytes in the Rx buffer + * + * Example: rxbufsize=4, rxhead = 0, rxtail = 2 + * + * +---+---+---+---+ + * | X | X | | | X = inuse + * +---+---+---+---+ + * | `- rxtail = 2 + * `- rxhead = 0 + * + * inuse = 2 - 0 = 2 + * + * Example: rxbufsize=4, rxhead = 2, rxtail = 0 + * + * +---+---+---+---+ + * | | | X | X | X = inuse + * +---+---+---+---+ + * | `- rxhead = 2 + * `- rxtail = 0 + * + * inuse = (0 + 4) - 2 = 2 + * + ****************************************************************************/ + +static uint16_t hciuart_rxinuse(const struct hciuart_config_s *config) +{ + struct hciuart_state_s *state; + size_t inuse; + + DEBUGASSERT(config != NULL && config->state != NULL); + state = config->state; + + /* Keep track of how much is discarded */ + + if (state->rxtail >= state->rxhead) + { + inuse = state->rxtail - state->rxhead; + } + else + { + inuse = (state->rxtail + config->rxbufsize) - state->rxhead; + } + + return inuse; +} + +/**************************************************************************** + * Name: hciuart_copytorxbuffer + * + * Description: + * Copy data to the driver Rx buffer. + * + ****************************************************************************/ + +static ssize_t hciuart_copytorxbuffer(const struct hciuart_config_s *config) +{ + struct hciuart_state_s *state; + ssize_t nbytes = 0; + uint16_t rxhead; + uint16_t rxtail; + uint16_t rxnext; + uint8_t rxbyte; + + /* Get a copy of the rxhead and rxtail indices of the Rx buffer */ + + state = config->state; + rxhead = state->rxhead; + rxtail = state->rxtail; + + { + /* Is there data available in the Rx FIFO? */ + + while ((hciuart_getreg32(config, TIVA_UART_FR_OFFSET) & UART_FR_RXFE) + == 0) + { + /* Compare the Rx buffer head and tail indices. If the + * incremented tail index would make the Rx buffer appear empty, + * then we must stop the copy. If there is data pending in the Rx + * FIFO, this could be very bad because a data overrun condition + * is likely to* occur. + */ + + rxnext = rxtail + 1; + if (rxnext >= config->rxbufsize) + { + rxnext = 0; + } + + /* Would this make the Rx buffer appear full? */ + + if (rxnext == rxhead) + { + /* Yes, stop the copy and update the indices */ + + break; + } + + /* Get a byte from the Rx FIFO buffer */ + + rxbyte = hciuart_getreg32(config, TIVA_UART_DR_OFFSET) & 0xff; + + /* And add it to the tail of the Rx buffer */ + + config->rxbuffer[rxtail] = rxbyte; + rxtail = rxnext; + nbytes++; + } + } + + /* Save the updated Rx buffer tail index */ + + state->rxtail = rxtail; + + /* Notify any waiting threads that new Rx data is available */ + + if (nbytes > 0 && state->rxwaiting) + { + state->rxwaiting = false; + nxsem_post(&state->rxwait); + } + + wlinfo("rxhead %u rxtail %u nbytes %ld\n", rxhead, rxtail, (long)nbytes); + return nbytes; +} + +/**************************************************************************** + * Name: hciuart_copyfromrxbuffer + * + * Description: + * Copy data from the driver Rx buffer to the caller provided destination + * buffer. + * + ****************************************************************************/ + +static ssize_t hciuart_copyfromrxbuffer(const struct hciuart_config_s *config, + uint8_t *dest, size_t destlen) +{ + struct hciuart_state_s *state; + ssize_t nbytes; + uint16_t rxhead; + uint16_t rxtail; + uint8_t rxbyte; + + /* Get a copy of the rxhead and rxtail indices of the Rx buffer */ + + state = config->state; + rxhead = state->rxhead; + rxtail = state->rxtail; + nbytes = 0; + + /* Is there data available in the Rx buffer? Is there space in the user + * buffer? + */ + + while (rxhead != rxtail && nbytes < destlen) + { + /* Get a byte from the head of the Rx buffer */ + + rxbyte = config->rxbuffer[rxhead]; + + /* And add it to the caller's buffer buffer */ + + dest[nbytes] = rxbyte; + + /* Update indices and counts */ + + nbytes++; + + if (++rxhead >= config->rxbufsize) + { + rxhead = 0; + } + } + + /* Save the updated Rx buffer head index */ + + state->rxhead = rxhead; + + wlinfo("rxhead %u rxtail %u nbytes %ld\n", rxhead, rxtail, (long)nbytes); + return nbytes; +} + +/**************************************************************************** + * Name: hciuart_copytotxfifo + * + * Description: + * Copy data from the Tx buffer to the Tx FIFO + * + ****************************************************************************/ + +static ssize_t hciuart_copytotxfifo(const struct hciuart_config_s *config) +{ + struct hciuart_state_s *state; + ssize_t nbytes; + uint16_t txhead; + uint16_t txtail; + uint8_t txbyte; + + /* Get a copy of the txhead and txtail indices of the Rx buffer */ + + state = config->state; + txhead = state->txhead; + txtail = state->txtail; + nbytes = 0; + + /* Compare the Tx buffer head and tail indices. If the Tx buffer is + * empty, then we finished with the copy. + */ + + while (txhead != txtail) + { +#ifdef CONFIG_TIVA_HCIUART_SW_TXFLOW + if (tiva_gpioread(config->cts_gpio)) + { + break; + } +#endif + /* Is the transmit data register empty? + * + * Transmit data register empty + * This bit is set by hardware when the content of the transmit + * register has been transferred into the shift register. + */ + + if ((hciuart_getreg32(config, TIVA_UART_FR_OFFSET) & UART_FR_TXFF) != 0) + { + break; + } + + /* Get a byte from the head of the Tx buffer */ + + txbyte = config->txbuffer[txhead]; + if (++txhead >= config->txbufsize) + { + txhead = 0; + } + + /* And add it to the of the Tx FIFO */ + + hciuart_putreg32(config, TIVA_UART_DR_OFFSET, (uint32_t)txbyte); + nbytes++; + } + + wlinfo("txhead %u txtail %u nbytes %ld\n", txhead, txtail, (long)nbytes); + state->txhead = txhead; + return nbytes; +} + +/**************************************************************************** + * Name: hciuart_line_configure + * + * Description: + * Set the serial line format and speed. + * + * Per "Specification of the Bluetooth System, Wireless connections made + * easy, Host Controller Interface [Transport Layer]", Volume 4, Revision + * 1.2 or later, 1 January 2006, HCI UART tranport uses these settings: + * + * 8 data bits, no parity, 1 stop, RTS/CTS flow control + * + * BAUD and flow control response time are manufacturer specific. + * + ****************************************************************************/ + +static void hciuart_line_configure(const struct hciuart_config_s *config) +{ + uint32_t baud; + + uint32_t den; + uint32_t brdi; + uint32_t remainder; + uint32_t divfrac; + uint32_t lcrh; + + /* The current BAUD selection is part of the variable state data */ + + DEBUGASSERT(config != NULL && config->state != NULL); + baud = config->state->baud; + + wlinfo("baud %lu\n", (unsigned long)baud); + + den = baud << 4; + brdi = SYSCLK_FREQUENCY / den; + remainder = SYSCLK_FREQUENCY - den * brdi; + divfrac = ((remainder << 6) + (den >> 1)) / den; + + hciuart_putreg32(config, TIVA_UART_IBRD_OFFSET, brdi); + hciuart_putreg32(config, TIVA_UART_FBRD_OFFSET, divfrac); + + /* Configure 8 data bits, No parity, 1 stop bit - required by HCI UART */ + + lcrh = 0; + lcrh |= UART_LCRH_WLEN_8BITS; + hciuart_putreg32(config, TIVA_UART_LCRH_OFFSET, lcrh); +} + +/**************************************************************************** + * Name: hciuart_configure + * + * Description: + * Configure the UART clocking, GPIO pins, baud, bits, parity, etc. + * + * Per "Specification of the Bluetooth System, Wireless connections made + * easy, Host Controller Interface [Transport Layer]", Volume 4, Revision + * 1.2 or later, 1 January 2006, HCI UART tranport uses these settings: + * + * 8 data bits, no parity, 1 stop, RTS/CTS flow control + * + * BAUD and flow control response time are manufacturer specific. + * + ****************************************************************************/ + +static int hciuart_configure(const struct hciuart_config_s *config) +{ + uint32_t lcrh; + uint32_t ctl; + + /* Note: The logic here depends on the fact that that the UART module + * was enabled in tiva_lowsetup(). + */ + + wlinfo("config %p\n", config); + + /* Configure pins for UART use */ + + tiva_configgpio(config->tx_gpio); + tiva_configgpio(config->rx_gpio); + + tiva_configgpio(config->cts_gpio); + tiva_configgpio(config->rts_gpio); + +#ifdef CONFIG_BLUETOOTH_UART_CC2564 + tiva_configgpio(config->shutd_gpio); +#endif + + DEBUGASSERT(config->state != NULL); + config->state->baud = config->baud; + hciuart_line_configure(config); + + /* Enable the FIFOs */ + + lcrh = hciuart_getreg32(config, TIVA_UART_LCRH_OFFSET); + lcrh |= UART_LCRH_FEN; + hciuart_putreg32(config, TIVA_UART_LCRH_OFFSET, lcrh); + + /* Enable Rx, Tx, and the UART */ + + ctl = hciuart_getreg32(config, TIVA_UART_CTL_OFFSET); + ctl |= (UART_CTL_UARTEN | UART_CTL_TXE | UART_CTL_RXE); + hciuart_putreg32(config, TIVA_UART_CTL_OFFSET, ctl); + + /* Set up the cache IM value */ + + config->state->im = hciuart_getreg32(config, TIVA_UART_IM_OFFSET); + + hciuart_putreg32(config, TIVA_UART_IFLS_OFFSET, + UART_IFLS_TXIFLSEL_18th | UART_IFLS_RXIFLSEL_78th); + + hciuart_putreg32(config, TIVA_UART_IM_OFFSET, UART_IM_RXIM | UART_IM_RTIM); + + /* Enable bluetooth module */ + +#ifdef CONFIG_BLUETOOTH_UART_CC2564 + tiva_gpiowrite(config->shutd_gpio, true); +#endif + +#ifdef CONFIG_TIVA_HCIUART_SW_TXFLOW + while (tiva_gpioread(config->cts_gpio)) + { + } +#endif + +#ifdef CONFIG_TIVA_HCIUART_SW_RXFLOW + /* Disable Rx flow control, i.e, assert RTS (active low). */ + + tiva_gpiowrite(config->rts_gpio, false); +#endif + + return OK; +} + +/**************************************************************************** + * Name: hciuart_interrupt + * + * Description: + * This is the UART interrupt callback. It will be invoked when an + * interrupt received on the 'irq' It should call hciuart_copytorxbuffer + * or hciuart_copytotxfifo to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'irq' number into the + * appropriate btuart_lowerhalf_s structure in order to call these + * functions. + * + ****************************************************************************/ + +static int hciuart_interrupt(int irq, void *context, void *arg) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)arg; + struct hciuart_state_s *state; + uint32_t status; + uint8_t handled; + int passes; + + DEBUGASSERT(config != NULL && config->state != NULL); + state = config->state; + + /* Report serial activity to the power management logic */ + +#if defined(CONFIG_PM) && CONFIG_TIVA_PM_SERIAL_ACTIVITY > 0 + pm_activity(PM_IDLE_DOMAIN, CONFIG_TIVA_PM_SERIAL_ACTIVITY); +#endif + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + handled = (HCIUART_RXHANDLED | HCIUART_TXHANDLED); + for (passes = 0; passes < 256 && handled != 0; passes++) + { + handled = 0; + + /* Get the masked UART status word. */ + + status = hciuart_getreg32(config, TIVA_UART_MIS_OFFSET); + hciuart_putreg32(config, TIVA_UART_ICR_OFFSET, status); + + /* Handle incoming, receive bytes (non-DMA only) */ + + if ((status & (UART_MIS_RXMIS | UART_MIS_RTMIS)) != 0 && + hciuart_rxenabled(config)) + { + ssize_t nbytes; +#ifdef CONFIG_TIVA_HCIUART_SW_RXFLOW + /* Set CTS high if FIFO 7/8 full is triggered */ + + if ((status & (UART_MIS_RXMIS)) != 0) + { + tiva_gpiowrite(config->rts_gpio, true); + } +#endif + /* Received data ready... copy data from the Rx FIFO to the Rx + * buffer. + */ + + nbytes = hciuart_copytorxbuffer(config); + UNUSED(nbytes); + +#ifdef CONFIG_TIVA_HCIUART_SW_RXFLOW + /* Assert CTS because we now have space for more data */ + + if ((status & (UART_MIS_RXMIS)) != 0) + { + tiva_gpiowrite(config->rts_gpio, false); + } +#endif + /* Is there anything in the Rx buffer? Has the user registered an + * Rx callback function? + */ + + if (state->rxhead != state->rxtail && state->callback != NULL) + { + state->callback(&config->lower, state->arg); + handled = HCIUART_RXHANDLED; + } + } + + /* Handle outgoing, transmit bytes + * + * Transmit data register empty + * This bit is set by hardware when the content of the transmit data + * register has been transferred into the shift register. + */ + + if ((status & UART_MIS_TXMIS) != 0) + { + ssize_t nbytes; + uint8_t txhandled; + + /* Transmit data register empty ... copy data from the Tx buffer + * to the Tx FIFO. + */ + + nbytes = hciuart_copytotxfifo(config); + UNUSED(nbytes); + + /* If the Tx buffer is now empty, then disable further Tx + * interrupts. Tx interrupts will only be enabled in the + * following circumstances: + * + * 1. The user is waiting in hciuart_write() for space to become + * available in the Tx FIFO. + * 2. The full, outgoing message has been placed into the Tx buffer + * by hciuart_write(). + * + * In either case, no more Tx interrupts will be needed until more + * data is added to the Tx buffer. + */ + + txhandled = HCIUART_TXHANDLED; + if (state->txhead == state->txtail) + { + /* Disable Tx interrupts and treat the event as unhandled in + * order to terminate looping. + */ + + hciuart_disableints(config, UART_IM_TXIM); + txhandled = 0; + } + + /* This copy will free up space in the Tx FIFO. Wake up any + * threads that may have been waiting for space in the Tx + * buffer. + */ + + if (state->txwaiting) + { + state->txwaiting = false; + nxsem_post(&state->txwait); + } + + handled |= txhandled; + } + } + + return OK; +} + +/**************************************************************************** + * Name: hciuart_rxattach + * + * Description: + * Attach/detach the upper half Rx callback. + * + * rxattach() allows the upper half logic to attach a callback function + * that will be used to inform the upper half that an Rx frame is + * available. This callback will, most likely, be invoked in the + * context of an interrupt callback. The receive() method should then + * be invoked in order to receive the obtain the Rx frame data. + * + ****************************************************************************/ + +static void hciuart_rxattach(const struct btuart_lowerhalf_s *lower, + btuart_rxcallback_t callback, void *arg) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)lower; + struct hciuart_state_s *state; + irqstate_t flags; + + wlinfo("config %p callback %p arg %p\n", config, callback, arg); + + DEBUGASSERT(config != NULL && config->state != NULL); + state = config->state; + + /* If the callback is NULL, then we are detaching */ + + flags = spin_lock_irqsave(); + if (callback == NULL) + { + uint32_t intset; + + /* Disable Rx callbacks and detach the Rx callback */ + + intset = UART_IM_RXIM | UART_IM_RTIM; + hciuart_disableints(config, intset); + + state->callback = NULL; + state->arg = NULL; + } + + /* Otherwise, we are attaching */ + + else + { + state->arg = arg; + state->callback = callback; + } + + spin_unlock_irqrestore(flags); +} + +/**************************************************************************** + * Name: hciuart_rxenable + * + * Description: + * Enable/disable RX callbacks from the HCI UART. + * + * hciuart_rxenable() may be used to enable or disable callback events. + * This probably translates to enabling and disabled Rx interrupts at + * the UART. NOTE: Rx event notification should be done sparingly: + * Rx data overrun may occur when Rx events are disabled! + * + ****************************************************************************/ + +static void hciuart_rxenable(const struct btuart_lowerhalf_s *lower, + bool enable) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)lower; + + DEBUGASSERT(config != NULL && config->state != NULL); + + { + uint32_t intset; + irqstate_t flags; + + flags = spin_lock_irqsave(); + if (enable) + { + /* Receive an interrupt when their is anything in the Rx data + * register (or an Rx timeout occurs). + */ + + intset = UART_IM_RXIM | UART_IM_RTIM; + hciuart_enableints(config, intset); + } + else + { + intset = UART_IM_RXIM | UART_IM_RTIM; + hciuart_disableints(config, intset); + } + + spin_unlock_irqrestore(flags); + } +} + +/**************************************************************************** + * Name: hciuart_setbaud + * + * Description: + * The HCI UART comes up with some initial BAUD rate. Some support + * auto-BAUD detection, some support writing a configuration file to + * select the initial BAUD. The simplest strategy, however, is simply + * to use the HCI UART's default initial BAUD to perform the basic + * bring up, then send a vendor-specific command to increase the HCI + * UARTs BAUD. This method then may be used to adjust the lower half + * driver to the new HCI UART BAUD. + * + ****************************************************************************/ + +static int hciuart_setbaud(const struct btuart_lowerhalf_s *lower, + uint32_t baud) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)lower; + + DEBUGASSERT(config != NULL && config->state != NULL); + + config->state->baud = baud; + hciuart_line_configure(config); + return OK; +} + +/**************************************************************************** + * Name: hciuart_read + * + * Description: + * Read UART data. + * + * hciuart_read() after receipt of a callback notifying the upper half of + * the availability of Rx frame, the upper half may call the receive() + * method in order to obtain the buffered Rx frame data. + * + ****************************************************************************/ + +static ssize_t hciuart_read(const struct btuart_lowerhalf_s *lower, + void *buffer, size_t buflen) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)lower; + struct hciuart_state_s *state; + uint8_t *dest; + size_t remaining; + size_t ntotal; + ssize_t nbytes; + bool rxenable; + + wlinfo("config %p buffer %p buflen %lu\n", + config, buffer, (unsigned long)buflen); + + /* NOTE: This assumes that the caller has exclusive access to the Rx + * buffer, i.e., one lower half instance can server only one upper half! + */ + + DEBUGASSERT(config != NULL && config->state != NULL); + state = config->state; + + /* Read any pending data to the Rx buffer */ + + nbytes = hciuart_copytorxbuffer(config); + UNUSED(nbytes); + + /* Loop copying data to the user buffer while the Rx buffer is not empty + * and the callers buffer is not full. + */ + + dest = (uint8_t *)buffer; + remaining = buflen; + ntotal = 0; + + rxenable = hciuart_rxenabled(config); + hciuart_rxenable(lower, false); + + while (state->rxtail != state->rxhead && ntotal < buflen) + { + nbytes = hciuart_copyfromrxbuffer(config, dest, remaining); + if (nbytes <= 0) + { + DEBUGASSERT(nbytes == 0); + + /* If no data has been received, then we must wait for the arrival + * of new Rx data and try again. + */ + + if (ntotal == 0) + { + DEBUGASSERT(!state->rxwaiting); + state->rxwaiting = true; + do + { + int ret = nxsem_wait(&state->rxwait); + DEBUGASSERT(ret == 0 || ret == -EINTR); + UNUSED(ret); + } + while (state->rxwaiting); + } + + /* Otherwise, this must be the end of the packet. Just break out + * and return what we have. + */ + + else + { + break; + } + } + else + { + /* More data has been copied. Update pointers, counts, and + * indices. + */ + + ntotal += nbytes; + dest += nbytes; + remaining -= nbytes; + + /* Read any additional pending data into the Rx buffer that may + * have accumulated while we were copying. + */ + + nbytes = hciuart_copytorxbuffer(config); + if (nbytes < 0) + { + /* An error occurred.. this should not really happen */ + + return nbytes; + } + + /* Otherwise, continue looping */ + } + } + + hciuart_rxenable(lower, rxenable); + return ntotal; +} + +/**************************************************************************** + * Name: hciuart_write + * + * Description: + * Write UART data. + * + * hciuart_write() will add the outgoing frame to the Tx buffer and will + * return immediately. This function may block only in the event that + * there is insufficient buffer space to hold the Tx frame data. In that + * case the lower half will block until there is sufficient to buffer + * the entire outgoing packet. + * + ****************************************************************************/ + +static ssize_t hciuart_write(const struct btuart_lowerhalf_s *lower, + const void *buffer, size_t buflen) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)lower; + struct hciuart_state_s *state; + const uint8_t *src; + ssize_t nbytes = 0; + uint16_t txhead; + uint16_t txtail; + uint16_t txnext; + size_t remaining; + irqstate_t flags; + + DEBUGASSERT(config != NULL && config->state != NULL); + state = config->state; + + /* NOTE: This assumes that the caller has exclusive access to the Tx + * buffer, i.e., one lower half instance can serve only one upper half! + */ + + /* Make sure that the Tx Interrupts are disabled. */ + + flags = spin_lock_irqsave(); + hciuart_disableints(config, UART_IM_TXIM); + spin_unlock_irqrestore(flags); + + /* Loop until all of the user data have been moved to the Tx buffer */ + + src = buffer; + remaining = buflen; + + while (remaining > 0) + { + /* Copy bytes to the tail of the Tx buffer */ + /* Get a copy of the rxhead and rxtail indices of the Tx buffer */ + + txhead = state->txhead; + txtail = state->txtail; + + txnext = txtail + 1; + if (txnext >= config->txbufsize) + { + txnext = 0; + } + + /* Is there space available in the Tx buffer? Do have more bytes to + * copy? + */ + + while (txhead != txnext && remaining > 0) + { + /* Yes.. copy one byte to the Tx buffer */ + + config->txbuffer[txtail] = *src++; + + txtail = txnext; + if (++txnext >= config->txbufsize) + { + txnext = 0; + } + + remaining--; + } + + /* Save the updated Tx buffer tail index */ + + state->txtail = txtail; + + /* Copy bytes from the Tx buffer to the Tx FIFO */ + + nbytes = hciuart_copytotxfifo(config); + + /* If nothing could be copied to the Tx FIFO and we still have user + * data that we have not added to the Tx buffer, then we must wait for + * space in the Tx* buffer then try again. + */ + + if (nbytes <= 0 && remaining > 0) + { + DEBUGASSERT(nbytes == 0); + + /* Enable the Tx interrupt and wait for space open up in the Tx + * buffer. + */ + + flags = enter_critical_section(); + hciuart_enableints(config, UART_IM_TXIM); + + DEBUGASSERT(!state->txwaiting); + state->txwaiting = true; + do + { + int ret = nxsem_wait(&state->txwait); + DEBUGASSERT(ret == 0 || ret == -EINTR); + UNUSED(ret); + } + while (state->txwaiting); + + /* Disable Tx interrupts again */ + + hciuart_disableints(config, UART_IM_TXIM); + leave_critical_section(flags); + } + } + + /* If the Tx buffer is not empty, then exit with the Tx interrupts enabled. */ + + if (state->txhead != state->txtail) + { + flags = spin_lock_irqsave(); + hciuart_enableints(config, UART_IM_TXIM); + spin_unlock_irqrestore(flags); + } + + return buflen; +} + +/**************************************************************************** + * Name: hciuart_rxdrain + * + * Description: + * Flush/drain all buffered RX data + * + ****************************************************************************/ + +static ssize_t hciuart_rxdrain(const struct btuart_lowerhalf_s *lower) +{ + const struct hciuart_config_s *config = + (const struct hciuart_config_s *)lower; + struct hciuart_state_s *state; + size_t ntotal; + ssize_t nbytes; + bool rxenable; + + DEBUGASSERT(config != NULL && config->state != NULL); + state = config->state; + + /* Read any pending data to the Rx buffer */ + + nbytes = hciuart_copytorxbuffer(config); + UNUSED(nbytes); + + /* Loop discarding in the Rx buffer until the Rx buffer is empty */ + + ntotal = 0; + + rxenable = hciuart_rxenabled(config); + hciuart_rxenable(lower, false); + + while (state->rxtail != state->rxhead) + { + /* Keep track of how much is discarded */ + + ntotal += hciuart_rxinuse(config); + + /* Discard the data in the Rx buffer */ + + state->rxhead = 0; + state->rxtail = 0; + + /* Read any additional pending data into the Rx buffer that may + * have accumulated while we were discarding. + */ + + nbytes = hciuart_copytorxbuffer(config); + UNUSED(nbytes); + } + + hciuart_rxenable(lower, rxenable); + return ntotal; +} + +/**************************************************************************** + * Name: hciuart_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opportunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void hciuart_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Logic for PM_NORMAL goes here */ + + } + break; + + case(PM_IDLE): + { + /* Logic for PM_IDLE goes here */ + + } + break; + + case(PM_STANDBY): + { + /* Logic for PM_STANDBY goes here */ + + } + break; + + case(PM_SLEEP): + { + /* Logic for PM_SLEEP goes here */ + + } + break; + + default: + /* Should not get here */ + + break; + } +} +#endif + +/**************************************************************************** + * Name: hciuart_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int hciuart_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* Logic to prepare for a reduced power state goes here. */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hciuart_instantiate + * + * Description: + * Obtain an instance of the HCI UART interface for the specified HCI UART + * This assumes that hciuart_initialize was called previously. + * + * Input Parameters: + * uart - Identifies the HCI UART to be configured + * + * Returned Value: + * On success, a reference to the HCI UART lower driver for the associated + * UART + * + ****************************************************************************/ + +const struct btuart_lowerhalf_s * +hciuart_instantiate(enum hciuart_devno_e uart) +{ + const struct hciuart_config_s *config; +#ifdef CONFIG_PM + int ret; +#endif + + wlinfo("Instantiating HCIUART%d\n", (int)uart + 1); + DEBUGASSERT((int)uart >= 0 && (int)uart < 8); + + /* Check if this uart is available in the configuration */ + + config = g_hciuarts[(int)uart]; + if (config == NULL) + { + wlerr("ERROR: UART%d not configured\n", uart + 1); + return NULL; + } + + /* Register to receive power management callbacks */ + +#ifdef CONFIG_PM + ret = pm_register(&g_serialcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + + /* Configure and enable the UART */ + + hciuart_configure(config); + return &config->lower; +} + +/**************************************************************************** + * Name: hciuart_initialize + * + * Description: + * Performs the low-level, one-time UART initialization. This must be + * called before hciuart_instantiate. + * + * Input Paramters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void hciuart_initialize(void) +{ + const struct hciuart_config_s *config; + struct hciuart_state_s *state; + int ret; + int i; + + /* Configure all UARTs */ + + for (i = 0; i < sizeof(g_hciuarts)/sizeof(g_hciuarts[0]); i++) + { + config = g_hciuarts[i]; + if (config != NULL) + { + state = config->state; + + /* Enable UART clock */ + + tiva_uart_enableclk(config->id); + tiva_uart_enablepwr(config->id); + + /* Disable UART interrupts */ + + hciuart_disableints(config, HCIUART_ALLINTS); + + /* Initialize signalling semaphores */ + + nxsem_init(&state->rxwait, 0, 0); + nxsem_setprotocol(&state->rxwait, SEM_PRIO_NONE); + + nxsem_init(&state->txwait, 0, 0); + nxsem_setprotocol(&state->txwait, SEM_PRIO_NONE); + + /* Attach and enable the HCI UART IRQ */ + + ret = irq_attach(config->irq, hciuart_interrupt, (void *)config); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the UART) + */ + + up_enable_irq(config->irq); + } + } + } +} diff --git a/arch/arm/src/tiva/tiva_hciuart.h b/arch/arm/src/tiva/tiva_hciuart.h new file mode 100644 index 00000000000..7b954effed8 --- /dev/null +++ b/arch/arm/src/tiva/tiva_hciuart.h @@ -0,0 +1,138 @@ +/**************************************************************************** + * arch/arm/src/tiva/tiva_hciuart.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name NuttX 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 EXPRESS 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_TIVA_HCIUART_H +#define __ARCH_ARM_SRC_TIVA_HCIUART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum hciuart_devno_e +{ +#ifdef CONFIG_TIVA_UART0_HCIUART + HCIUART0, /* HCI UART on TIVA UART0 */ +#endif +#ifdef CONFIG_TIVA_UART1_HCIUART + HCIUART1, /* HCI UART on TIVA UART1 */ +#endif +#ifdef CONFIG_TIVA_UART2_HCIUART + HCIUART2, /* HCI UART on TIVA UART2 */ +#endif +#ifdef CONFIG_TIVA_UART3_HCIUART + HCIUART3, /* HCI UART on TIVA UART3 */ +#endif +#ifdef CONFIG_TIVA_UART4_HCIUART + HCIUART4, /* HCI UART on TIVA UART4 */ +#endif +#ifdef CONFIG_TIVA_UART5_HCIUART + HCIUART5, /* HCI UART on TIVA UART5 */ +#endif +#ifdef CONFIG_TIVA_UART6_HCIUART + HCIUART6, /* HCI UART on TIVA UART6 */ +#endif +#ifdef CONFIG_TIVA_UART7_HCIUART + HCIUART7 /* HCI UART on TIVA UART7 */ +#endif +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: hciuart_instantiate + * + * Description: + * Obtain an instance of the HCI UART interface for the specified HCI UART + * This assumes that hciuart_initialize was called previously. + * + * Input Parameters: + * uart - Identifies the HCI UART to be configured + * + * Returned Value: + * On success, a reference to the HCI UART lower driver for the associated + * UART + * + ****************************************************************************/ + +const struct btuart_lowerhalf_s * +hciuart_instantiate(enum hciuart_devno_e uart); + +/**************************************************************************** + * Name: hciuart_initialize + * + * Description: + * Performs the low-level, one-time USART initialization. This must be + * called before hciuart_instantiate. + * + * Input Paramters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void hciuart_initialize(void); + +/**************************************************************************** + * Name: tiva_serial_dma_poll + * + * Description: + * Checks receive DMA buffers for received bytes that have not accumulated + * to the point where the DMA half/full interrupt has triggered. + * + * This function should be called from a timer or other periodic context. + * + * Input Paramters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_TIVA_HCIUART_RXDMA +void tiva_serial_dma_poll(void); +#endif + +#endif /* __ARCH_ARM_SRC_TIVA_HCIUART_H */ diff --git a/configs/tm4c1294-launchpad/include/board.h b/configs/tm4c1294-launchpad/include/board.h index 8afbe185d14..d9b172ca647 100644 --- a/configs/tm4c1294-launchpad/include/board.h +++ b/configs/tm4c1294-launchpad/include/board.h @@ -195,4 +195,19 @@ #define GPIO_EN0_LED1 GPIO_EN0_LED1_1 #define GPIO_EN0_LED2 GPIO_EN0_LED2_1 +/* Control pins for BOOST-CC2564MODA plugged into BoosterPack1 + * + * --- ------------ + * Pin Pin Function + * --- ------------ + * PM3 NSHUTD + * PG0 RTS + * PL4 CTS + * --- ------------ + */ + +#define UART7_GPIO_NSHUTD (GPIO_FUNC_OUTPUT | GPIO_PORTM | GPIO_PIN_3) +#define UART7_GPIO_RTS (GPIO_FUNC_OUTPUT | GPIO_PORTG | GPIO_PIN_0) +#define UART7_GPIO_CTS (GPIO_FUNC_INPUT | GPIO_PORTL | GPIO_PIN_4) + #endif /* __CONFIGS_TM4C1294_LAUNCHPAD_INCLUDE_BOARD_H */ diff --git a/configs/tm4c1294-launchpad/src/Makefile b/configs/tm4c1294-launchpad/src/Makefile index 35532e4824c..39fc3b53c77 100644 --- a/configs/tm4c1294-launchpad/src/Makefile +++ b/configs/tm4c1294-launchpad/src/Makefile @@ -60,4 +60,10 @@ ifeq ($(CONFIG_LIB_BOARDCTL),y) CSRCS += tm4c_appinit.c endif +ifeq ($(CONFIG_TIVA_HCIUART),y) +ifeq ($(CONFIG_BLUETOOTH_UART),y) +CSRCS += tm4c_hciuart.c +endif +endif + include $(TOPDIR)/configs/Board.mk diff --git a/configs/tm4c1294-launchpad/src/tm4c1294-launchpad.h b/configs/tm4c1294-launchpad/src/tm4c1294-launchpad.h index fb392a6c852..c5e3b7050a0 100644 --- a/configs/tm4c1294-launchpad/src/tm4c1294-launchpad.h +++ b/configs/tm4c1294-launchpad/src/tm4c1294-launchpad.h @@ -50,6 +50,30 @@ * Pre-processor Definitions ************************************************************************************/ /* Configuration ********************************************************************/ +#define HAVE_HCIUART 1 + +#if !defined(CONFIG_TIVA_HCIUART) || !defined(CONFIG_BLUETOOTH_UART) +# undef HAVE_HCIUART +#elif defined(CONFIG_TIVA_UART0_HCIUART) +# define HCIUART_SERDEV HCIUART0 +#elif defined(CONFIG_TIVA_UART1_HCIUART) +# define HCIUART_SERDEV HCIUART1 +#elif defined(CONFIG_TIVA_UART2_HCIUART) +# define HCIUART_SERDEV HCIUART2 +#elif defined(CONFIG_TIVA_UART3_HCIUART) +# define HCIUART_SERDEV HCIUART3 +#elif defined(CONFIG_TIVA_UART4_HCIUART) +# define HCIUART_SERDEV HCIUART4 +#elif defined(CONFIG_TIVA_UART5_HCIUART) +# define HCIUART_SERDEV HCIUART5 +#elif defined(CONFIG_TIVA_UART6_HCIUART) +# define HCIUART_SERDEV HCIUART6 +#elif defined(CONFIG_TIVA_UART7_HCIUART) +# define HCIUART_SERDEV HCIUART7 +#else +# error No HCI UART specifified +#endif + /* How many SSI modules does this chip support? */ @@ -177,5 +201,25 @@ int tm4c_bringup(void); int tiva_timer_configure(void); #endif +/**************************************************************************** + * Name: hciuart_dev_initialize + * + * Description: + * This function is called by board initialization logic to configure the + * Bluetooth HCI UART driver + * + * Input Parameters: + * None + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +#ifdef HAVE_HCIUART +int hciuart_dev_initialize(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __CONFIGS_TM4C1294_LAUNCHPAD_TM4C1294_LAUNCHPAD_H */ diff --git a/configs/tm4c1294-launchpad/src/tm4c_bringup.c b/configs/tm4c1294-launchpad/src/tm4c_bringup.c index 35e1f760278..16ccb611df5 100644 --- a/configs/tm4c1294-launchpad/src/tm4c_bringup.c +++ b/configs/tm4c1294-launchpad/src/tm4c_bringup.c @@ -306,7 +306,7 @@ static void tm4c_qei(void) int tm4c_bringup(void) { -#ifdef HAVE_TIMER +#if defined(HAVE_TIMER) || defined(HAVE_HCIUART) int ret; #endif @@ -336,5 +336,13 @@ int tm4c_bringup(void) } #endif +#ifdef HAVE_HCIUART + ret = hciuart_dev_initialize(); + if (ret < 0) + { + serr("ERROR: Failed to initialize HCI UART driver: %d\n", ret); + } +#endif + return OK; } diff --git a/configs/tm4c1294-launchpad/src/tm4c_hciuart.c b/configs/tm4c1294-launchpad/src/tm4c_hciuart.c new file mode 100644 index 00000000000..3268ac8db73 --- /dev/null +++ b/configs/tm4c1294-launchpad/src/tm4c_hciuart.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * configs/tm4c1294-launchpad/src/tm4c_hciuart.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Alan Carvalho de Assis + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name NuttX 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 EXPRESS 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "tiva_hciuart.h" +#include "tm4c1294-launchpad.h" + +#include + +#ifdef HAVE_HCIUART + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hciuart_dev_initialize + * + * Description: + * This function is called by board initialization logic to configure the + * Bluetooth HCI UART driver + * + * Input Parameters: + * None + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int hciuart_dev_initialize(void) +{ + const struct btuart_lowerhalf_s *lower; + int ret; + + /* Perform one-time initialization */ + + hciuart_initialize(); + + /* Instantiate the HCI UART lower half interface */ + + lower = hciuart_instantiate(HCIUART_SERDEV); + if (lower == NULL) + { + wlerr("ERROR: Failed to instantiate HCIUART%d\n", HCIUART_SERDEV + 1); + return -ENODEV; + } + + /* Then initialize the HCI UART upper half driver with the bluetooth stack */ + + ret = btuart_register(lower); + if (ret < 0) + { + wlerr("ERROR: btuart_register() failed: %d\n", ret); + } + + return ret; +} + +#endif /* HAVE_HCIUART */