From 07f9154e5ba15383690b2be63bfc5c1f64b73f2d Mon Sep 17 00:00:00 2001 From: Alin Jerpelea Date: Mon, 21 Oct 2019 14:14:33 +0000 Subject: [PATCH] Merged in alinjerpelea/nuttx (pull request #1056) boards: cxd56xx: add board support for LTE modem and modem driver * drivers: modem: add altair modem driver Add modem driver for the altair modem Signed-off-by: Alin Jerpelea * boards: cxd56xx: add board support for LTE modem Add the Altair LTE modem support on the Spresense board Signed-off-by: Alin Jerpelea * boards: cxd56xx: spresense: add LTE defconfig Add the Altair LTE modem defconfig for spresense board Signed-off-by: Alin Jerpelea Approved-by: Gregory Nutt --- boards/arm/cxd56xx/common/src/Make.defs | 5 + boards/arm/cxd56xx/common/src/cxd56_altmdm.c | 319 +++ .../arm/cxd56xx/common/src/cxd56_altmdm_spi.c | 255 ++ boards/arm/cxd56xx/spresense/Kconfig | 43 + .../cxd56xx/spresense/configs/lte/defconfig | 88 + boards/arm/cxd56xx/spresense/include/board.h | 1 + .../cxd56xx/spresense/include/cxd56_altmdm.h | 201 ++ .../arm/cxd56xx/spresense/src/cxd56_bringup.c | 8 + drivers/modem/Kconfig | 2 + drivers/modem/Make.defs | 2 + drivers/modem/altair/Kconfig | 52 + drivers/modem/altair/Make.defs | 50 + drivers/modem/altair/altmdm.c | 463 ++++ drivers/modem/altair/altmdm_dev.h | 194 ++ drivers/modem/altair/altmdm_pm.c | 1771 +++++++++++++ drivers/modem/altair/altmdm_pm.h | 239 ++ drivers/modem/altair/altmdm_pm_state.c | 154 ++ drivers/modem/altair/altmdm_pm_state.h | 86 + drivers/modem/altair/altmdm_spi.c | 2281 +++++++++++++++++ drivers/modem/altair/altmdm_spi.h | 182 ++ drivers/modem/altair/altmdm_sys.c | 827 ++++++ drivers/modem/altair/altmdm_sys.h | 274 ++ include/nuttx/modem/altmdm.h | 152 ++ 23 files changed, 7649 insertions(+) create mode 100644 boards/arm/cxd56xx/common/src/cxd56_altmdm.c create mode 100644 boards/arm/cxd56xx/common/src/cxd56_altmdm_spi.c create mode 100644 boards/arm/cxd56xx/spresense/configs/lte/defconfig create mode 100644 boards/arm/cxd56xx/spresense/include/cxd56_altmdm.h create mode 100644 drivers/modem/altair/Kconfig create mode 100644 drivers/modem/altair/Make.defs create mode 100644 drivers/modem/altair/altmdm.c create mode 100644 drivers/modem/altair/altmdm_dev.h create mode 100644 drivers/modem/altair/altmdm_pm.c create mode 100644 drivers/modem/altair/altmdm_pm.h create mode 100644 drivers/modem/altair/altmdm_pm_state.c create mode 100644 drivers/modem/altair/altmdm_pm_state.h create mode 100644 drivers/modem/altair/altmdm_spi.c create mode 100644 drivers/modem/altair/altmdm_spi.h create mode 100644 drivers/modem/altair/altmdm_sys.c create mode 100644 drivers/modem/altair/altmdm_sys.h create mode 100644 include/nuttx/modem/altmdm.h diff --git a/boards/arm/cxd56xx/common/src/Make.defs b/boards/arm/cxd56xx/common/src/Make.defs index 8d6fa0baa4..ea6ae44a54 100644 --- a/boards/arm/cxd56xx/common/src/Make.defs +++ b/boards/arm/cxd56xx/common/src/Make.defs @@ -38,6 +38,11 @@ ifeq ($(CONFIG_CXD56_AUDIO), y) CSRCS += cxd56_audio.c endif +ifeq ($(CONFIG_MODEM_ALTMDM),y) +CSRCS += cxd56_altmdm.c +CSRCS += cxd56_altmdm_spi.c +endif + ifeq ($(CONFIG_BOARDCTL_UNIQUEID),y) CSRCS += cxd56_uid.c endif diff --git a/boards/arm/cxd56xx/common/src/cxd56_altmdm.c b/boards/arm/cxd56xx/common/src/cxd56_altmdm.c new file mode 100644 index 0000000000..cd5064b3a8 --- /dev/null +++ b/boards/arm/cxd56xx/common/src/cxd56_altmdm.c @@ -0,0 +1,319 @@ +/**************************************************************************** + * boards/arm/cxd56xx/common/src/cxd56_altmdm.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) +#include +#include +#include "cxd56_gpio.h" +#include "cxd56_gpioint.h" +#include "cxd56_pinconfig.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) + +#define ALTMDM_SHUTDOWN (PIN_SPI2_MISO) +#define MODEM_WAKEUP (PIN_SPI2_MOSI) +#define MASTER_REQUEST (PIN_RTC_IRQ_OUT) +#define SLAVE_REQUEST (PIN_SPI2_SCK) +#define LTE_POWER_BUTTON (PIN_AP_CLK) +#define NUM_OF_PINS (sizeof(pincfg) / sizeof(struct altmdm_pincfg)) + +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) + +struct altmdm_pincfg + { + uint32_t pin; + bool input_enable; + bool init_val; + }; + +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) + +static const struct altmdm_pincfg pincfg[] = +{ + {MODEM_WAKEUP, false, false}, /* out, low */ + {MASTER_REQUEST, false, false}, /* out, low */ + {SLAVE_REQUEST, true, false}, /* in, low */ +}; + +#endif + +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_altmdm_poweron + * + * Description: + * Power on the Altair modem device on the board. + * + ****************************************************************************/ + +void board_altmdm_poweron(void) +{ + int i; + + /* power on altair modem device */ + + cxd56_gpio_config(ALTMDM_SHUTDOWN, false); + cxd56_gpio_write(ALTMDM_SHUTDOWN, true); + + cxd56_gpio_config(LTE_POWER_BUTTON, false); + cxd56_gpio_write(LTE_POWER_BUTTON, true); + + board_power_control(POWER_LTE, true); + + for (i = 0; i < NUM_OF_PINS; i++) + { + /* input pin: input enable */ + + cxd56_gpio_config(pincfg[i].pin, pincfg[i].input_enable); + + /* if it is an output pin, write a default value */ + + if (pincfg[i].input_enable == false) + { + cxd56_gpio_write(pincfg[i].pin, pincfg[i].init_val); + } + } + + /* Slave request seems to float in Lite Hibernation and becomes HIGH at some + * times when it should stay LOW. + */ + + cxd56_pin_config(PINCONF_SET(SLAVE_REQUEST, + PINCONF_MODE0, + PINCONF_INPUT_ENABLE, + PINCONF_DRIVE_NORMAL, PINCONF_PULLDOWN)); +} + +/**************************************************************************** + * Name: board_altmdm_poweroff + * + * Description: + * Power off the Altair modem device on the board. + * + ****************************************************************************/ + +void board_altmdm_poweroff(void) +{ + int i; + + for (i = 0; i < NUM_OF_PINS; i++) + { + /* input disable, output disable(Hi-z) */ + + cxd56_gpio_config(pincfg[i].pin, false); + } + + /* power off Altair modem device */ + + cxd56_gpio_write(ALTMDM_SHUTDOWN, true); + + board_power_control(POWER_LTE, false); + + cxd56_gpio_write(ALTMDM_SHUTDOWN, false); + cxd56_gpio_write(LTE_POWER_BUTTON, false); +} + +/**************************************************************************** + * Name: board_altmdm_gpio_write + * + * Description: + * Write GPIO pin. + * + ****************************************************************************/ + +void board_altmdm_gpio_write(uint32_t pin, bool value) +{ + if (pin < NUM_OF_PINS) + { + if (pincfg[pin].input_enable == false) + { + cxd56_gpio_write(pincfg[pin].pin, value); + } + } +} + +/**************************************************************************** + * Name: board_altmdm_gpio_read + * + * Description: + * Read GPIO pin. + * + ****************************************************************************/ + +bool board_altmdm_gpio_read(uint32_t pin) +{ + bool val = false; + + if (pin < NUM_OF_PINS) + { + if (pincfg[pin].input_enable == true) + { + val = cxd56_gpio_read(pincfg[pin].pin); + } + } + + return val; +} + +/**************************************************************************** + * Name: board_altmdm_gpio_irq + * + * Description: + * Register GPIO irq. + * + ****************************************************************************/ + +void board_altmdm_gpio_irq(uint32_t pin, uint32_t polarity, + uint32_t noise_filter, xcpt_t irqhandler) +{ + uint32_t pol; + uint32_t nf; + + switch (polarity) + { + case ALTMDM_GPIOINT_LEVEL_HIGH: + pol = GPIOINT_LEVEL_HIGH; + break; + + case ALTMDM_GPIOINT_LEVEL_LOW: + pol = GPIOINT_LEVEL_LOW; + break; + + case ALTMDM_GPIOINT_EDGE_RISE: + pol = GPIOINT_EDGE_RISE; + break; + + case ALTMDM_GPIOINT_EDGE_FALL: + pol = GPIOINT_EDGE_FALL; + break; + + case ALTMDM_GPIOINT_EDGE_BOTH: + pol = GPIOINT_EDGE_BOTH; + break; + + default: + return; + break; + } + if (noise_filter == ALTMDM_GPIOINT_NOISE_FILTER_ENABLE) + { + nf = GPIOINT_NOISE_FILTER_ENABLE; + } + else + { + nf = GPIOINT_NOISE_FILTER_DISABLE; + } + if (pin < NUM_OF_PINS) + { + if (pincfg[pin].input_enable == true) + { + if (irqhandler) + { + /* Attach then enable the new interrupt handler */ + + cxd56_gpioint_config(pincfg[pin].pin, + (GPIOINT_TOGGLE_MODE_MASK | nf | pol), + irqhandler, NULL); + } + } + } +} + +/**************************************************************************** + * Name: board_altmdm_gpio_int_control + * + * Description: + * Enable or disable GPIO interrupt. + * + ****************************************************************************/ + +void board_altmdm_gpio_int_control(uint32_t pin, bool en) +{ + if (pin < NUM_OF_PINS) + { + if (pincfg[pin].input_enable == true) + { + if (en) + { + /* enable interrupt */ + + cxd56_gpioint_enable(pincfg[pin].pin); + } + else + { + /* disable interrupt */ + + cxd56_gpioint_disable(pincfg[pin].pin); + } + } + } +} + +#endif diff --git a/boards/arm/cxd56xx/common/src/cxd56_altmdm_spi.c b/boards/arm/cxd56xx/common/src/cxd56_altmdm_spi.c new file mode 100644 index 0000000000..a5b7b2e041 --- /dev/null +++ b/boards/arm/cxd56xx/common/src/cxd56_altmdm_spi.c @@ -0,0 +1,255 @@ +/**************************************************************************** + * boards/arm/cxd56xx/common/src/cxd56_altmdm_spi.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 + +#if defined(CONFIG_CXD56_SPI) && defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_LTE) + +#include +#include +#include + +#include +#include +#include +#include +#include "cxd56_spi.h" +#include "cxd56_pinconfig.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_CXD56_LTE_SPI4) +#define SPI_CH (4) +#if defined(CONFIG_CXD56_LTE_SPI4_DMAC) +# if defined(CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE) +# if (CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE > CONFIG_CXD56_DMAC_SPI4_TX_MAXSIZE) +# error CONFIG_CXD56_DMAC_SPI4_TX_MAXSIZE too small +# endif +# if (CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE > CONFIG_CXD56_DMAC_SPI4_RX_MAXSIZE) +# error CONFIG_CXD56_DMAC_SPI4_RX_MAXSIZE too small +# endif +# endif +#endif +#elif defined(CONFIG_CXD56_LTE_SPI5) +#define SPI_CH (5) +#if defined(CONFIG_CXD56_LTE_SPI5_DMAC) +# if defined(CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE) +# if (CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE > CONFIG_CXD56_DMAC_SPI5_TX_MAXSIZE) +# error CONFIG_CXD56_DMAC_SPI5_TX_MAXSIZE too small +# endif +# if (CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE > CONFIG_CXD56_DMAC_SPI5_RX_MAXSIZE) +# error CONFIG_CXD56_DMAC_SPI5_RX_MAXSIZE too small +# endif +# endif +#endif +#else +#error "Select LTE SPI 4 or 5" +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static void *g_devhandle = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spi_pincontrol + * + * Description: + * Configure the SPI pin + * + * Input Parameter: + * on - true: enable pin, false: disable pin + * + ****************************************************************************/ + +static void spi_pincontrol(int bus, bool on) +{ + switch (bus) + { +#ifdef CONFIG_CXD56_SPI4 + case 4: + if (on) + { + CXD56_PIN_CONFIGS(PINCONFS_SPI4); + } + else + { + CXD56_PIN_CONFIGS(PINCONFS_SPI4_GPIO); + } + break; +#endif /* CONFIG_CXD56_SPI4 */ + +#ifdef CONFIG_CXD56_SPI5 + case 5: +#ifdef CONFIG_CXD56_SPI5_PINMAP_EMMC + if (on) + { + CXD56_PIN_CONFIGS(PINCONFS_EMMCA_SPI5); + } + else + { + CXD56_PIN_CONFIGS(PINCONFS_EMMCA_GPIO); + } +#endif /* CONFIG_CXD56_SPI5_PINMAP_EMMC */ +#ifdef CONFIG_CXD56_SPI5_PINMAP_SDIO + if (on) + { + CXD56_PIN_CONFIGS(PINCONFS_SDIOA_SPI5); + } + else + { + CXD56_PIN_CONFIGS(PINCONFS_SDIOA_GPIO); + } +#endif /* CONFIG_CXD56_SPI5_PINMAP_SDIO */ + break; +#endif /* CONFIG_CXD56_SPI5 */ + default: + break; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_altmdm_initialize + * + * Description: + * Initialize Altair modem + * + ****************************************************************************/ + +int board_altmdm_initialize(FAR const char *devpath) +{ + FAR struct spi_dev_s *spi; + int spi_ch = SPI_CH; + + m_info("Initializing ALTMDM..\n"); + + if (!g_devhandle) + { + /* Initialize spi deivce */ + + spi = cxd56_spibus_initialize(spi_ch); + if (!spi) + { + m_err("ERROR: Failed to initialize spi%d.\n", spi_ch); + return -ENODEV; + } + + spi_pincontrol(spi_ch, false); + + g_devhandle = altmdm_register(devpath, spi); + if (!g_devhandle) + { + m_err("ERROR: Failed to register altmdm driver.\n"); + return -ENODEV; + } + + board_altmdm_poweroff(); + } + + return OK; +} + +/**************************************************************************** + * Name: board_altmdm_uninitialize + * + * Description: + * Uninitialize Altair modem + * + ****************************************************************************/ + +int board_altmdm_uninitialize(void) +{ + m_info("Uninitializing ALTMDM..\n"); + + if (g_devhandle) + { + altmdm_unregister(g_devhandle); + + g_devhandle = NULL; + } + + return OK; +} + +/**************************************************************************** + * Name: board_altmdm_power_control + * + * Description: + * Power on/off the Altair modem device on the board. + * + ****************************************************************************/ + +void board_altmdm_power_control(bool en) +{ + int spi_ch = SPI_CH; + + if (en) + { + /* power on altair modem device */ + + board_altmdm_poweron(); + + /* enable the SPI pin */ + + spi_pincontrol(spi_ch, true); + } + else + { + /* disable the SPI pin */ + + spi_pincontrol(spi_ch, false); + + /* power off Altair modem device */ + + board_altmdm_poweroff(); + } +} + +#endif /* CONFIG_CXD56_SPI && CONFIG_MODEM_ALTMDM */ diff --git a/boards/arm/cxd56xx/spresense/Kconfig b/boards/arm/cxd56xx/spresense/Kconfig index a178b9a1e7..e535cec0d0 100644 --- a/boards/arm/cxd56xx/spresense/Kconfig +++ b/boards/arm/cxd56xx/spresense/Kconfig @@ -68,4 +68,47 @@ config LCD_ON_MAIN_BOARD endchoice endif +comment "LTE Options" + +menuconfig CXD56_LTE + bool "LTE" + default n + +if CXD56_LTE + +choice + prompt "LTE SPI selection" + default CXD56_LTE_SPI4 + +config CXD56_LTE_SPI4 + bool "Use SPI4" + select CXD56_SPI4 + +config CXD56_LTE_SPI5 + bool "Use SPI5" + select CXD56_SPI5 +endchoice + +if CXD56_LTE_SPI4 + +config CXD56_LTE_SPI4_DMAC + bool "Use DMAC for SPI4" + default y + select CXD56_DMAC_SPI4_TX + select CXD56_DMAC_SPI4_RX + +endif # CXD56_LTE_SPI4 + +if CXD56_LTE_SPI5 + +config CXD56_LTE_SPI5_DMAC + bool "Use DMAC for SPI5" + default y + select CXD56_DMAC_SPI5_TX + select CXD56_DMAC_SPI5_RX + +endif # CXD56_LTE_SPI4 + +endif # CXD56_LTE + endif diff --git a/boards/arm/cxd56xx/spresense/configs/lte/defconfig b/boards/arm/cxd56xx/spresense/configs/lte/defconfig new file mode 100644 index 0000000000..4c12df3e87 --- /dev/null +++ b/boards/arm/cxd56xx/spresense/configs/lte/defconfig @@ -0,0 +1,88 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_CXD56_I2C0_SCUSEQ is not set +# CONFIG_MMCSD_HAVE_WRITEPROTECT is not set +# CONFIG_MMCSD_SPI is not set +# CONFIG_MTD_SMART_WEAR_LEVEL is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="spresense" +CONFIG_ARCH_BOARD_SPRESENSE=y +CONFIG_ARCH_CHIP="cxd56xx" +CONFIG_ARCH_CHIP_CXD56XX=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_USEBASEPRI=y +CONFIG_BOARD_LOOPSPERMSEC=5434 +CONFIG_BOOT_RUNFROMISRAM=y +CONFIG_BUILTIN=y +CONFIG_CLOCK_MONOTONIC=y +CONFIG_CXD56_BINARY=y +CONFIG_CXD56_I2C0=y +CONFIG_CXD56_I2C=y +CONFIG_CXD56_LTE=y +CONFIG_CXD56_SDIO=y +CONFIG_CXD56_SPI5=y +CONFIG_CXD56_SPI=y +CONFIG_CXD56_USBDEV=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FAT_MAXFNAME=64 +CONFIG_FS_FAT=y +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y +CONFIG_FS_SMARTFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_I2C=y +CONFIG_MAX_TASKS=16 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_MMCSD=y +CONFIG_MMCSD_SDIO=y +CONFIG_MODEM=y +CONFIG_MTD_BYTE_WRITE=y +CONFIG_MTD_PARTITION=y +CONFIG_MTD_SMART=y +CONFIG_MTD_SMART_ENABLE_CRC=y +CONFIG_MTD_SMART_SECTOR_SIZE=4096 +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PREALLOC_WDOGS=16 +CONFIG_RAM_SIZE=1572864 +CONFIG_RAM_START=0x0d000000 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_RTC=y +CONFIG_RTC_DRIVER=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SMARTFS_ALIGNED_ACCESS=y +CONFIG_SMARTFS_MAXNAMLEN=30 +CONFIG_SMARTFS_MULTI_ROOT_DIRS=y +CONFIG_SPI=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_SYSTEM_CLE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_CXXINITIALIZE=y +CONFIG_SYSTEM_USBMSC=y +CONFIG_UART1_SERIAL_CONSOLE=y +CONFIG_USBDEV=y +CONFIG_USBDEV_DMA=y +CONFIG_USBDEV_DUALSPEED=y +CONFIG_USBMSC=y +CONFIG_USBMSC_EPBULKIN=1 +CONFIG_USBMSC_REMOVABLE=y +CONFIG_USER_ENTRYPOINT="spresense_main" diff --git a/boards/arm/cxd56xx/spresense/include/board.h b/boards/arm/cxd56xx/spresense/include/board.h index e5630eba71..a1df198423 100644 --- a/boards/arm/cxd56xx/spresense/include/board.h +++ b/boards/arm/cxd56xx/spresense/include/board.h @@ -57,6 +57,7 @@ #include "cxd56_gpioif.h" #include "cxd56_audio.h" +#include "cxd56_altmdm.h" #include "cxd56_ak09912.h" #include "cxd56_apds9930.h" #include "cxd56_apds9960.h" diff --git a/boards/arm/cxd56xx/spresense/include/cxd56_altmdm.h b/boards/arm/cxd56xx/spresense/include/cxd56_altmdm.h new file mode 100644 index 0000000000..fe1b3522b4 --- /dev/null +++ b/boards/arm/cxd56xx/spresense/include/cxd56_altmdm.h @@ -0,0 +1,201 @@ +/**************************************************************************** + * boards/arm/cxd56xx/spresense/include/cxd56_altmdm.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __BOARDS_ARM_CXD56XX_SPRESENSE_INCLUDE_CXD56_ALTMDM_H +#define __BOARDS_ARM_CXD56XX_SPRESENSE_INCLUDE_CXD56_ALTMDM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Altair modem gpio definitions *******************************************/ + +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) + +/* definitions of gpio pin number */ + +#define ALTMDM_GPIO_MODEM_WAKEUP (0) +#define ALTMDM_GPIO_MASTER_REQ (1) +#define ALTMDM_GPIO_SLAVE_REQ (2) + +/* definitions of gpio interrupt polarity */ + +#define ALTMDM_GPIOINT_LEVEL_HIGH (0) +#define ALTMDM_GPIOINT_LEVEL_LOW (1) +#define ALTMDM_GPIOINT_EDGE_RISE (2) +#define ALTMDM_GPIOINT_EDGE_FALL (3) +#define ALTMDM_GPIOINT_EDGE_BOTH (4) + +/* definitions of gpio interrupt noise filter */ + +#define ALTMDM_GPIOINT_NOISE_FILTER_ENABLE (0) +#define ALTMDM_GPIOINT_NOISE_FILTER_DISABLE (1) + +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#if defined(CONFIG_MODEM_ALTMDM) && defined(CONFIG_CXD56_GPIO_IRQ) + +/**************************************************************************** + * Name: board_altmdm_initialize + * + * Description: + * Initialize Altair modem + * + ****************************************************************************/ + +int board_altmdm_initialize(FAR const char *devpath); + +/**************************************************************************** + * Name: board_altmdm_uninitialize + * + * Description: + * Uninitialize Altair modem + * + ****************************************************************************/ + +int board_altmdm_uninitialize(void); + +/**************************************************************************** + * Name: board_altmdm_power_control + * + * Description: + * Power on/off the Altair modem device on the board. + * + ****************************************************************************/ + +void board_altmdm_power_control(bool en); + +/**************************************************************************** + * Name: board_altmdm_poweron + * + * Description: + * Power on the Altair modem device on the board. + * + ****************************************************************************/ + +void board_altmdm_poweron(void); + +/**************************************************************************** + * Name: board_altmdm_poweroff + * + * Description: + * Power off the Altair modem device on the board. + * + ****************************************************************************/ + +void board_altmdm_poweroff(void); + +/**************************************************************************** + * Name: board_altmdm_gpio_write + * + * Description: + * Write GPIO pin. + * + ****************************************************************************/ + +void board_altmdm_gpio_write(uint32_t pin, bool value); + +/**************************************************************************** + * Name: board_altmdm_gpio_read + * + * Description: + * Read GPIO pin. + * + ****************************************************************************/ + +bool board_altmdm_gpio_read(uint32_t pin); + +/**************************************************************************** + * Name: board_altmdm_gpio_irq + * + * Description: + * Register GPIO irq. + * + ****************************************************************************/ + +void board_altmdm_gpio_irq(uint32_t pin, uint32_t polarity, + uint32_t noise_filter, xcpt_t irqhandler); + +/**************************************************************************** + * Name: board_altmdm_gpio_int_control + * + * Description: + * Enable or disable GPIO interrupt. + * + ****************************************************************************/ + +void board_altmdm_gpio_int_control(uint32_t pin, bool en); + +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_CXD56XX_SPRESENSE_INCLUDE_CXD56_ALTMDM_H */ diff --git a/boards/arm/cxd56xx/spresense/src/cxd56_bringup.c b/boards/arm/cxd56xx/spresense/src/cxd56_bringup.c index 8b2052a20a..f6fe5360b3 100644 --- a/boards/arm/cxd56xx/spresense/src/cxd56_bringup.c +++ b/boards/arm/cxd56xx/spresense/src/cxd56_bringup.c @@ -389,6 +389,14 @@ int cxd56_bringup(void) usbdev_rndis_initialize(mac); #endif +#ifdef CONFIG_MODEM_ALTMDM + ret = board_altmdm_initialize("/dev/altmdm"); + if (ret < 0) + { + _err("ERROR: Failed to initialze Altair modem. \n"); + } +#endif + #ifdef CONFIG_WL_GS2200M ret = board_gs2200m_initialize("/dev/gs2200m", 5); if (ret < 0) diff --git a/drivers/modem/Kconfig b/drivers/modem/Kconfig index bfc7568612..0f2cc66d24 100644 --- a/drivers/modem/Kconfig +++ b/drivers/modem/Kconfig @@ -18,3 +18,5 @@ config MODEM_U_BLOX_DEBUG ---help--- Allow the u-blox modem driver print debug information. + +source "drivers/modem/altair/Kconfig" diff --git a/drivers/modem/Make.defs b/drivers/modem/Make.defs index 6916f46fa2..3b406f63a7 100644 --- a/drivers/modem/Make.defs +++ b/drivers/modem/Make.defs @@ -39,6 +39,8 @@ ifeq ($(CONFIG_MODEM_U_BLOX),y) CSRCS += u-blox.c endif +include modem$(DELIM)altair$(DELIM)Make.defs + # Include modem driver build support DEPPATH += --dep-path modem diff --git a/drivers/modem/altair/Kconfig b/drivers/modem/altair/Kconfig new file mode 100644 index 0000000000..9f1533136f --- /dev/null +++ b/drivers/modem/altair/Kconfig @@ -0,0 +1,52 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig MODEM_ALTMDM + bool "Altair modem support" + default y + ---help--- + Enable driver for the Altair modem. + +if MODEM_ALTMDM + +config MODEM_ALTMDM_PROTCOL_V2_1 + bool "Enable SPI protocol version 2.1" + default y + depends on MODEM_ALTMDM + ---help--- + Support only this version. + +config MODEM_ALTMDM_DEBUG + bool "Enable debug mode for Altair modem driver" + default n + depends on MODEM_ALTMDM + ---help--- + Allow the Altair modem driver print debug information. + +config MODEM_ALTMDM_KEEP_WAKE_STATE + bool "Configuration to keep wake state of modem" + default n + depends on MODEM_ALTMDM + ---help--- + none + +config MODEM_ALTMDM_MAX_PACKET_SIZE + int "Max size to be transfer in bytes" + default 2064 + depends on MODEM_ALTMDM + ---help--- + none + +config MODEM_ALTMDM_SLEEP_TIMER_VAL + int "Modem sleep timer" + default 20 + depends on MODEM_ALTMDM + ---help--- + Modem sleep timer in milliseconds. + Modem may sleep if there is no data to be transferred + during specified time. Values smaller than 20 milliseconds + can not be specified. + +endif diff --git a/drivers/modem/altair/Make.defs b/drivers/modem/altair/Make.defs new file mode 100644 index 0000000000..d24feb638d --- /dev/null +++ b/drivers/modem/altair/Make.defs @@ -0,0 +1,50 @@ +############################################################################ +# lte/drivers/Make.defs +# +# Copyright 2018 Sony Semiconductor Solutions Corporation +# +# 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 of Sony Semiconductor Solutions Corporation 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. +# +############################################################################ + +ifeq ($(CONFIG_MODEM),y) + +ifeq ($(CONFIG_MODEM_ALTMDM),y) +CSRCS += altmdm.c +CSRCS += altmdm_spi.c +CSRCS += altmdm_pm.c +CSRCS += altmdm_pm_state.c +CSRCS += altmdm_sys.c +endif + +DEPPATH += --dep-path modem$(DELIM)altair +VPATH += :modem$(DELIM)altair +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)modem} + +endif diff --git a/drivers/modem/altair/altmdm.c b/drivers/modem/altair/altmdm.c new file mode 100644 index 0000000000..c9483f8c8a --- /dev/null +++ b/drivers/modem/altair/altmdm.c @@ -0,0 +1,463 @@ +/**************************************************************************** + * drivers/modem/altair/altmdm.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 "altmdm_dev.h" +#include "altmdm_spi.h" +#include "altmdm_pm.h" +#include "altmdm_sys.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Character driver methods. */ + +static int altmdm_open(FAR struct file *filep); +static int altmdm_close(FAR struct file *filep); +static ssize_t altmdm_read(FAR struct file *filep, FAR char *buffer, + size_t len); +static ssize_t altmdm_write(FAR struct file *filep, FAR const char *buffer, + size_t len); +static int altmdm_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This the vtable that supports the character driver interface. */ + +static const struct file_operations g_altmdmfops = +{ + altmdm_open, /* open */ + altmdm_close, /* close */ + altmdm_read, /* read */ + altmdm_write, /* write */ + 0, /* seek */ + altmdm_ioctl, /* ioctl */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: is_poweron + * + * Description: + * Check ALTMDM power on. + * + ****************************************************************************/ + +static int is_poweron(FAR struct altmdm_dev_s *priv) +{ + int poweron; + + altmdm_sys_lock(&priv->lock); + + poweron = priv->poweron; + + altmdm_sys_unlock(&priv->lock); + + return poweron; +} + +/**************************************************************************** + * Name: altmdm_initialize + * + * Description: + * Initialize ALTMDM driver. + * + ****************************************************************************/ + +static int altmdm_initialize(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_initlock(&priv->lock); + if (ret == ERROR) + { + m_err("altmdm_sys_initlock() failed:%d\n", ret); + } + + priv->poweron = 0; + + /* Intialize ALTMDM SPI driver. */ + + ret = altmdm_spi_init(priv); + + return ret; +} + +/**************************************************************************** + * Name: altmdm_uninitialize + * + * Description: + * Uninitialize ALTMDM driver. + * + ****************************************************************************/ + +static int altmdm_uninitialize(FAR struct altmdm_dev_s *priv) +{ + int ret; + + /* Unintialize ALTMDM SPI driver */ + + altmdm_spi_uninit(priv); + + ret = altmdm_sys_deletelock(&priv->lock); + if (ret == ERROR) + { + m_err("altmdm_sys_deletelock() failed:%d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_open + * + * Description: + * Standard character driver open method. + * + ****************************************************************************/ + +static int altmdm_open(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: altmdm_close + * + * Description: + * Standard character driver close method. + * + ****************************************************************************/ + +static int altmdm_close(FAR struct file *filep) +{ + return OK; +} + +/**************************************************************************** + * Name: altmdm_read + * + * Description: + * Standard character driver read method. + * + ****************************************************************************/ + +static ssize_t altmdm_read(FAR struct file *filep, + FAR char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct altmdm_dev_s *priv = inode->i_private; + ssize_t rsize = -EPERM; + + rsize = altmdm_spi_read(priv, buffer, len); + + return rsize; +} + +/**************************************************************************** + * Name: altmdm_write + * + * Description: + * Standard character driver write method. + * + ****************************************************************************/ + +static ssize_t altmdm_write(FAR struct file *filep, FAR const char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct altmdm_dev_s *priv = inode->i_private; + ssize_t wsize = -EPERM; + + if (is_poweron(priv)) + { + wsize = altmdm_spi_write(priv, buffer, len); + } + + return wsize; +} + +/**************************************************************************** + * Name: altmdm_ioctl + * + * Description: + * Standard character driver ioctl method. + * + ****************************************************************************/ + +static int altmdm_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct altmdm_dev_s *priv = inode->i_private; + int ret = -EPERM; + + switch (cmd) + { + case MODEM_IOC_POWERON: /* Power on ALTMDM. */ + { + altmdm_sys_lock(&priv->lock); + + if (!priv->poweron) + { + altmdm_pm_poweron(priv); + + priv->poweron = 1; + + ret = altmdm_spi_enable(priv); + } + else + { + ret = -EBUSY; + } + + altmdm_sys_unlock(&priv->lock); + } + break; + + case MODEM_IOC_POWEROFF: /* Power off ALTMDM. */ + { + altmdm_sys_lock(&priv->lock); + + if (priv->poweron) + { + ret = altmdm_spi_disable(priv); + + altmdm_pm_poweroff(priv); + + priv->poweron = 0; + } + else + { + ret = -EBUSY; + } + + altmdm_sys_unlock(&priv->lock); + } + break; + + case MODEM_IOC_READABORT: /* Abort the read process. */ + { + ret = altmdm_spi_readabort(priv); + } + break; + + case MODEM_IOC_SLEEP: /* Make ALTMDM sleep. */ + { + if (is_poweron(priv)) + { + ret = altmdm_spi_sleepmodem(priv); + } + } + break; + + case MODEM_IOC_PM_REGISTERCB: /* Register callback function. */ + { + ret = altmdm_pm_registercb(MODEM_PM_CB_TYPE_NORMAL, + (altmdm_pm_cbfunc_t) arg); + } + break; + + case MODEM_IOC_PM_DEREGISTERCB: /* Deregister callback function. */ + { + ret = altmdm_pm_deregistercb(MODEM_PM_CB_TYPE_NORMAL); + } + break; + + case MODEM_IOC_PM_ERR_REGISTERCB: /* Register error callback function. */ + { + ret = altmdm_pm_registercb(MODEM_PM_CB_TYPE_ERROR, + (altmdm_pm_cbfunc_t) arg); + } + break; + + case MODEM_IOC_PM_ERR_DEREGISTERCB: /* Deregister error callback + function. + */ + { + ret = altmdm_pm_deregistercb(MODEM_PM_CB_TYPE_ERROR); + } + break; + + case MODEM_IOC_PM_GETSTATE: /* Get ALTMDM power management state. */ + { + *(uint32_t *) arg = altmdm_pm_getstate(); + ret = 0; + } + break; + + case MODEM_IOC_PM_INITWAKELOCK: /* Initialze wakelock resource. */ + { + ret = altmdm_pm_initwakelock((struct altmdm_pm_wakelock_s *)arg); + } + break; + + case MODEM_IOC_PM_ACQUIREWAKELOCK: /* Acquire wakelock. */ + { + ret = altmdm_pm_acquirewakelock((struct altmdm_pm_wakelock_s *)arg); + } + break; + + case MODEM_IOC_PM_RELEASEWAKELOCK: /* Release wakelock. */ + { + ret = altmdm_pm_releasewakelock((struct altmdm_pm_wakelock_s *)arg); + } + break; + + case MODEM_IOC_PM_GETNUMOFWAKELOCK: /* Get number of wakelocks. */ + { + ret = altmdm_pm_getnumofwakelock((struct altmdm_pm_wakelock_s *)arg); + } + break; + + case MODEM_IOC_PM_GETWAKELOCKSTATE: /* Get wakelock state. */ + { + ret = altmdm_pm_getwakelockstate(); + } + break; + + default: + m_err("Unrecognized cmd: 0x%08x\n", cmd); + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_register + * + * Description: + * Register the ALTMDM character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/altmdm". + * dev - An instance of the SPI interface to use to communicate with + * ALTMDM. + * + * Returned Value: + * Not NULL on success; NULL on failure. + * + ****************************************************************************/ + +FAR void *altmdm_register(FAR const char *devpath, FAR struct spi_dev_s *dev) +{ + FAR struct altmdm_dev_s *priv; + int ret; + int size = sizeof(struct altmdm_dev_s); + + priv = (FAR struct altmdm_dev_s *)kmm_malloc(size); + if (!priv) + { + m_err("Failed to allocate instance.\n"); + return NULL; + } + + priv->spi = dev; + priv->path = strdup(devpath); + + ret = altmdm_initialize(priv); + if (ret < 0) + { + m_err("Failed to initialize ALTMDM driver.\n"); + kmm_free(priv); + return NULL; + } + + ret = register_driver(devpath, &g_altmdmfops, 0666, priv); + if (ret < 0) + { + m_err("Failed to register driver: %d\n", ret); + kmm_free(priv); + return NULL; + } + + return (FAR void *)priv; +} + +/**************************************************************************** + * Name: altmdm_unregister + * + * Description: + * Unregister the ALTMDM character device. + * + * Input Parameters: + * handle - The pointer that getting from altmdm_register. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void altmdm_unregister(FAR void *handle) +{ + FAR struct altmdm_dev_s *priv; + + if (handle) + { + priv = (FAR struct altmdm_dev_s *)handle; + + altmdm_uninitialize(priv); + + (void)unregister_driver(priv->path); + + kmm_free(priv->path); + kmm_free(priv); + } +} + +#endif diff --git a/drivers/modem/altair/altmdm_dev.h b/drivers/modem/altair/altmdm_dev.h new file mode 100644 index 0000000000..fc99c822aa --- /dev/null +++ b/drivers/modem/altair/altmdm_dev.h @@ -0,0 +1,194 @@ +/**************************************************************************** + * drivers/modem/altair/altmdm_dev.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __DRIVERS_MODEM_ALTAIR_ALTMDM_DEV_H +#define __DRIVERS_MODEM_ALTAIR_ALTMDM_DEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +# include + +# include "altmdm_spi.h" +# include "altmdm_sys.h" + +# if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct altmdm_dev_s + { + FAR char *path; /* Registration path */ + FAR struct spi_dev_s *spi; + struct altmdm_spi_dev_s spidev; + struct altmdm_sys_lock_s lock; + int poweron; + }; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_spi_init + * + * Description: + * Initialize ALTMDM driver. + * + ****************************************************************************/ + +int altmdm_spi_init(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_uninit + * + * Description: + * Uninitialize ALTMDM driver. + * + ****************************************************************************/ + +int altmdm_spi_uninit(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_enable + * + * Description: + * Enable ALTMDM SPI driver. + * + ****************************************************************************/ + +int altmdm_spi_enable(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_disable + * + * Description: + * Disable ALTMDM SPI driver. + * + ****************************************************************************/ + +int altmdm_spi_disable(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_read + * + * Description: + * ALTMDM SPI driver read method. + * + ****************************************************************************/ + +ssize_t altmdm_spi_read(FAR struct altmdm_dev_s *priv, + FAR const char *buffer, size_t readlen); + +/**************************************************************************** + * Name: altmdm_spi_write + * + * Description: + * ALTMDM SPI driver write method. + * + ****************************************************************************/ + +ssize_t altmdm_spi_write(FAR struct altmdm_dev_s *priv, + FAR const char *buffer, size_t witelen); + +/**************************************************************************** + * Name: altmdm_spi_readabort + * + * Description: + * Abort the read process. + * + ****************************************************************************/ + +int altmdm_spi_readabort(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_sleepmodem + * + * Description: + * Make ALTMDM sleep. + * + ****************************************************************************/ + +int altmdm_spi_sleepmodem(FAR struct altmdm_dev_s *priv); + +#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + +/**************************************************************************** + * Name: altmdm_spi_setreceiverready + * + * Description: + * Set receiver ready notification. + * + ****************************************************************************/ + +int altmdm_spi_setreceiverready(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_isreceiverready + * + * Description: + * Check already notified or not by altmdm_spi_setreceiverready. + * + ****************************************************************************/ + +int altmdm_spi_isreceiverready(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_spi_clearreceiverready + * + * Description: + * Clear receiver ready notification. + * + ****************************************************************************/ + +int altmdm_spi_clearreceiverready(FAR struct altmdm_dev_s *priv); + +#endif + +/**************************************************************************** + * Name: altmdm_spi_gpioreadyisr + * + * Description: + * Interrupt handler for SLAVE_REQUEST GPIO line. + * + ****************************************************************************/ + +int altmdm_spi_gpioreadyisr(int irq, FAR void *context, FAR void *arg); + +#endif +#endif /* __DRIVERS_MODEM_ALTAIR_ALTMDM_DEV_H */ \ No newline at end of file diff --git a/drivers/modem/altair/altmdm_pm.c b/drivers/modem/altair/altmdm_pm.c new file mode 100644 index 0000000000..9467345ff4 --- /dev/null +++ b/drivers/modem/altair/altmdm_pm.c @@ -0,0 +1,1771 @@ +/**************************************************************************** + * drivers/modem/altair/altmdm_pm.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 "altmdm_sys.h" +#include "altmdm_pm.h" +#include "altmdm_pm_state.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +# define EVENT_BIT(b) (1<<(b)) +# define EVENT_NONE (0) +# define EVENT_D2H_DOWN EVENT_BIT(0) +# define EVENT_D2H_UP EVENT_BIT(1) +# define EVENT_MODEM_SLEPT_NOTIF EVENT_BIT(2) +# define EVENT_MODEM_WAKEUP_NOTIF EVENT_BIT(3) +# define EVENT_MODEM_GOING_TO_SLEEP_NOTIF EVENT_BIT(4) +# define EVENT_MODEM_WAKEUP_REQ EVENT_BIT(5) +# define EVENT_MODEM_SLEEP_REQ EVENT_BIT(6) +# define EVENT_EXIT EVENT_BIT(7) +# define EVENT_MODEM_RESET_NOTIF EVENT_BIT(8) +# define EVENT_MODEM_POWERON_REQ EVENT_BIT(9) +# define EVENT_MODEM_POWEROFF_REQ EVENT_BIT(10) +# define EVENT_PM_TASK_WAIT (EVENT_D2H_DOWN | EVENT_D2H_UP | \ + EVENT_MODEM_WAKEUP_REQ | \ + EVENT_MODEM_RESET_NOTIF | \ + EVENT_MODEM_POWERON_REQ | \ + EVENT_MODEM_POWEROFF_REQ | \ + EVENT_MODEM_SLEEP_REQ | EVENT_EXIT) +# define EVENT_STATE_CHG_WAIT (EVENT_MODEM_SLEPT_NOTIF | \ + EVENT_MODEM_GOING_TO_SLEEP_NOTIF | \ + EVENT_MODEM_WAKEUP_NOTIF) +# define EVENT_MODEM_SLEEP_REQ_DONE_OK EVENT_BIT(0) +# define EVENT_MODEM_SLEEP_REQ_DONE_NG EVENT_BIT(1) +# define EVENT_MODEM_SLEEP_REQ_DONE (EVENT_MODEM_SLEEP_REQ_DONE_OK | \ + EVENT_MODEM_SLEEP_REQ_DONE_NG) +# define EVENT_MODEM_WAKEUP_REQ_DONE_OK EVENT_BIT(0) +# define EVENT_MODEM_WAKEUP_REQ_DONE_NG EVENT_BIT(1) +# define EVENT_MODEM_WAKEUP_REQ_DONE (EVENT_MODEM_WAKEUP_REQ_DONE_OK | \ + EVENT_MODEM_WAKEUP_REQ_DONE_NG) +# define EVENT_MODEM_POWER_ON_DONE EVENT_BIT(0) +# define EVENT_MODEM_POWER_OFF_DONE EVENT_BIT(1) + +/* Timeout is counted in units of millisecond. */ + +# define D2H_UP_EVENT_TIMEOUT (5*1000) +# define ST_TRANS_EVENT_TIMEOUT (ALTMDM_SYS_FLAG_TMOFEVR) + +# define PM_TASK_PRI (90) +# define PM_TASK_NAME "altmdm_pm_task" +# define PM_TASK_STKSIZE (1024) + +# define GPIO_LOW (false) +# define GPIO_HIGH (true) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct altmdm_dev_s *g_privdata = NULL; +static struct altmdm_sys_flag_s g_statetrans_flag; +static struct altmdm_sys_flag_s g_pmtask_flag; +static struct altmdm_sys_flag_s g_wakeup_done_flag; +static struct altmdm_sys_flag_s g_sleep_done_flag; +static struct altmdm_sys_flag_s g_power_done_flag; +static bool g_is_initdone = false; +static bool g_is_waitnotif = false; +static bool g_is_notrun; +static int g_taskid; +static altmdm_pm_cbfunc_t g_pm_callback = NULL; +static altmdm_pm_cbfunc_t g_pm_errcallback = NULL; +static sq_queue_t g_wakelock; +static uint32_t g_boot_stat = MODEM_PM_ERR_RESET_BOOTSTAT_NONE; + +/**************************************************************************** + * Name: init_h2d_gpio + * + * Description: + * Initialize Host to Device GPIO line. + * + ****************************************************************************/ + +static int init_h2d_gpio(FAR struct altmdm_dev_s *priv) +{ + return 0; +} + +/**************************************************************************** + * Name: uninit_h2d_gpio + * + * Description: + * Uninitialize Host to Device GPIO line. + * + ****************************************************************************/ + +static int uninit_h2d_gpio(FAR struct altmdm_dev_s *priv) +{ + return 0; +} + +/**************************************************************************** + * Name: init_d2h_gpio + * + * Description: + * Initialize Device to Host GPIO line. + * + ****************************************************************************/ + +static int init_d2h_gpio(FAR struct altmdm_dev_s *priv) +{ + return 0; +} + +/**************************************************************************** + * Name: uninit_d2h_gpio + * + * Description: + * Uninitialize Device to Host GPIO line. + * + ****************************************************************************/ + +static int uninit_d2h_gpio(FAR struct altmdm_dev_s *priv) +{ + return 0; +} + +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + +/**************************************************************************** + * Name: set_mreq_gpio + * + * Description: + * Control Master-request GPIO line. + * + ****************************************************************************/ + +static int set_mreq_gpio(FAR struct altmdm_dev_s *priv, bool value) +{ + return 0; +} +# endif + +/**************************************************************************** + * Name: set_h2d_gpio + * + * Description: + * Control Host to Device GPIO line. + * + ****************************************************************************/ + +static int set_h2d_gpio(FAR struct altmdm_dev_s *priv, bool value) +{ + return 0; +} + +/**************************************************************************** + * Name: get_d2h_gpio + * + * Description: + * Get current value of Device to Host GPIO line. + * + ****************************************************************************/ + +static int get_d2h_gpio(FAR struct altmdm_dev_s *priv, FAR bool * value) +{ + return 0; +} + +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + +/**************************************************************************** + * Name: set_mreq_down + * + * Description: + * Deassert Master-request GPIO line. + * + ****************************************************************************/ + +static int set_mreq_down(FAR struct altmdm_dev_s *priv) +{ + return set_mreq_gpio(priv, GPIO_LOW); +} + +/**************************************************************************** + * Name: set_mreq_up + * + * Description: + * Assert Master-request GPIO line. + * + ****************************************************************************/ + +static int set_mreq_up(FAR struct altmdm_dev_s *priv) +{ + return set_mreq_gpio(priv, GPIO_HIGH); +} +# endif + +/**************************************************************************** + * Name: set_h2d_down + * + * Description: + * Deassert Host to Device GPIO line. + * + ****************************************************************************/ + +static int set_h2d_down(FAR struct altmdm_dev_s *priv) +{ + return set_h2d_gpio(priv, GPIO_LOW); +} + +/**************************************************************************** + * Name: set_h2d_up + * + * Description: + * Assert Host to Device GPIO line. + * + ****************************************************************************/ + +static int set_h2d_up(FAR struct altmdm_dev_s *priv) +{ + return set_h2d_gpio(priv, GPIO_HIGH); +} + +/**************************************************************************** + * Name: send_d2h_down_notif + * + * Description: + * Notify that Device to Host GPIO line has been deassertted. + * + ****************************************************************************/ + +static int send_d2h_down_notif(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_D2H_DOWN); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_d2h_up_notif + * + * Description: + * Notify that Device to Host GPIO line has been assertted. + * + ****************************************************************************/ + +static int send_d2h_up_notif(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + uint32_t pm_state; + + pm_state = altmdm_pm_getinternalstate(); + if ((pm_state == MODEM_PM_INTERNAL_STATE_SLEEP) || + (pm_state == MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE)) + { + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_D2H_UP); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_slept_notif + * + * Description: + * Notify that the modem slept. + * + ****************************************************************************/ + +static int send_modem_slept_notif(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + + if (g_is_waitnotif) + { + /* Send only when waiting for notification. */ + + ret = altmdm_sys_setflag(&g_statetrans_flag, EVENT_MODEM_SLEPT_NOTIF); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_wakeup_notif + * + * Description: + * Notify that the modem has woken up. + * + ****************************************************************************/ + +static int send_modem_wakeup_notif(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + + if (g_is_waitnotif) + { + /* Send only when waiting for notification. */ + + ret = altmdm_sys_setflag(&g_statetrans_flag, EVENT_MODEM_WAKEUP_NOTIF); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + } +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + else + { + altmdm_spi_setreceiverready(priv); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: send_modem_reset_notif + * + * Description: + * Notify that the modem is reset. + * + ****************************************************************************/ + +static int send_modem_reset_notif(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_MODEM_RESET_NOTIF); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_wakeup_request + * + * Description: + * Send request to wake up the modem. + * + ****************************************************************************/ + +static int send_modem_wakeup_request(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_MODEM_WAKEUP_REQ); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_sleep_request + * + * Description: + * Send request to sleep the modem. + * + ****************************************************************************/ + +static int send_modem_sleep_request(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_MODEM_SLEEP_REQ); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_exit_request + * + * Description: + * Send request to terminate the power management task. + * + ****************************************************************************/ + +static int send_exit_request(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_EXIT); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_poweron_request + * + * Description: + * Send request to power on the modem. + * + ****************************************************************************/ + +static int send_modem_poweron_request(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_MODEM_POWERON_REQ); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_poweroff_request + * + * Description: + * Send request to power off the modem. + * + ****************************************************************************/ + +static int send_modem_poweroff_request(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_pmtask_flag, EVENT_MODEM_POWEROFF_REQ); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_wakeup_done + * + * Description: + * Notify that the wake up of the modem is complete. + * + ****************************************************************************/ + +static int send_modem_wakeup_done(FAR struct altmdm_dev_s *priv, int result) +{ + int ret; + uint32_t ptn; + + if (result == 0) + { + ptn = EVENT_MODEM_WAKEUP_REQ_DONE_OK; + } + else + { + ptn = EVENT_MODEM_WAKEUP_REQ_DONE_NG; + } + ret = altmdm_sys_setflag(&g_wakeup_done_flag, ptn); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_sleep_done + * + * Description: + * Notify that the modem slept. + * + ****************************************************************************/ + +static int send_modem_sleep_done(FAR struct altmdm_dev_s *priv, int result) +{ + int ret; + uint32_t ptn; + + if (result == 0) + { + ptn = EVENT_MODEM_SLEEP_REQ_DONE_OK; + } + else + { + ptn = EVENT_MODEM_SLEEP_REQ_DONE_NG; + } + ret = altmdm_sys_setflag(&g_sleep_done_flag, ptn); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_poweron_done + * + * Description: + * Notify that the modem power on. + * + ****************************************************************************/ + +static int send_modem_poweron_done(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_power_done_flag, EVENT_MODEM_POWER_ON_DONE); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: send_modem_poweroff_done + * + * Description: + * Notify that the modem power off. + * + ****************************************************************************/ + +static int send_modem_poweroff_done(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = altmdm_sys_setflag(&g_power_done_flag, EVENT_MODEM_POWER_OFF_DONE); + if (ret != 0) + { + m_err("ERR:%04d Set flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: wait_for_d2h_up_complete + * + * Description: + * Wait until the Device to Host GPIO line is assert. + * + ****************************************************************************/ + +static int wait_for_d2h_up_complete(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + + ret = altmdm_sys_waitflag(&g_pmtask_flag, EVENT_D2H_UP, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + D2H_UP_EVENT_TIMEOUT); + + return ret; +} + +/**************************************************************************** + * Name: wait_for_modem_state_change_notif + * + * Description: + * Wait until the state of the modem changes. + * + ****************************************************************************/ + +static int wait_for_modem_state_change_notif(FAR struct altmdm_dev_s *priv, + FAR uint32_t * state) +{ + int ret; + uint32_t ptn; + + g_is_waitnotif = true; + + ret = altmdm_sys_waitflag(&g_statetrans_flag, EVENT_STATE_CHG_WAIT, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ST_TRANS_EVENT_TIMEOUT); + if (ret != 0) + { + m_err("ERR:%04d Wait flag:%d.\n", __LINE__, ret); + } + else + { + if (ptn & EVENT_MODEM_SLEPT_NOTIF) + { + *state = MODEM_PM_INTERNAL_STATE_SLEEP; + } + else if (ptn & EVENT_MODEM_WAKEUP_NOTIF) + { + *state = MODEM_PM_INTERNAL_STATE_WAKE; + } + else if (ptn & EVENT_MODEM_GOING_TO_SLEEP_NOTIF) + { + *state = MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP; + } + else + { + *state = MODEM_PM_INTERNAL_STATE_MAX; + } + } + + g_is_waitnotif = false; + + return ret; +} + +/**************************************************************************** + * Name: wait_for_wakeup_requeset_done + * + * Description: + * Wait until the wakeup request is completed. + * + ****************************************************************************/ + +static int wait_for_wakeup_requeset_done(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + + ret = altmdm_sys_waitflag(&g_wakeup_done_flag, + EVENT_MODEM_WAKEUP_REQ_DONE, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ALTMDM_SYS_FLAG_TMOFEVR); + if (ret != 0) + { + m_err("ERR:%04d Wait flag:%d.\n", __LINE__, ret); + } + else + { + if (ptn & EVENT_MODEM_WAKEUP_REQ_DONE_NG) + { + ret = -1; + } + } + + return ret; +} + +/**************************************************************************** + * Name: wait_for_sleep_requeset_done + * + * Description: + * Wait until the sleep request is completed. + * + ****************************************************************************/ + +static int wait_for_sleep_requeset_done(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + + ret = altmdm_sys_waitflag(&g_sleep_done_flag, EVENT_MODEM_SLEEP_REQ_DONE, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ALTMDM_SYS_FLAG_TMOFEVR); + if (ret != 0) + { + m_err("ERR:%04d Wait flag:%d.\n", __LINE__, ret); + } + else + { + if (ptn & EVENT_MODEM_SLEEP_REQ_DONE_NG) + { + ret = -1; + } + } + + return ret; +} + +/**************************************************************************** + * Name: wait_for_poweron_done + * + * Description: + * Wait until the power on is completed. + * + ****************************************************************************/ + +static int wait_for_poweron_done(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + + ret = altmdm_sys_waitflag(&g_power_done_flag, EVENT_MODEM_POWER_ON_DONE, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ALTMDM_SYS_FLAG_TMOFEVR); + if (ret != 0) + { + m_err("ERR:%04d Wait flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: wait_for_poweroff_done + * + * Description: + * Wait until the power off is completed. + * + ****************************************************************************/ + +static int wait_for_poweroff_done(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + + ret = altmdm_sys_waitflag(&g_power_done_flag, EVENT_MODEM_POWER_OFF_DONE, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ALTMDM_SYS_FLAG_TMOFEVR); + if (ret != 0) + { + m_err("ERR:%04d Wait flag:%d.\n", __LINE__, ret); + } + + return ret; +} + +/**************************************************************************** + * Name: d2h_gpio_isr + * + * Description: + * Interrupt handler for Device to Host GPIO line. + * + ****************************************************************************/ + +static void d2h_gpio_isr(FAR struct altmdm_dev_s *priv) +{ + int ret; + bool val = GPIO_LOW; + + ret = get_d2h_gpio(priv, &val); + if (ret == 0) + { + switch (val) + { + case GPIO_LOW: + + ret = send_d2h_down_notif(priv); + if (ret != 0) + { + m_err("ERR:%04d send d2h down notification:%d.\n", __LINE__, + ret); + } + break; + + case GPIO_HIGH: + + ret = send_d2h_up_notif(priv); + if (ret != 0) + { + m_err("ERR:%04d send device up notification:%d.\n", + __LINE__, ret); + } + break; + + default: + m_err("ERR:%04d Invalid D2H GPIO value:%d.\n", __LINE__, val); + break; + } + } +} + +/**************************************************************************** + * Name: exe_callback + * + * Description: + * Execute callback of modem power manager. + * + ****************************************************************************/ + +static int exe_callback(uint32_t type, uint32_t cb_event) +{ + altmdm_pm_cbfunc_t lcallback = NULL; + + if (type == MODEM_PM_CB_TYPE_ERROR) + { + lcallback = g_pm_errcallback; + } + else + { + lcallback = g_pm_callback; + } + + if (lcallback == NULL) + { + return -EPERM; + } + lcallback(cb_event); + + return 0; +} + +/**************************************************************************** + * Name: wakeup_modem_itself + * + * Description: + * The modem wakes up by itself, it transitions to the wakeup state. + * + ****************************************************************************/ + +static int wakeup_modem_itself(FAR struct altmdm_dev_s *priv, bool wakeupreq) +{ + int ret; + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE); + + ret = set_h2d_up(priv); + if (ret == 0) + { + /* Transitions to the wakeup state. */ + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_WAKE); + + /* When the EVENT_MODEM_WAKEUP_REQ is simultaneous, + * there is no need to notify. + */ + + if (!wakeupreq) + { + /* Perform processing at the time of state transition. */ + + send_modem_wakeup_notif(priv); + } + exe_callback(MODEM_PM_CB_TYPE_NORMAL, MODEM_PM_CB_WAKE); + } + + return ret; +} + +/**************************************************************************** + * Name: sleep_modem_itself + * + * Description: + * The modem slept on itself, it transitions to the sleep state. + * + ****************************************************************************/ + +static int sleep_modem_itself(FAR struct altmdm_dev_s *priv) +{ + set_h2d_down(priv); + + /* Transitions to the sleep state. */ + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_SLEEP); + + /* Perform processing at the time of state transition. */ + + send_modem_slept_notif(priv); + exe_callback(MODEM_PM_CB_TYPE_NORMAL, MODEM_PM_CB_SLEEP); + + return 0; +} + +/**************************************************************************** + * Name: modem_sleep_procedure + * + * Description: + * Make the modem transition to sleep. + * + ****************************************************************************/ + +static int modem_sleep_procedure(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = set_h2d_down(priv); + if (ret == 0) + { + /* Transitions to the sleep state. */ + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_SLEEP); + + /* Perform processing at the time of state transition. */ + + send_modem_slept_notif(priv); + exe_callback(MODEM_PM_CB_TYPE_NORMAL, MODEM_PM_CB_SLEEP); + } + + return ret; +} + +/**************************************************************************** + * Name: modem_wakeup_procedure + * + * Description: + * Make the modem transition to wakeup. + * + ****************************************************************************/ + +static int modem_wakeup_procedure(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE); + + ret = set_h2d_up(priv); + if (ret == 0) + { +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + set_mreq_up(priv); +# endif + ret = wait_for_d2h_up_complete(priv); + if (ret != 0) + { + m_err("ERR:%04d device is not up.\n", __LINE__); + + /* Do rollback. */ + +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + set_mreq_down(priv); +# endif + set_h2d_down(priv); + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_SLEEP); + } + else + { + /* Transitions to the wake state. */ + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_WAKE); + + /* Perform processing at the time of state transition. */ + + exe_callback(MODEM_PM_CB_TYPE_NORMAL, MODEM_PM_CB_WAKE); + } + } + + return ret; +} + +/**************************************************************************** + * Name: sleep_is_possible + * + * Description: + * Check if the modem can sleep. + * + ****************************************************************************/ + +static int sleep_is_possible(FAR struct altmdm_dev_s *priv) +{ +# ifdef CONFIG_MODEM_ALTMDM_KEEP_WAKE_STATE + return -EPERM; +# else + int num_of_lock; + uint32_t pm_state; + + pm_state = altmdm_pm_getinternalstate(); + if (pm_state != MODEM_PM_INTERNAL_STATE_WAKE) + { + return -EBUSY; + } + + num_of_lock = altmdm_pm_getwakelockstate(); + if (num_of_lock) + { + return -EBUSY; + } + + if (g_boot_stat != MODEM_PM_ERR_RESET_BOOTSTAT_DONE) + { + return -EBUSY; + } + + return 0; +# endif +} + +/**************************************************************************** + * Name: modem_sleep_req + * + * Description: + * Execute the sleep request. + * + ****************************************************************************/ + +static int modem_sleep_req(FAR struct altmdm_dev_s *priv) +{ + int ret; + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP); + + ret = send_modem_sleep_request(priv); + if (ret == 0) + { + ret = wait_for_sleep_requeset_done(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: modem_wakeup_req + * + * Description: + * Execute the wakeup request. + * + ****************************************************************************/ + +static int modem_wakeup_req(FAR struct altmdm_dev_s *priv) +{ + int ret; + + ret = send_modem_wakeup_request(priv); + if (ret == 0) + { + ret = wait_for_wakeup_requeset_done(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: pm_task + * + * Description: + * ALTMDM power manager driver task. + * + ****************************************************************************/ + +static int pm_task(int argc, FAR char *argv[]) +{ + int ret; + uint32_t ptn; + FAR struct altmdm_dev_s *priv = g_privdata; + + while (!g_is_notrun) + { + ret = altmdm_sys_waitflag(&g_pmtask_flag, EVENT_PM_TASK_WAIT, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ALTMDM_SYS_FLAG_TMOFEVR); + if (ret != 0) + { + m_err("ERR:%04d Wait Flag:%d.\n", __LINE__, ret); + } + else + { + m_info("pm_task ptn:%x.\n", ptn); + + if (ptn & EVENT_MODEM_WAKEUP_REQ) + { + if (ptn & EVENT_D2H_UP) + { + /* Modem already wakeup. */ + + ret = wakeup_modem_itself(priv, true); + +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + set_mreq_up(priv); +# endif + } + else + { + /* Make modem wakeup. */ + + ret = modem_wakeup_procedure(priv); + } + send_modem_wakeup_done(priv, ret); + + if (ptn & EVENT_MODEM_SLEEP_REQ) + { + /* This condition does not occur, + * but it is due to fail safe. + */ + + send_modem_sleep_done(priv, -1); + } + } + else if (ptn & EVENT_MODEM_SLEEP_REQ) + { + /* Make modem sleep. */ + + ret = modem_sleep_procedure(priv); + send_modem_sleep_done(priv, ret); + } + else if (ptn & EVENT_D2H_UP) + { + /* Modem has wake itself. */ + + wakeup_modem_itself(priv, false); + } + else if (ptn & EVENT_D2H_DOWN) + { + /* Modem become sleep itself. */ + + sleep_modem_itself(priv); + } + + if (ptn & EVENT_MODEM_POWERON_REQ) + { + /* Modem power on. */ + + send_modem_poweron_done(priv); + } + + if (ptn & EVENT_MODEM_POWEROFF_REQ) + { + /* Modem power off. */ + + sleep_modem_itself(priv); + + send_modem_poweroff_done(priv); + } + + if (ptn & EVENT_MODEM_RESET_NOTIF) + { + if (MODEM_PM_ERR_RESET_BOOTSTAT_NONE != g_boot_stat) + { + exe_callback(MODEM_PM_CB_TYPE_ERROR, g_boot_stat); + } + else + { + m_err("ERR:%04d Unexpected boot stat:%d.\n", + __LINE__, g_boot_stat); + } + } + + if (ptn & EVENT_EXIT) + { + g_is_notrun = true; + } + } + } + + task_delete(0); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_pm_init + * + * Description: + * Initialize the ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_init(FAR struct altmdm_dev_s *priv) +{ + if (g_is_initdone) + { + return -EPERM; + } + + g_is_initdone = true; + + g_privdata = priv; + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_SLEEP); + + /* Create event flags. */ + + altmdm_sys_initflag(&g_statetrans_flag); + altmdm_sys_initflag(&g_pmtask_flag); + altmdm_sys_initflag(&g_wakeup_done_flag); + altmdm_sys_initflag(&g_sleep_done_flag); + altmdm_sys_initflag(&g_power_done_flag); + + sq_init(&g_wakelock); + + /* Initialize GPIO. */ + + init_h2d_gpio(priv); + init_d2h_gpio(priv); + + /* Create Power management task. */ + + g_is_notrun = false; + + g_taskid = task_create(PM_TASK_NAME, PM_TASK_PRI, PM_TASK_STKSIZE, + (main_t) pm_task, NULL); + if (g_taskid == ERROR) + { + m_err("Failed to create pm task\n"); + } + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_uninit + * + * Description: + * Uninitialize the ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_uninit(FAR struct altmdm_dev_s *priv) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + g_is_initdone = false; + + /* Delete Transfer task. */ + + send_exit_request(priv); + + /* Check pm task is deleted or not. */ + + while (1) + { + if (g_is_notrun) + { + break; + } + usleep(10); + } + + /* Delete event flags. */ + + altmdm_sys_deleteflag(&g_statetrans_flag); + altmdm_sys_deleteflag(&g_pmtask_flag); + altmdm_sys_deleteflag(&g_wakeup_done_flag); + altmdm_sys_deleteflag(&g_sleep_done_flag); + altmdm_sys_deleteflag(&g_power_done_flag); + + /* Uinitialize GPIO. */ + + uninit_h2d_gpio(priv); + uninit_d2h_gpio(priv); + + altmdm_pm_setinternalstate(MODEM_PM_INTERNAL_STATE_SLEEP); + + sq_init(&g_wakelock); + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_wakeup + * + * Description: + * Make modem wake up. + * + ****************************************************************************/ + +int altmdm_pm_wakeup(FAR struct altmdm_dev_s *priv) +{ + int ret; + int retval = MODEM_PM_WAKEUP_FAIL; + bool is_slept = false; + uint32_t modem_state; + + if (!g_is_initdone) + { + return -EPERM; + } + + modem_state = altmdm_pm_getinternalstate(); + switch (modem_state) + { + case MODEM_PM_INTERNAL_STATE_WAKE: + + retval = MODEM_PM_WAKEUP_ALREADY; + +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + /* Case where modem spontaneously enters the wake state and already + notified by altmdm_spi_setreceiverready(). + */ + + if (altmdm_spi_isreceiverready(priv)) + { + altmdm_spi_clearreceiverready(priv); + retval = MODEM_PM_WAKEUP_DONE; + } +# endif + break; + + case MODEM_PM_INTERNAL_STATE_SLEEP: + + is_slept = true; + break; + + case MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP: + case MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE: + + /* Wait for change modem state. */ + + wait_for_modem_state_change_notif(priv, &modem_state); + + if (modem_state == MODEM_PM_INTERNAL_STATE_SLEEP) + { + is_slept = true; + } + else if (modem_state == MODEM_PM_INTERNAL_STATE_WAKE) + { + retval = MODEM_PM_WAKEUP_DONE; + } + else + { + m_err("ERR:%04d unexpected event occurr. state:%d.\n", + __LINE__, modem_state); + } + + break; + + default: + m_err("ERR:%04d unexpected event occurr. state:%d.\n", + __LINE__, modem_state); + } + + if (is_slept) + { + /* Wakeup request. */ + + ret = modem_wakeup_req(priv); + if (ret == 0) + { + retval = MODEM_PM_WAKEUP_DONE; + } + } + + return retval; +} + +/**************************************************************************** + * Name: altmdm_pm_notify_reset + * + * Description: + * Notify reset has done. + * + ****************************************************************************/ + +int altmdm_pm_notify_reset(FAR struct altmdm_dev_s *priv) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + send_modem_reset_notif(priv); + + return 0; +} + +# ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + +/**************************************************************************** + * Name: altmdm_pm_callgpiohandler + * + * Description: + * Call Device to Host GPIO interrupt handler. + * + ****************************************************************************/ + +int altmdm_pm_callgpiohandler(FAR struct altmdm_dev_s *priv) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + d2h_gpio_isr(priv); + + return 0; +} +# endif + +/**************************************************************************** + * Name: altmdm_pm_registercb + * + * Description: + * Register callback for ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_registercb(uint32_t type, altmdm_pm_cbfunc_t cb) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + if (type == MODEM_PM_CB_TYPE_ERROR) + { + if (g_pm_errcallback == NULL) + { + g_pm_errcallback = cb; + } + } + else + { + if (g_pm_callback == NULL) + { + g_pm_callback = cb; + } + } + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_deregistercb + * + * Description: + * Deregister callback for ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_deregistercb(uint32_t type) +{ + altmdm_pm_cbfunc_t *lcallback = NULL; + + if (!g_is_initdone) + { + return -EPERM; + } + + if (type == MODEM_PM_CB_TYPE_ERROR) + { + lcallback = &g_pm_errcallback; + } + else + { + lcallback = &g_pm_callback; + } + if (*lcallback == NULL) + { + return -EPERM; + } + + *lcallback = NULL; + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_sleepmodem + * + * Description: + * Make modem sleep. + * + ****************************************************************************/ + +int altmdm_pm_sleepmodem(FAR struct altmdm_dev_s *priv) +{ + int ret; + + if (!g_is_initdone) + { + return -EPERM; + } + + ret = modem_sleep_req(priv); + + return ret; +} + +/**************************************************************************** + * Name: altmdm_pm_cansleep + * + * Description: + * Check if modem can sleep. + * + ****************************************************************************/ + +int altmdm_pm_cansleep(FAR struct altmdm_dev_s *priv) +{ + int ret; + + if (!g_is_initdone) + { + return -EPERM; + } + + ret = sleep_is_possible(priv); + if (ret == 0) + { + m_info("possible to sleep.\n"); + ret = 1; + } + else + { + m_info("impossible to sleep.\n"); + ret = 0; + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_pm_initwakelock + * + * Description: + * Initialize the modem wakelock resource. + * + ****************************************************************************/ + +int altmdm_pm_initwakelock(FAR struct altmdm_pm_wakelock_s *lock) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + if (!lock) + { + return -EINVAL; + } + + memset(lock, 0, sizeof(struct altmdm_pm_wakelock_s)); + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_acquirewakelock + * + * Description: + * Acquire the modem wakelock. + * + ****************************************************************************/ + +int altmdm_pm_acquirewakelock(FAR struct altmdm_pm_wakelock_s *lock) +{ + irqstate_t flags; + + if (!g_is_initdone) + { + return -EPERM; + } + + if (!lock) + { + return -EINVAL; + } + + flags = enter_critical_section(); + + if (lock->count == 0) + { + sq_addlast((FAR sq_entry_t *) & lock->queue, &g_wakelock); + } + lock->count++; + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_releasewakelock + * + * Description: + * Release the modem wakelock. + * + ****************************************************************************/ + +int altmdm_pm_releasewakelock(FAR struct altmdm_pm_wakelock_s *lock) +{ + irqstate_t flags; + + if (!g_is_initdone) + { + return -EPERM; + } + + if (!lock && (lock->count < 1)) + { + return -EINVAL; + } + + flags = enter_critical_section(); + + lock->count--; + + if (lock->count == 0) + { + sq_rem((FAR sq_entry_t *) & lock->queue, &g_wakelock); + } + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_getnumofwakelock + * + * Description: + * Get the lock count of the specified wakelock. + * + ****************************************************************************/ + +int altmdm_pm_getnumofwakelock(FAR struct altmdm_pm_wakelock_s *lock) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + if (!lock) + { + return -EINVAL; + } + + return lock->count; +} + +/**************************************************************************** + * Name: altmdm_pm_getwakelockstate + * + * Description: + * Get the wakelock status. If the return value is 0, it means that it is + * not locked. Otherwise it means that someone is locking. + * + ****************************************************************************/ + +int altmdm_pm_getwakelockstate(void) +{ + int num; + irqstate_t flags; + + if (!g_is_initdone) + { + return -EPERM; + } + + flags = enter_critical_section(); + + num = sq_count(&g_wakelock); + + leave_critical_section(flags); + + return num; +} + +/**************************************************************************** + * Name: altmdm_pm_poweron + * + * Description: + * Modem power on. + * + ****************************************************************************/ + +int altmdm_pm_poweron(FAR struct altmdm_dev_s *priv) +{ + int ret; + + if (!g_is_initdone) + { + return -EPERM; + } + + ret = send_modem_poweron_request(priv); + if (ret == 0) + { + ret = wait_for_poweron_done(priv); + } + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_poweroff + * + * Description: + * Modem power off. + * + ****************************************************************************/ + +int altmdm_pm_poweroff(FAR struct altmdm_dev_s *priv) +{ + int ret; + + if (!g_is_initdone) + { + return -EPERM; + } + + ret = send_modem_poweroff_request(priv); + if (ret == 0) + { + ret = wait_for_poweroff_done(priv); + } + + return 0; +} + +/**************************************************************************** + * Name: altmdm_pm_set_bootstatus + * + * Description: + * Set boot status. + * + ****************************************************************************/ + +int altmdm_pm_set_bootstatus(FAR struct altmdm_dev_s *priv, uint32_t status) +{ + if (!g_is_initdone) + { + return -EPERM; + } + + g_boot_stat = status; + + return 0; +} + +#endif diff --git a/drivers/modem/altair/altmdm_pm.h b/drivers/modem/altair/altmdm_pm.h new file mode 100644 index 0000000000..8291f4edd6 --- /dev/null +++ b/drivers/modem/altair/altmdm_pm.h @@ -0,0 +1,239 @@ +/**************************************************************************** + * drivers/modem/altair/altmdm_pm.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __DRIVERS_MODEM_ALTAIR_ALTMDM_PM_H +#define __DRIVERS_MODEM_ALTAIR_ALTMDM_PM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "altmdm_dev.h" +#include "altmdm_sys.h" +#include "altmdm_pm_state.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MODEM_PM_WAKEUP_DONE (0) +#define MODEM_PM_WAKEUP_ALREADY (1) +#define MODEM_PM_WAKEUP_FAIL (2) + +#define MODEM_PM_CB_SLEEP (0) +#define MODEM_PM_CB_WAKE (1) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_pm_init + * + * Description: + * Initialize the ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_init(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_uninit + * + * Description: + * Uninitialize the ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_uninit(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_wakeup + * + * Description: + * Make modem wake up. + * + ****************************************************************************/ + +int altmdm_pm_wakeup(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_notify_reset + * + * Description: + * Notify reset has done. + * + ****************************************************************************/ + +int altmdm_pm_notify_reset(FAR struct altmdm_dev_s *priv); + +#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + +/**************************************************************************** + * Name: altmdm_pm_callgpiohandler + * + * Description: + * Call Device to Host GPIO interrupt handler. + * + ****************************************************************************/ + +int altmdm_pm_callgpiohandler(FAR struct altmdm_dev_s *priv); +#endif + +/**************************************************************************** + * Name: altmdm_pm_registercb + * + * Description: + * Register callback for ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_registercb(uint32_t type, altmdm_pm_cbfunc_t cb); + +/**************************************************************************** + * Name: altmdm_pm_deregistercb + * + * Description: + * Deregister callback for ALTMDM power manager driver. + * + ****************************************************************************/ + +int altmdm_pm_deregistercb(uint32_t type); + +/**************************************************************************** + * Name: altmdm_pm_sleepmodem + * + * Description: + * Make modem sleep. + * + ****************************************************************************/ + +int altmdm_pm_sleepmodem(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_cansleep + * + * Description: + * Check if modem can sleep. + * + ****************************************************************************/ + +int altmdm_pm_cansleep(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_initwakelock + * + * Description: + * Initialize the modem wakelock resource. + * + ****************************************************************************/ + +int altmdm_pm_initwakelock(FAR struct altmdm_pm_wakelock_s *lock); + +/**************************************************************************** + * Name: altmdm_pm_acquirewakelock + * + * Description: + * Acquire the modem wakelock. + * + ****************************************************************************/ + +int altmdm_pm_acquirewakelock(FAR struct altmdm_pm_wakelock_s *lock); + +/**************************************************************************** + * Name: altmdm_pm_releasewakelock + * + * Description: + * Release the modem wakelock. + * + ****************************************************************************/ + +int altmdm_pm_releasewakelock(FAR struct altmdm_pm_wakelock_s *lock); + +/**************************************************************************** + * Name: altmdm_pm_getnumofwakelock + * + * Description: + * Get the lock count of the specified wakelock. + * + ****************************************************************************/ + +int altmdm_pm_getnumofwakelock(FAR struct altmdm_pm_wakelock_s *lock); + +/**************************************************************************** + * Name: altmdm_pm_getwakelockstate + * + * Description: + * Get the wakelock status. If the return value is 0, it means that it is + * not locked. Otherwise it means that someone is locking. + * + ****************************************************************************/ + +int altmdm_pm_getwakelockstate(void); + +/**************************************************************************** + * Name: altmdm_pm_poweron + * + * Description: + * Modem power on. + * + ****************************************************************************/ + +int altmdm_pm_poweron(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_poweroff + * + * Description: + * Modem power off. + * + ****************************************************************************/ + +int altmdm_pm_poweroff(FAR struct altmdm_dev_s *priv); + +/**************************************************************************** + * Name: altmdm_pm_set_bootstatus + * + * Description: + * Set boot status. + * + ****************************************************************************/ + +int altmdm_pm_set_bootstatus(FAR struct altmdm_dev_s *priv, uint32_t status); + +#endif +#endif /* __DRIVERS_MODEM_ALTAIR_ALTMDM_PM_H */ \ No newline at end of file diff --git a/drivers/modem/altair/altmdm_pm_state.c b/drivers/modem/altair/altmdm_pm_state.c new file mode 100644 index 0000000000..9655979b63 --- /dev/null +++ b/drivers/modem/altair/altmdm_pm_state.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * drivers/modem/altair/altmdm_pm_state.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 "altmdm_pm_state.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint32_t g_stateofmodem; + +#ifdef CONFIG_MODEM_PM_PUTSTATE +static char *g_putstring[MODEM_PM_INTERNAL_STATE_MAX] = +{ + "SLEEP", + "GOING_TO_WAKE", + "WAKE", + "GOING_TO_SLEEP" +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_pm_getstate + * + * Description: + * Get current modem state. + * + ****************************************************************************/ + +uint32_t altmdm_pm_getstate(void) +{ + uint32_t get_state; + uint32_t internal_state; + + internal_state = altmdm_pm_getinternalstate(); + + switch (internal_state) + { + case MODEM_PM_INTERNAL_STATE_SLEEP: + case MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE: + get_state = MODEM_PM_STATE_SLEEP; + break; + + case MODEM_PM_INTERNAL_STATE_WAKE: + case MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP: + get_state = MODEM_PM_STATE_WAKE; + break; + + default: + get_state = MODEM_PM_STATE_WAKE; + break; + } + + return get_state; +} + +/**************************************************************************** + * Name: altmdm_pm_getinternalstate + * + * Description: + * Get internal modem state. + * + ****************************************************************************/ + +uint32_t altmdm_pm_getinternalstate(void) +{ + uint32_t get_state; + irqstate_t flags; + + flags = enter_critical_section(); + + get_state = g_stateofmodem; + + leave_critical_section(flags); + + return get_state; +} + +/**************************************************************************** + * Name: altmdm_pm_setinternalstate + * + * Description: + * Set internal modem state. + * + ****************************************************************************/ + +void altmdm_pm_setinternalstate(uint32_t state) +{ + irqstate_t flags; +#ifdef CONFIG_MODEM_PM_PUTSTATE + uint32_t prev_state; +#endif + + if (state < MODEM_PM_INTERNAL_STATE_MAX) + { + flags = enter_critical_section(); +#ifdef CONFIG_MODEM_PM_PUTSTATE + prev_state = g_stateofmodem; +#endif + g_stateofmodem = state; + + leave_critical_section(flags); +#ifdef CONFIG_MODEM_PM_PUTSTATE + m_err("MODEM State [%d:%s]-->[%d:%s]\n", + prev_state, g_putstring[prev_state], state, g_putstring[state]); +#endif + } +} +#endif diff --git a/drivers/modem/altair/altmdm_pm_state.h b/drivers/modem/altair/altmdm_pm_state.h new file mode 100644 index 0000000000..2a0518cf1f --- /dev/null +++ b/drivers/modem/altair/altmdm_pm_state.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * drivers/modem/altmdm/altmdm_pm_state.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __DRIVERS_MODEM_ALTMDM_ALTMDM_PM_STATE_H +#define __DRIVERS_MODEM_ALTMDM_ALTMDM_PM_STATE_H + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MODEM_PM_INTERNAL_STATE_SLEEP (0) +#define MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE (1) +#define MODEM_PM_INTERNAL_STATE_WAKE (2) +#define MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP (3) +#define MODEM_PM_INTERNAL_STATE_MAX (4) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_pm_getstate + * + * Description: + * Get current modem state. + * + ****************************************************************************/ + +uint32_t altmdm_pm_getstate(void); + +/**************************************************************************** + * Name: altmdm_pm_getinternalstate + * + * Description: + * Get internal modem state. + * + ****************************************************************************/ + +uint32_t altmdm_pm_getinternalstate(void); + +/**************************************************************************** + * Name: altmdm_pm_setinternalstate + * + * Description: + * Set internal modem state. + * + ****************************************************************************/ + +void altmdm_pm_setinternalstate(uint32_t state); + +#endif +#endif /* __DRIVERS_MODEM_ALTMDM_ALTMDM_PM_STATE_H */ diff --git a/drivers/modem/altair/altmdm_spi.c b/drivers/modem/altair/altmdm_spi.c new file mode 100644 index 0000000000..dd03774aa7 --- /dev/null +++ b/drivers/modem/altair/altmdm_spi.c @@ -0,0 +1,2281 @@ +/**************************************************************************** + * drivers/modem/altmdm/altmdm_spi.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 "altmdm_sys.h" +#include "altmdm_pm.h" +#include "altmdm_pm_state.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define EVENT_BIT(b) (1<<(b)) +#define EVENT_NONE (0) +#define EVENT_TXREQ EVENT_BIT(0) +#define EVENT_RXREQ EVENT_BIT(1) +#define EVENT_CANCEL EVENT_BIT(2) +#define EVENT_EXIT EVENT_BIT(3) +#define EVENT_RXRDY EVENT_BIT(4) +#define EVENT_RXBUFRDY EVENT_BIT(5) +#define EVENT_TX_DONE EVENT_BIT(6) +#define EVENT_RX_DONE EVENT_BIT(7) +#define EVENT_SLEEPREQ EVENT_BIT(8) +#define EVENT_SLEEP_DONE EVENT_BIT(9) +#define EVENT_SV_TIMER_EXP EVENT_BIT(10) +#define EVENT_XFERRDY EVENT_BIT(11) +#define EVENT_REQMASK (EVENT_TXREQ | EVENT_RXREQ | EVENT_SLEEPREQ | \ + EVENT_SV_TIMER_EXP) +#define EVENT_TRANS_WAIT (EVENT_TXREQ | EVENT_RXREQ | EVENT_RXBUFRDY | \ + EVENT_SLEEPREQ | EVENT_SV_TIMER_EXP | EVENT_EXIT) +#define XFER_TASK_PRI (90) +#define XFER_TASK_STKSIZE (1536) +#define XFER_TASK_NAME "altmdm_xfer_task" +#if defined(CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE) +# if ((CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE & 0x3) != 0) +# error MODEM_ALTMDM_MAX_PACKET_SIZE must be aligned 0x4 (4B) +# endif +# define MAX_PKT_SIZE (CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE) +#else +# define MAX_PKT_SIZE (2064) +#endif +#define UNIT_SIZE (4) +#define RX_ENABLE (0) +#define RX_DISABLE (1) +#define SLEEP_OK (0) +#define SLEEP_NG (-EBUSY) + +/* Timeout is counted in units of millisecond. */ + +#define WAIT_RXREQ_TIMEOUT (1000) +#define WAIT_XFERRDY_TIMEOUT (25 * 1000) +#if defined(CONFIG_MODEM_ALTMDM_SLEEP_TIMER_VAL) +# if (CONFIG_MODEM_ALTMDM_SLEEP_TIMER_VAL < 20) +# error MODEM_ALTMDM_SLEEP_TIMER_VAL too small +# endif +# define SV_TIMER_TIMOUT_VAL (CONFIG_MODEM_ALTMDM_SLEEP_TIMER_VAL) +#else +# define SV_TIMER_TIMOUT_VAL (20) +#endif +#define WRITE_WAIT_TIMEOUT (ALTMDM_SYS_FLAG_TMOFEVR) +#define SREQ_WAIT_TIMEOUT (ALTMDM_SYS_FLAG_TMOFEVR) + +#define SPI_MAXFREQUENCY (13000000) /* 13MHz. */ + +#define GPIO_SREQ_INT_POLARITY (ALTMDM_GPIOINT_LEVEL_HIGH) +#define GPIO_SREQ_INT_NOISE_FILTER (ALTMDM_GPIOINT_NOISE_FILTER_DISABLE) + +/* Defines for transfer mode */ + +#define MODE_RXDATA (0) /* Data receive mode. */ +#define MODE_TXDATA (1) /* Data send mode. */ +#define MODE_TRXDATA (2) /* Data send and receive mode. */ +#define MODE_RXDATANOBUFF (3) /* Data receive mode when there is no + * receiving buffer. + */ +#define MODE_TRXDATANOBUFF (4) /* Data send and receive mode when + * there is no receiving buffer. + */ +#define MODE_RXINVALID (5) /* Data receive mode when receiving + * header is wrong. + */ +#define MODE_TRXHEADERFAILTXREQ (6) /* Data send and receive mode when + * header transfer fails. Send request + * triggered. + */ +#define MODE_TRXHEADERFAILRXREQ (7) /* Data receive mode when header + * transfer fails. Receive request + * triggered. + */ +#define MODE_RXRESET (8) /* Reset packet receive mode. */ +#define MODE_TRXRESET (9) /* Data send and reset packet receive + * mode. + */ + +/* Defines for transfer result code */ + +#define TRANS_OK (1) /* OK. */ +#define TRANS_OK_RXDATANOBUFF (-1) /* OK when MODE_RXDATANOBUFF mode. */ +#define TRANS_OK_TRXDATANORXBUFF (-2) /* OK when MODE_TRXDATANOBUFF mode. */ +#define TRANS_RXINVALID (-3) /* NG when MODE_RXINVALID mode. */ +#define TRANS_WAITRCVRTMO (-4) /* NG when receiver ready timeout. */ +#define TRANS_OK_RCVBUFFUL (-5) /* OK when receiver is buffer full. */ + +#define RESET_BOOTSTAT_BOOTING (0) /* Boot stat: booting */ +#define RESET_BOOTSTAT_UPDATING (1) /* Boot stat: updating */ + +#define STAT_INF_GET_BOOTSTAT (1 << 1) /* Status info: Get bootstatus bit */ +#define STAT_INF_RESET (1 << 2) /* Status info: Reset bit */ +#define STAT_INF_BUFFFULL (1 << 3) /* Status info: Buffer full bit */ + +#define STAT_INF_IS_RESET(info) ((info & STAT_INF_RESET) >> 2) +#define STAT_INF_IS_BUFF_FULL(info) ((info & STAT_INF_BUFFFULL) >> 3) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct altmdm_dev_s *g_privdata = NULL; +static char g_tmp_rxbuff[MAX_PKT_SIZE]; +static char g_tmp_txbuff[MAX_PKT_SIZE]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: svtimer_handler + * + * Description: + * Timeout handler for supervisory timer. + * + ****************************************************************************/ + +static void svtimer_handler(int signo, FAR siginfo_t * info, + FAR void *ucontext) +{ + FAR struct altmdm_dev_s *priv = + (FAR struct altmdm_dev_s *)(info->si_value.sival_ptr); + + altmdm_sys_setflag(&priv->spidev.xfer_flag, EVENT_SV_TIMER_EXP); +} + +/**************************************************************************** + * Name: init_svtimer + * + * Description: + * Initialize supervisory timer. + * + ****************************************************************************/ + +static int init_svtimer(FAR struct altmdm_dev_s *priv) +{ + priv->spidev.sleep_param.sv_timerid = NULL; + + return 0; +} + +/**************************************************************************** + * Name: delete_svtimer + * + * Description: + * Delete supervisory timer. + * + ****************************************************************************/ + +static int delete_svtimer(FAR struct altmdm_dev_s *priv) +{ + altmdm_sys_stoptimer(priv->spidev.sleep_param.sv_timerid); + priv->spidev.sleep_param.sv_timerid = NULL; + + return 0; +} + +/**************************************************************************** + * Name: start_svtimer + * + * Description: + * Start supervisory timer. + * + ****************************************************************************/ + +static int start_svtimer(FAR struct altmdm_dev_s *priv) +{ + timer_t timerid; + + timerid = altmdm_sys_starttimer(SV_TIMER_TIMOUT_VAL, SV_TIMER_TIMOUT_VAL, + svtimer_handler, 0, priv); + if (timerid == NULL) + { + return -1; + } + priv->spidev.sleep_param.sv_timerid = timerid; + + return 0; +} + +/**************************************************************************** + * Name: stop_svtimer + * + * Description: + * Stop supervisory timer. + * + ****************************************************************************/ + +static int stop_svtimer(FAR struct altmdm_dev_s *priv) +{ + altmdm_sys_stoptimer(priv->spidev.sleep_param.sv_timerid); + priv->spidev.sleep_param.sv_timerid = NULL; + + return 0; +} + +/**************************************************************************** + * Name: do_dmaxfer + * + * Description: + * Execute DMA transfer. + * + ****************************************************************************/ + +static int do_dmaxfer(FAR struct altmdm_dev_s *priv, FAR void *tx_buffer, + FAR void *rx_buffer, size_t dma_size) +{ + SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, dma_size); + + return 0; +} + +/**************************************************************************** + * Name: get_dmasize + * + * Description: + * Get the data size used for DMA transfer. + * + ****************************************************************************/ + +static int get_dmasize(FAR struct altmdm_dev_s *priv, int data_size) +{ + return data_size; +} + +/**************************************************************************** + * Name: wait_receiverready + * + * Description: + * Wait until reciever is ready. + * + ****************************************************************************/ + +static int wait_receiverready(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + ret = altmdm_sys_waitflag(&spidev->xfer_flag, EVENT_RXREQ, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + WAIT_RXREQ_TIMEOUT); + if (ret != 0) + { + m_err("receiver ready timeout.\n"); + return TRANS_WAITRCVRTMO; + } + + return 0; +} + +/**************************************************************************** + * Name: wait_xferready + * + * Description: + * Wait until xfer is ready. + * + ****************************************************************************/ + +static int wait_xferready(FAR struct altmdm_dev_s *priv) +{ + int ret; + uint32_t ptn; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + ret = altmdm_sys_waitflag(&spidev->xferready_flag, EVENT_XFERRDY, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + WAIT_XFERRDY_TIMEOUT); + if (ret != 0) + { + m_err("xfer ready timeout.\n"); + + /* Make it ready to transfer. + * It is assumed that modem does not implement reset packet. + */ + + if (!spidev->is_xferready) + { + spidev->is_xferready = true; + m_info("ready to xfer\n"); + } + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: notify_xferready + * + * Description: + * Notify xfer is ready. + * + ****************************************************************************/ + +static int notify_xferready(FAR struct altmdm_dev_s *priv) +{ + int ret; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + ret = altmdm_sys_setflag(&spidev->xferready_flag, EVENT_XFERRDY); + + return ret; +} + +/**************************************************************************** + * Name: init_rxbuffer + * + * Description: + * Initialize the receive buffer used for data transfer. + * + ****************************************************************************/ + +static void init_rxbuffer(FAR struct altmdm_dev_s *priv, + FAR struct altmdm_spi_rxbuff_s **rxbuff, + uint32_t unit_size) +{ + FAR struct altmdm_spi_rxbuff_s *l_buff = NULL; + + l_buff = (FAR struct altmdm_spi_rxbuff_s *)kmm_malloc + (sizeof(struct altmdm_spi_rxbuff_s)); + if (l_buff == NULL) + { + m_err("cannot allocate memory for received buffer\n"); + } + else + { + memset(l_buff, 0x00, sizeof(struct altmdm_spi_rxbuff_s)); + + l_buff->buff_addr = (char *)kmm_malloc(unit_size); + if (l_buff->buff_addr == NULL) + { + m_err("cannot allocate memory for received buffer\n"); + kmm_free(l_buff); + l_buff = NULL; + } + else + { + l_buff->buff_size = unit_size; + } + } + *rxbuff = l_buff; +} + +/**************************************************************************** + * Name: uninit_rxbuffer + * + * Description: + * Uninitialize the receive buffer used for data transfer. + * + ****************************************************************************/ + +static void uninit_rxbuffer(FAR struct altmdm_dev_s *priv, + FAR struct altmdm_spi_rxbuff_s *rxbuff) +{ + if (rxbuff != NULL) + { + if (rxbuff->buff_addr != NULL) + { + kmm_free(rxbuff->buff_addr); + } + kmm_free(rxbuff); + } +} + +/**************************************************************************** + * Name: alloc_rxbuffer + * + * Description: + * Get the allocated receive buffer. + * + ****************************************************************************/ + +static void alloc_rxbuffer(FAR struct altmdm_dev_s *priv, + FAR struct altmdm_spi_rxbuff_s **rxbuff, + uint32_t size) +{ + if (priv->spidev.rxbuffinfo.free_buff == NULL) + { + m_err("cannot allocate free rx buffer\n"); + } + else + { + *rxbuff = priv->spidev.rxbuffinfo.free_buff; + priv->spidev.rxbuffinfo.free_buff = NULL; + } +} + +/**************************************************************************** + * Name: free_rxbuffer + * + * Description: + * Release allocated receive buffer. + * + ****************************************************************************/ + +static void free_rxbuffer(FAR struct altmdm_dev_s *priv, + FAR struct altmdm_spi_rxbuff_s *rxbuff) +{ + if (priv->spidev.rxbuffinfo.free_buff != NULL) + { + m_err("cannot free rx buffer\n"); + } + else + { + priv->spidev.rxbuffinfo.free_buff = rxbuff; + } +} + +/**************************************************************************** + * Name: create_rxbufffifo + * + * Description: + * Create receiving FIFO. This fifo is used when copying to the buffer + * specified by the user. + * + ****************************************************************************/ + +static void create_rxbufffifo(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo; + + init_rxbuffer(priv, &priv->spidev.rxbuffinfo.free_buff, MAX_PKT_SIZE); + + fifo->head = NULL; + fifo->tail = NULL; + + altmdm_sys_initcsem(&fifo->csem); +} + +/**************************************************************************** + * Name: destroy_rxbufffifo + * + * Description: + * Destroy receiving FIFO. + * + ****************************************************************************/ + +static void destroy_rxbufffifo(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo; + + uninit_rxbuffer(priv, priv->spidev.rxbuffinfo.free_buff); + + altmdm_sys_deletecsem(&fifo->csem); +} + +/**************************************************************************** + * Name: put_rxbufffifo + * + * Description: + * Put date into the receiving FIFO. + * + ****************************************************************************/ + +static void put_rxbufffifo(FAR struct altmdm_dev_s *priv, + FAR struct altmdm_spi_rxbuff_s *rxbuff) +{ + FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo; + irqstate_t flags; + + flags = enter_critical_section(); + + if (fifo->head == NULL) + { + fifo->head = rxbuff; + fifo->tail = rxbuff; + rxbuff->next = NULL; + } + else + { + fifo->tail->next = rxbuff; + fifo->tail = rxbuff; + rxbuff->next = NULL; + } + + leave_critical_section(flags); + + altmdm_sys_postcsem(&fifo->csem); +} + +/**************************************************************************** + * Name: get_rxbufffifo + * + * Description: + * Get date from the receiving FIFO. If the FIFO is empty, + * it is kept waiting until data is put in the FIFO. + * + ****************************************************************************/ + +static void get_rxbufffifo(FAR struct altmdm_dev_s *priv, + FAR struct altmdm_spi_rxbuff_s **rxbuff) +{ + FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo; + irqstate_t flags; + + *rxbuff = NULL; + + altmdm_sys_waitcsem(&fifo->csem); + + flags = enter_critical_section(); + + if (fifo->head != NULL) + { + *rxbuff = fifo->head; + fifo->head = fifo->head->next; + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: abort_get_rxbufffifo + * + * Description: + * If waiting for data to be put in the FIFO, then abort it. + * + ****************************************************************************/ + +static void abort_get_rxbufffifo(FAR struct altmdm_dev_s *priv) +{ + int val; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo; + + if (!altmdm_sys_getcsemvalue(&fifo->csem, &val)) + { + if (val < 0) + { + spidev->rx_param.rxabort = true; + altmdm_sys_postcsem(&fifo->csem); + } + } +} + +/**************************************************************************** + * Name: clear_txheader + * + * Description: + * Clear the header for transmission. + * + ****************************************************************************/ + +static void clear_txheader(FAR struct altmdm_dev_s *priv) +{ + memset(&priv->spidev.tx_param.header, 0x00, + sizeof(struct altmdm_spi_xferhdr_s)); +} + +/**************************************************************************** + * Name: clear_rxheader + * + * Description: + * Clear the header for reception. + * + ****************************************************************************/ + +static void clear_rxheader(FAR struct altmdm_dev_s *priv) +{ + memset(&priv->spidev.rx_param.header, 0x00, + sizeof(struct altmdm_spi_xferhdr_s)); +} + +/**************************************************************************** + * Name: set_txheader_datasize + * + * Description: + * Set transmission data size in the header. + * + ****************************************************************************/ + +static void set_txheader_datasize(FAR struct altmdm_dev_s *priv, + int total_size, int actual_size) +{ + FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header; + + tx_header->header[0] = + (tx_header->header[0] & 0xf0) + ((total_size >> 10) & 0x0000000f); + tx_header->header[1] = (total_size >> 2) & 0x000000ff; + tx_header->header[2] = + ((total_size & 0x00000003) << 6) + ((actual_size >> 8) & 0x0000003f); + tx_header->header[3] = (actual_size & 0x000000ff); +} + +/**************************************************************************** + * Name: set_txheader_possibleofrx + * + * Description: + * Set flag in the header. The flag indicates that master can receive data. + * + ****************************************************************************/ + +static void set_txheader_possibleofrx(FAR struct altmdm_dev_s *priv, + bool possible) +{ + FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header; + + if (!possible) + { + tx_header->header[0] = 0x80 + (tx_header->header[0] & 0x7f); + } + else + { + tx_header->header[0] = 0x00 + (tx_header->header[0] & 0x7f); + } +} + +/**************************************************************************** + * Name: set_txheader_sleepreq + * + * Description: + * Set flag in the header. The flag indicates that sleep request. + * + ****************************************************************************/ + +static void set_txheader_sleepreq(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header; + + tx_header->header[0] = 0x10 + (tx_header->header[0] & 0xef); +} + +/**************************************************************************** + * Name: show_txheader + * + * Description: + * Show header for transmission. + * + ****************************************************************************/ + +static void show_txheader(FAR struct altmdm_dev_s *priv) +{ +#ifdef MODEM_ALTMDM_DEBUG + FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header; + + m_info("[TXHDR]=%02x,%02x,%02x,%02x\n", + tx_header->header[0], tx_header->header[1], + tx_header->header[2], tx_header->header[3]); +#endif +} + +/**************************************************************************** + * Name: parse_rxheader + * + * Description: + * Parse header for receiving. + * + ****************************************************************************/ + +static void parse_rxheader(FAR struct altmdm_dev_s *priv, + FAR int *total_size, FAR int *actual_size, + FAR int *is_reset, FAR int *is_bufful) +{ + FAR struct altmdm_spi_xferhdr_s *rx_header = &priv->spidev.rx_param.header; + + m_info("[RXHDR]%02x,%02x,%02x,%02x\n", + rx_header->header[0], rx_header->header[1], + rx_header->header[2], rx_header->header[3]); + + *total_size = ((rx_header->header[0] & 0x0f) << 10) + + ((rx_header->header[1] & 0xff) << 2) + (rx_header->header[2] >> 6); + *actual_size = ((rx_header->header[2] & 0x3f) << 8) + + (rx_header->header[3] & 0xff); + + priv->spidev.rx_param.status_info = (rx_header->header[0] & 0xf0) >> 4; + + *is_reset = STAT_INF_IS_RESET(priv->spidev.rx_param.status_info); + *is_bufful = STAT_INF_IS_BUFF_FULL(priv->spidev.rx_param.status_info); + + m_info("t=%d a=%d r=%d b=%d\n", + *total_size, *actual_size, *is_reset, *is_bufful); + + return; +} + +/**************************************************************************** + * Name: verify_rxheader + * + * Description: + * Verify header for receiving. + * + ****************************************************************************/ + +static int verify_rxheader(FAR struct altmdm_dev_s *priv, + int total_size, int actual_size) +{ + int calc_total_size; + + if ((total_size == 0) || (actual_size == 0)) + { + return -1; + } + + if ((total_size > MAX_PKT_SIZE) || (actual_size > MAX_PKT_SIZE)) + { + return -1; + } + + if (total_size % UNIT_SIZE) + { + return -1; + } + + if (total_size != actual_size) + { + calc_total_size = ((actual_size / UNIT_SIZE) + 1) * UNIT_SIZE; + + if (total_size != calc_total_size) + { + return -1; + } + } + + return 0; +} + +/**************************************************************************** + * Name: do_xferheader + * + * Description: + * Execute header transfer. + * + ****************************************************************************/ + +static int do_xferheader(FAR struct altmdm_dev_s *priv, + uint32_t is_rxreq, uint32_t is_txreq, + uint32_t is_sleepreq, uint32_t is_rcvrready) +{ + int ret; + int dma_xfer_size; + struct altmdm_spi_dev_s *spidev = &priv->spidev; + bool possibleofrx = true; + + /* Make transfer header */ + + clear_txheader(priv); + + if ((is_sleepreq) || (is_txreq)) + { + if (is_sleepreq) + { + set_txheader_sleepreq(priv); + } + else + { + set_txheader_datasize(priv, spidev->tx_param.total_size, + spidev->tx_param.actual_size); + } + } + if (!is_sleepreq) + { + alloc_rxbuffer(priv, &spidev->rx_param.rxbuff, MAX_PKT_SIZE); + if (spidev->rx_param.rxbuff == NULL) + { + possibleofrx = false; + } + set_txheader_possibleofrx(priv, possibleofrx); + } + show_txheader(priv); + + /* Wait for Receiver Ready to receive. */ + + if ((!is_rxreq) && (!is_rcvrready)) + { + ret = wait_receiverready(priv); + if (ret < 0) + { + goto trans_header_error; + } + } + + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, sizeof(struct altmdm_spi_xferhdr_s)); + + ret = do_dmaxfer(priv, (void *)&spidev->tx_param.header, + (void *)&spidev->rx_param.header, dma_xfer_size); + if (ret < 0) + { + goto trans_header_error; + } + + return ret; + +trans_header_error: + m_err("ERR:%04d Transfer Header Failed. ret = %d.\n", __LINE__, ret); + + /* Clear Header */ + + clear_rxheader(priv); + set_txheader_datasize(priv, 0, 0); + + return ret; +} + +/**************************************************************************** + * Name: do_receivedata + * + * Description: + * Executes the receive only transfer mode. + * + ****************************************************************************/ + +static int do_receivedata(FAR struct altmdm_dev_s *priv) +{ + int ret; + int dma_xfer_size; + FAR void *rxbuff; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, spidev->rx_param.total_size); + + rxbuff = spidev->rx_param.rxbuff->buff_addr; + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, rxbuff, dma_xfer_size); + } + if (ret < 0) + { + m_err("Rcv Data Failed. ret = %d.\n", ret); + clear_rxheader(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: do_senddata + * + * Description: + * Executes the transmission only transfer mode. + * + ****************************************************************************/ + +static int do_senddata(FAR struct altmdm_dev_s *priv) +{ + int ret; + int dma_xfer_size; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, spidev->tx_param.total_size); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr, + (void *)g_tmp_rxbuff, dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Snd Data Failed. ret = %d.\n", __LINE__, ret); + clear_txheader(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: do_trxdata + * + * Description: + * Executes the transmission and receive transfer mode. + * + ****************************************************************************/ + +static int do_trxdata(FAR struct altmdm_dev_s *priv) +{ + int ret; + int xfer_size; + int dma_xfer_size; + FAR void *rxbuff; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Choose the larger one. */ + + if (spidev->tx_param.total_size < spidev->rx_param.total_size) + { + xfer_size = spidev->rx_param.total_size; + } + else + { + xfer_size = spidev->tx_param.total_size; + } + + rxbuff = spidev->rx_param.rxbuff->buff_addr; + + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, xfer_size); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr, rxbuff, + dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Trx Data Failed. ret = %d.\n", __LINE__, ret); + clear_txheader(priv); + clear_rxheader(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: do_receivedata_nobuff + * + * Description: + * Executes the receive only transfer mode. When receiving buffer cannot + * be prepared. + * + ****************************************************************************/ + +static int do_receivedata_nobuff(FAR struct altmdm_dev_s *priv) +{ + int ret; + int dma_xfer_size; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, spidev->rx_param.total_size); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, (void *)g_tmp_rxbuff, + dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Rcv Data Nobuff Failed. ret = %d.\n", __LINE__, ret); + clear_rxheader(priv); + } + else + { + ret = TRANS_OK_RXDATANOBUFF; + } + + return ret; +} + +/**************************************************************************** + * Name: do_trxdata_norxbuff + * + * Description: + * Executes the transmission and receive transfer mode. When receiving + * buffer cannot be prepared. + * + ****************************************************************************/ + +static int do_trxdata_norxbuff(FAR struct altmdm_dev_s *priv) +{ + int ret; + int xfer_size; + int dma_xfer_size; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Choose the larger one. */ + + if (spidev->tx_param.total_size < spidev->rx_param.total_size) + { + xfer_size = spidev->rx_param.total_size; + } + else + { + xfer_size = spidev->tx_param.total_size; + } + + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, xfer_size); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr, + (void *)g_tmp_rxbuff, dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Trx Data Norxbuff Failed. ret = %d.\n", __LINE__, ret); + clear_txheader(priv); + clear_rxheader(priv); + } + else + { + ret = TRANS_OK_TRXDATANORXBUFF; + } + + return ret; +} + +/**************************************************************************** + * Name: do_receivesleepdata + * + * Description: + * Executes the sleep data transfer mode. + * + ****************************************************************************/ + +static int do_receivesleepdata(FAR struct altmdm_dev_s *priv, FAR int *resp) +{ + int ret; + int dma_xfer_size; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, UNIT_SIZE); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, (void *)g_tmp_rxbuff, + dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Rcv Sleep Resp Data Failed. ret = %d.\n", + __LINE__, ret); + } + else + { + m_info("[SRESP] 0x%02x,0x%02x,0x%02x,0x%02x\n", + g_tmp_rxbuff[0], g_tmp_rxbuff[1], + g_tmp_rxbuff[2], g_tmp_rxbuff[3]); + + if (!memcmp(g_tmp_rxbuff, "OK", 2)) + { + *resp = SLEEP_OK; + } + else + { + *resp = SLEEP_NG; + } + } + + return ret; +} + +/**************************************************************************** + * Name: do_receivereset + * + * Description: + * Executes the reset packet receive only transfer mode. + * + ****************************************************************************/ + +static int do_receivereset(FAR struct altmdm_dev_s *priv) +{ + int ret; + int dma_xfer_size; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, spidev->rx_param.total_size); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, (void *)g_tmp_rxbuff, + dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Rcv Reset Failed. ret = %d.\n", __LINE__, ret); + clear_rxheader(priv); + } + else + { + if ((STAT_INF_GET_BOOTSTAT | STAT_INF_RESET) == + (spidev->rx_param. + status_info & (STAT_INF_GET_BOOTSTAT | STAT_INF_RESET))) + { + switch (g_tmp_rxbuff[0]) + { + case RESET_BOOTSTAT_BOOTING: + altmdm_pm_set_bootstatus(priv, + MODEM_PM_ERR_RESET_BOOTSTAT_BOOTING); + break; + case RESET_BOOTSTAT_UPDATING: + altmdm_pm_set_bootstatus(priv, + MODEM_PM_ERR_RESET_BOOTSTAT_UPDATING); + break; + default: + m_err + ("ERR:%04d Invalid payload of reset packet. %02x,%02x,%02x,%02x\n", + __LINE__, g_tmp_rxbuff[0], g_tmp_rxbuff[1], g_tmp_rxbuff[2], + g_tmp_rxbuff[3]); + break; + } + } + else if (STAT_INF_RESET == + (spidev->rx_param.status_info & STAT_INF_RESET)) + { + altmdm_pm_set_bootstatus(priv, MODEM_PM_ERR_RESET_BOOTSTAT_DONE); + } + else + { + m_err("ERR:%04d Unexpected status info. %04x\n", __LINE__, + spidev->rx_param.status_info); + } + } + + return ret; +} + +/**************************************************************************** + * Name: do_trxreset + * + * Description: + * Executes the transmission and receive reset packet transfer mode. + * + ****************************************************************************/ + +static int do_trxreset(FAR struct altmdm_dev_s *priv) +{ + int ret; + int xfer_size; + int dma_xfer_size; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + /* Wait for Receiver Ready to receive. */ + + ret = wait_receiverready(priv); + if (ret >= 0) + { + /* Choose the larger one. */ + + if (spidev->tx_param.total_size < spidev->rx_param.total_size) + { + xfer_size = spidev->rx_param.total_size; + } + else + { + xfer_size = spidev->tx_param.total_size; + } + + /* Get DMA transfer size */ + + dma_xfer_size = get_dmasize(priv, xfer_size); + + /* Do DMA transfer */ + + ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr, + (void *)g_tmp_rxbuff, dma_xfer_size); + } + if (ret < 0) + { + m_err("ERR:%04d Trx Reset Failed. ret = %d.\n", __LINE__, ret); + clear_txheader(priv); + clear_rxheader(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: do_xfersleep + * + * Description: + * Executes the sleep request. + * + ****************************************************************************/ + +static int do_xfersleep(FAR struct altmdm_dev_s *priv, uint32_t is_rcvrready) +{ + int ret; + int resp; + int is_reset = 0; + int total_size; + int actual_size; + int is_bufful; + + /* Transfer header for sleep request */ + + ret = do_xferheader(priv, 0, 0, 1, is_rcvrready); + if (ret >= 0) + { + parse_rxheader(priv, &total_size, &actual_size, &is_reset, &is_bufful); + + /* Transfer data for sleep request */ + + ret = do_receivesleepdata(priv, &resp); + if (ret >= 0) + { + ret = resp; + } + } + if (ret < 0) + { + ret = SLEEP_NG; + } + + if (is_reset) + { + if (!priv->spidev.is_xferready) + { + priv->spidev.is_xferready = true; + m_info("ready to xfer\n"); + notify_xferready(priv); + } + altmdm_pm_notify_reset(priv); + } + + return ret; +} + +/**************************************************************************** + * Name: decide_xfermode + * + * Description: + * Decide transfer mode. + * + ****************************************************************************/ + +static uint32_t decide_xfermode(FAR struct altmdm_dev_s *priv, + uint32_t is_rxreq, uint32_t is_txreq, int ret) +{ + int retval; + int is_reset; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + uint32_t mode = MODE_RXINVALID; + + if (ret < 0) + { + if (is_txreq) + { + mode = MODE_TRXHEADERFAILTXREQ; + } + else + { + mode = MODE_TRXHEADERFAILRXREQ; + } + if (spidev->rx_param.rxbuff != NULL) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + } + else + { + parse_rxheader(priv, &spidev->rx_param.total_size, + &spidev->rx_param.actual_size, &is_reset, + &spidev->tx_param.is_bufful); + + if (is_rxreq) + { + retval = verify_rxheader(priv, spidev->rx_param.total_size, + spidev->rx_param.actual_size); + if (retval != 0) + { + m_info("RX header:total=0x%02x, actual=0x%02x.\n", + spidev->rx_param.total_size, + spidev->rx_param.actual_size); + + if (spidev->rx_param.rxbuff != NULL) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + + if (!is_txreq) + { + return mode; + } + + is_rxreq = 0; + + m_info("RX Header invalid. But Send will be done.\n"); + } + } + else if ((spidev->rx_param.actual_size != 0) || + (spidev->rx_param.total_size != 0)) + { + retval = verify_rxheader(priv, spidev->rx_param.total_size, + spidev->rx_param.actual_size); + if (retval == 0) + { + is_rxreq = 1; + } + } + + /* Diceide transfer mode here. */ + + if (is_txreq) + { + if (is_rxreq) + { + if (is_reset) + { + if (spidev->rx_param.rxbuff != NULL) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + + mode = MODE_TRXRESET; + } + else + { + if (spidev->rx_param.rxbuff == NULL) + { + mode = MODE_TRXDATANOBUFF; + } + else + { + mode = MODE_TRXDATA; + spidev->rx_param.rxbuff->rx_size = + spidev->rx_param.actual_size; + m_info("received size = %d.\n", + spidev->rx_param.rxbuff->rx_size); + } + } + } + else + { + if (spidev->rx_param.rxbuff != NULL) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + + mode = MODE_TXDATA; + } + } + else + { + if (is_reset) + { + if (spidev->rx_param.rxbuff != NULL) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + + mode = MODE_RXRESET; + } + else + { + if (spidev->rx_param.rxbuff == NULL) + { + mode = MODE_RXDATANOBUFF; + } + else + { + mode = MODE_RXDATA; + spidev->rx_param.rxbuff->rx_size = + spidev->rx_param.actual_size; + m_info("received size = %d.\n", + spidev->rx_param.rxbuff->rx_size); + } + } + } + } + + clear_rxheader(priv); + clear_txheader(priv); + + return mode; +} + +/**************************************************************************** + * Name: done_xfer + * + * Description: + * Notify that transfer has completed. + * + ****************************************************************************/ + +static void done_xfer(FAR struct altmdm_dev_s *priv, uint32_t xfer_mode, + int ret) +{ + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + switch (xfer_mode) + { + case MODE_RXDATA: + if (ret < 0) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + else + { + put_rxbufffifo(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + break; + + case MODE_TXDATA: + if (spidev->tx_param.is_bufful) + { + spidev->tx_param.is_bufful = 0; + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL; + } + else + { + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK; + } + altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE); + break; + + case MODE_TRXDATA: + if (spidev->tx_param.is_bufful) + { + spidev->tx_param.is_bufful = 0; + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL; + } + else + { + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK; + } + altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE); + + if (ret < 0) + { + free_rxbuffer(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + else + { + put_rxbufffifo(priv, spidev->rx_param.rxbuff); + spidev->rx_param.rxbuff = NULL; + } + break; + + case MODE_TRXDATANOBUFF: + if (spidev->tx_param.is_bufful) + { + spidev->tx_param.is_bufful = 0; + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL; + } + else + { + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK; + } + altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE); + break; + + case MODE_TRXHEADERFAILTXREQ: + spidev->tx_param.result = ret; + altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE); + break; + + case MODE_RXRESET: + if (!spidev->is_xferready) + { + spidev->is_xferready = true; + m_info("ready to xfer\n"); + notify_xferready(priv); + } + altmdm_pm_notify_reset(priv); + break; + + case MODE_TRXRESET: + if (!spidev->is_xferready) + { + spidev->is_xferready = true; + m_info("ready to xfer\n"); + notify_xferready(priv); + } + altmdm_pm_notify_reset(priv); + if (spidev->tx_param.is_bufful) + { + spidev->tx_param.is_bufful = 0; + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL; + } + else + { + spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK; + } + altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE); + break; + + case MODE_TRXHEADERFAILRXREQ: + case MODE_RXDATANOBUFF: + case MODE_RXINVALID: + break; + + default: + break; + } +} + +/**************************************************************************** + * Name: done_sleep + * + * Description: + * Notify that sleep request has completed. + * + ****************************************************************************/ + +static void done_sleep(FAR struct altmdm_dev_s *priv, int ret) +{ + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + spidev->sleep_param.result = ret; + altmdm_sys_setflag(&spidev->sleep_param.done_flag, EVENT_SLEEP_DONE); +} + +/**************************************************************************** + * Name: xfer_task_init + * + * Description: + * Initialize SPI transfer task. + * + ****************************************************************************/ + +static void xfer_task_init(FAR struct altmdm_dev_s *priv) +{ + sigset_t mask; + + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, NULL); + + init_svtimer(priv); +} + +/**************************************************************************** + * Name: xfer_task + * + * Description: + * ALTMDM SPI transfer task. + * + ****************************************************************************/ + +static int xfer_task(int argc, char *argv[]) +{ + int ret; + int sleep_result; + int res_code; + uint32_t is_txreq; + uint32_t is_rxreq; + uint32_t is_sleepreq; + uint32_t is_timerexp; + uint32_t do_sleep; + uint32_t ptn; + uint32_t xfer_mode; + uint32_t modem_state; + uint32_t is_rcvrready = 0; + FAR struct altmdm_dev_s *priv = g_privdata; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + xfer_task_init(priv); + + while (!spidev->is_not_run) + { + ret = altmdm_sys_waitflag(&spidev->xfer_flag, EVENT_TRANS_WAIT, + ALTMDM_SYS_FLAG_WMODEOR, &ptn, + ALTMDM_SYS_FLAG_TMOFEVR); + if (ret != 0) + { + m_err("wait flag failed:%d.\n", ret); + continue; + } + + m_info("ptn:%x.\n", ptn); + + if (ptn & EVENT_REQMASK) + { + is_txreq = ptn & EVENT_TXREQ; + is_rxreq = ptn & EVENT_RXREQ; + is_sleepreq = ptn & EVENT_SLEEPREQ; + is_timerexp = ptn & EVENT_SV_TIMER_EXP; + do_sleep = 0; + sleep_result = SLEEP_NG; + + /* Sleep transition event received. Check if it can sleep. */ + + if (is_sleepreq || is_timerexp) + { + /* If data transfer required at the same time, cannot sleep. */ + + if (!(is_txreq || is_rxreq)) + { + if (altmdm_pm_cansleep(priv)) + { + do_sleep = 1; + } + else if (is_timerexp) + { + /* Case where modem spontaneously enters sleep state and + * timer is not stopped. + */ + + modem_state = altmdm_pm_getinternalstate(); + if (modem_state == MODEM_PM_INTERNAL_STATE_SLEEP) + { + stop_svtimer(priv); + } + } + } + } + + if (do_sleep) + { + stop_svtimer(priv); + + /* Transfer sleep packet */ + + sleep_result = do_xfersleep(priv, 0); + if (sleep_result == SLEEP_OK) + { + altmdm_pm_sleepmodem(priv); + } + } + + if (is_sleepreq) + { + /* Send sleep response */ + + done_sleep(priv, sleep_result); + } + + /* Receive data transfer request */ + + if (is_txreq || is_rxreq) + { + stop_svtimer(priv); + + if (is_txreq) + { + /* Wakeup modem before data transfer */ + + res_code = altmdm_pm_wakeup(priv); + if (res_code == MODEM_PM_WAKEUP_FAIL) + { + done_xfer(priv, MODE_TXDATA, TRANS_WAITRCVRTMO); + start_svtimer(priv); + continue; + } +#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + else if (res_code == MODEM_PM_WAKEUP_DONE) + { + is_rcvrready = 1; + } +#endif + } + + /* transfer header */ + + ret = do_xferheader(priv, is_rxreq, is_txreq, 0, is_rcvrready); + +#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + if (is_rcvrready) + { + is_rcvrready = 0; + } +#endif + xfer_mode = decide_xfermode(priv, is_rxreq, is_txreq, ret); + + switch (xfer_mode) + { + case MODE_RXDATA: + ret = do_receivedata(priv); + break; + + case MODE_TXDATA: + ret = do_senddata(priv); + break; + + case MODE_TRXDATA: + ret = do_trxdata(priv); + break; + + case MODE_RXDATANOBUFF: + ret = do_receivedata_nobuff(priv); + break; + + case MODE_TRXDATANOBUFF: + ret = do_trxdata_norxbuff(priv); + break; + + case MODE_RXRESET: + ret = do_receivereset(priv); + break; + + case MODE_TRXRESET: + ret = do_trxreset(priv); + break; + + case MODE_RXINVALID: + ret = TRANS_RXINVALID; + break; + + case MODE_TRXHEADERFAILTXREQ: + case MODE_TRXHEADERFAILRXREQ: + break; + + default: + m_err("ERR:%04d Unknown decision of transfer: %d.\n", + __LINE__, xfer_mode); + break; + } + + m_info("m=%d\n", xfer_mode); + done_xfer(priv, xfer_mode, ret); + start_svtimer(priv); + } + } + + if (ptn & EVENT_EXIT) + { + spidev->is_not_run = true; + } + } + + delete_svtimer(priv); + task_delete(0); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_spi_gpioreadyisr + * + * Description: + * Interrupt handler for SLAVE_REQUEST GPIO line. + * + ****************************************************************************/ + +int altmdm_spi_gpioreadyisr(int irq, FAR void *context, FAR void *arg) +{ + uint32_t modem_state; + FAR struct altmdm_dev_s *priv = g_privdata; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + +#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + modem_state = altmdm_pm_getinternalstate(); + if ((modem_state == MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP) || + (modem_state == MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE) || + (modem_state == MODEM_PM_INTERNAL_STATE_SLEEP)) + { + altmdm_pm_callgpiohandler(priv); + } + else + { + altmdm_sys_setflag(&spidev->xfer_flag, EVENT_RXREQ); + } +#else + altmdm_sys_setflag(&spidev->xfer_flag, EVENT_RXREQ); +#endif + + return 0; +} + +/**************************************************************************** + * Name: altmdm_spi_init + * + * Description: + * Initialize ALTMDM driver. + * + ****************************************************************************/ + +int altmdm_spi_init(FAR struct altmdm_dev_s *priv) +{ + int ret = 0; + + g_privdata = priv; + + /* Initalize modem power management driver */ + + altmdm_pm_init(priv); + + memset(&priv->spidev, 0, sizeof(struct altmdm_spi_dev_s)); + memset(g_tmp_txbuff, 0, sizeof(g_tmp_txbuff)); + priv->spidev.is_not_run = false; + priv->spidev.is_xferready = false; + + altmdm_sys_initlock(&priv->spidev.tx_param.lock); + altmdm_sys_initlock(&priv->spidev.rx_param.lock); + altmdm_sys_initlock(&priv->spidev.sleep_param.lock); + + altmdm_sys_initflag(&priv->spidev.xfer_flag); + altmdm_sys_initflag(&priv->spidev.xferready_flag); + altmdm_sys_initflag(&priv->spidev.tx_param.done_flag); + altmdm_sys_initflag(&priv->spidev.sleep_param.done_flag); + + create_rxbufffifo(priv); + + /* SPI settings */ + + (void)SPI_LOCK(priv->spi, true); + SPI_SETMODE(priv->spi, SPIDEV_MODE0); + SPI_SETBITS(priv->spi, 8); + (void)SPI_SETFREQUENCY(priv->spi, SPI_MAXFREQUENCY); + (void)SPI_LOCK(priv->spi, false); + + priv->spidev.task_id = task_create(XFER_TASK_NAME, XFER_TASK_PRI, + XFER_TASK_STKSIZE, xfer_task, NULL); + if (priv->spidev.task_id == ERROR) + { + m_err("Failed to create xfer task\n"); + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_spi_uninit + * + * Description: + * Uninitialize ALTMDM driver. + * + ****************************************************************************/ + +int altmdm_spi_uninit(FAR struct altmdm_dev_s *priv) +{ + altmdm_sys_setflag(&priv->spidev.xfer_flag, EVENT_EXIT); + + /* check transfer task is deleted or not */ + + while (1) + { + if (priv->spidev.is_not_run) + { + break; + } + usleep(10); + } + + altmdm_sys_deletelock(&priv->spidev.tx_param.lock); + altmdm_sys_deletelock(&priv->spidev.rx_param.lock); + altmdm_sys_deletelock(&priv->spidev.sleep_param.lock); + + altmdm_sys_deleteflag(&priv->spidev.xfer_flag); + altmdm_sys_deleteflag(&priv->spidev.tx_param.done_flag); + altmdm_sys_deleteflag(&priv->spidev.sleep_param.done_flag); + + if (priv->spidev.rx_param.rxbuff != NULL) + { + free_rxbuffer(priv, priv->spidev.rx_param.rxbuff); + priv->spidev.rx_param.rxbuff = NULL; + } + destroy_rxbufffifo(priv); + + /* Uninitalize modem power management driver */ + + altmdm_pm_uninit(priv); + + return 0; +} + +/**************************************************************************** + * Name: altmdm_spi_enable + * + * Description: + * Enable ALTMDM SPI driver. + * + ****************************************************************************/ + +int altmdm_spi_enable(FAR struct altmdm_dev_s *priv) +{ + return 0; +} + +/**************************************************************************** + * Name: altmdm_spi_disable + * + * Description: + * Disable ALTMDM SPI driver. + * + ****************************************************************************/ + +int altmdm_spi_disable(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + spidev->is_xferready = false; + + return 0; +} + +/**************************************************************************** + * Name: altmdm_spi_read + * + * Description: + * ALTMDM SPI driver read method. + * + ****************************************************************************/ + +ssize_t altmdm_spi_read(FAR struct altmdm_dev_s * priv, + FAR const char *buffer, size_t readlen) +{ + FAR struct altmdm_spi_dev_s *spidev; + FAR struct altmdm_spi_rxbuff_s *rbuff; + ssize_t rsize = readlen; + + /* Check argument */ + + if ((priv == NULL) || (buffer == NULL)) + { + return -EINVAL; + } + + if (!readlen || readlen > MAX_PKT_SIZE) + { + m_err("Invalid read length:%d.\n", readlen); + return -EINVAL; + } + + spidev = &priv->spidev; + + altmdm_sys_lock(&spidev->rx_param.lock); + + get_rxbufffifo(priv, &rbuff); + if (spidev->rx_param.rxabort) + { + spidev->rx_param.rxabort = false; + if (rbuff != NULL) + { + m_info("rx buffer discard because of abort.%d\n", __LINE__); + free_rxbuffer(priv, rbuff); + } + rsize = -ECONNABORTED; + } + else + { + if (rbuff == NULL) + { + m_err("get rx buffer failed.\n"); + rsize = -EIO; + } + else if (rbuff->rx_size > readlen) + { + m_info("get rx buffer.%d\n", __LINE__); + rsize = readlen; + memcpy((void *)buffer, rbuff->buff_addr, rsize); + free_rxbuffer(priv, rbuff); + } + else + { + m_info("get rx buffer.%d\n", __LINE__); + rsize = rbuff->rx_size; + memcpy((void *)buffer, rbuff->buff_addr, rsize); + free_rxbuffer(priv, rbuff); + } + } + + altmdm_sys_unlock(&spidev->rx_param.lock); + + return rsize; +} + +/**************************************************************************** + * Name: altmdm_spi_write + * + * Description: + * ALTMDM SPI driver write method. + * + ****************************************************************************/ + +ssize_t altmdm_spi_write(FAR struct altmdm_dev_s * priv, + FAR const char *buffer, size_t witelen) +{ + int ret; + int remainder; + uint32_t ptn; + FAR struct altmdm_spi_dev_s *spidev; + ssize_t wsize = witelen; + + /* Check argument */ + + if ((priv == NULL) || (buffer == NULL)) + { + return -EINVAL; + } + + if (!witelen || witelen > MAX_PKT_SIZE) + { + m_err("Invalid write length:%d.\n", witelen); + return -EINVAL; + } + + spidev = &priv->spidev; + + if (!spidev->is_xferready) + { + wait_xferready(priv); + } + + altmdm_sys_lock(&spidev->tx_param.lock); + +again: + spidev->tx_param.buff_addr = (void *)buffer; + spidev->tx_param.actual_size = witelen; + + remainder = witelen % UNIT_SIZE; + if (remainder == 0) + { + spidev->tx_param.total_size = spidev->tx_param.actual_size; + } + else + { + spidev->tx_param.total_size = + ((spidev->tx_param.actual_size / UNIT_SIZE) + 1) * UNIT_SIZE; + } + + spidev->tx_param.result = 0; + + altmdm_sys_setflag(&spidev->xfer_flag, EVENT_TXREQ); + + ret = altmdm_sys_waitflag(&spidev->tx_param.done_flag, + EVENT_TX_DONE, + ALTMDM_SYS_FLAG_WMODEOR, + &ptn, + WRITE_WAIT_TIMEOUT); + if (ret != OK) + { + m_err("wait failed:%d\n", ret); + wsize = -ETIME; + } + else + { + switch (spidev->tx_param.result) + { + case TRANS_OK: + case TRANS_OK_TRXDATANORXBUFF: + wsize = witelen; + break; + + case TRANS_RXINVALID: + case TRANS_WAITRCVRTMO: + wsize = -EIO; + break; + + case TRANS_OK_RCVBUFFUL: + usleep(100); + goto again; + break; + + default: + m_err("Unexpected situation. tx result = %d.\n", + spidev->tx_param.result); + wsize = -EIO; + break; + } + m_info("%s: tx result: %d.\n", __func__, spidev->tx_param.result); + m_info("%s: write size: %d.\n", __func__, wsize); + } + + altmdm_sys_unlock(&spidev->tx_param.lock); + + return wsize; +} + +/**************************************************************************** + * Name: spicom_read_abort + * + * Description: + * Abort the read process. + * + ****************************************************************************/ + +int altmdm_spi_readabort(FAR struct altmdm_dev_s *priv) +{ + /* Check argument */ + + if (priv == NULL) + { + return -EINVAL; + } + + abort_get_rxbufffifo(priv); + + return OK; +} + +/**************************************************************************** + * Name: altmdm_spi_sleepmodem + * + * Description: + * Make ALTMDM sleep. + * + ****************************************************************************/ + +int altmdm_spi_sleepmodem(FAR struct altmdm_dev_s *priv) +{ + int ret; + bool sleep_requested; + uint32_t ptn; + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + altmdm_sys_lock(&spidev->sleep_param.lock); + sleep_requested = spidev->sleep_param.requested; + if (!sleep_requested) + { + spidev->sleep_param.requested = true; + } + altmdm_sys_unlock(&spidev->sleep_param.lock); + + if (sleep_requested) + { + ret = -EBUSY; + } + else + { + spidev->sleep_param.result = 0; + + altmdm_sys_setflag(&spidev->xfer_flag, EVENT_SLEEPREQ); + + ret = altmdm_sys_waitflag(&spidev->sleep_param.done_flag, + EVENT_SLEEP_DONE, ALTMDM_SYS_FLAG_WMODEOR, + &ptn, SREQ_WAIT_TIMEOUT); + if (ret != OK) + { + m_err("wait failed:%d\n", ret); + } + else + { + ret = spidev->sleep_param.result; + m_info("%s: sleep result: %d.\n", __func__, + spidev->sleep_param.result); + } + spidev->sleep_param.requested = false; + } + + return ret; +} + +#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1 + +/**************************************************************************** + * Name: altmdm_spi_setreceiverready + * + * Description: + * Set receiver ready notification. + * + ****************************************************************************/ + +int altmdm_spi_setreceiverready(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + altmdm_sys_setflag(&spidev->xfer_flag, EVENT_RXREQ); + + return 0; +} + +/**************************************************************************** + * Name: altmdm_spi_isreceiverready + * + * Description: + * Check already notified or not by altmdm_spi_setreceiverready. + * + ****************************************************************************/ + +int altmdm_spi_isreceiverready(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + struct altmdm_sys_flagstate_s flag_status; + + altmdm_sys_referflag(&spidev->xfer_flag, &flag_status); + if (flag_status.flag_pattern & EVENT_RXREQ) + { + return 1; + } + + return 0; +} + +/**************************************************************************** + * Name: altmdm_spi_clearreceiverready + * + * Description: + * Clear receiver ready notification. + * + ****************************************************************************/ + +int altmdm_spi_clearreceiverready(FAR struct altmdm_dev_s *priv) +{ + FAR struct altmdm_spi_dev_s *spidev = &priv->spidev; + + altmdm_sys_clearflag(&spidev->xfer_flag, EVENT_RXREQ); + + return 0; +} +#endif + +#endif /* CONFIG_MODEM_ALTMDM */ diff --git a/drivers/modem/altair/altmdm_spi.h b/drivers/modem/altair/altmdm_spi.h new file mode 100644 index 0000000000..40b2a6777c --- /dev/null +++ b/drivers/modem/altair/altmdm_spi.h @@ -0,0 +1,182 @@ +/**************************************************************************** + * drivers/modem/altmdm/altmdm_spi.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __DRIVERS_MODEM_ALTMDM_ALTMDM_ALTMDM_SPI_H +#define __DRIVERS_MODEM_ALTMDM_ALTMDM_ALTMDM_SPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "altmdm_dev.h" +#include "altmdm_sys.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure describes the transfer header. */ + +struct altmdm_spi_xferhdr_s + { + uint8_t header[4]; /* Transfer header. */ + }; + +/* This structure describes the buffer for data receive. */ + +struct altmdm_spi_rxbuff_s + { + char *buff_addr; /* Receive buffer address. */ + uint32_t buff_size; /* Size of this buffer. */ + uint32_t rx_size; /* Received data size. */ + struct altmdm_spi_rxbuff_s *next; /* Link for next buffer. */ + }; + +/* This structure describes the fifo for received buffer. */ + +struct altmdm_spi_rxbufffifo_s + { + struct altmdm_spi_rxbuff_s *head; /* Point to the head of fifo */ + struct altmdm_spi_rxbuff_s *tail; /* Point to the tail of fifo */ + struct altmdm_sys_csem_s csem; /* It is used for notification when + * data is put in fifo. + */ + }; + +/* This structure describes the parameters for receive buffer information. */ + +struct altmdm_spi_rxbuffinfo_s + { + struct altmdm_spi_rxbuff_s *free_buff; /* Free receive buffer address. */ + struct altmdm_spi_rxbufffifo_s fifo; /* Receive buffer fifo. */ + }; + +/* This structure describes the parameters for send data. */ + +struct altmdm_spi_tx_s + { + struct altmdm_sys_lock_s lock; /* Lock on accessing the following + * parameters. + */ + struct altmdm_sys_flag_s done_flag; /* Notify that tx request has been + * completed. + */ + struct altmdm_spi_xferhdr_s header; /* Tx header. */ + char *buff_addr; /* Buffer address for data transmission + * speceified by the user. + */ + int32_t actual_size; /* Actual data size. */ + int32_t total_size; /* Data size of 4byte alignment. */ + int32_t result; /* Result of transfer. */ + int32_t is_bufful; /* Indicates the slave is buffer full status. */ + }; + +/* This structure describes the parameters for receive data. */ + +struct altmdm_spi_rx_s + { + struct altmdm_sys_lock_s lock; /* Lock on accessing the following + * parameters. + */ + struct altmdm_spi_xferhdr_s header; /* Rx header. */ + int8_t status_info; /* Header status information */ + int32_t actual_size; /* Actual data size */ + int32_t total_size; /* Data size of 4byte alignment. */ + struct altmdm_spi_rxbuff_s *rxbuff; /* Current recieve beffer. */ + bool rxabort; /* Indicates whether the rx process is aborted. */ + }; + +/* This structure describes the parameters for sleep modem. */ + +struct altmdm_spi_sleepmodem_s + { + struct altmdm_sys_lock_s lock; /* Lock on accessing the following + * parameters. + */ + + struct altmdm_sys_flag_s done_flag; /* Notify that sleep request has been + * completed. + */ + int32_t result; /* Result of sleep request. */ + bool requested; /* Indicates that sleep request has been requested. */ + timer_t sv_timerid; /* Superviser timer. */ + }; + +/* This structure describes the resource of the ALTMDM spi driver */ + +struct altmdm_spi_dev_s + { + /* Common fields */ + + bool is_not_run; /* Indicates xfer task is not run. */ + int32_t task_id; /* xfer task ID. */ + bool is_xferready; /* Indicates whether the modem is ready to xfer. */ + struct altmdm_sys_flag_s xferready_flag; /* Used for wating ready to + * xfer. + */ + struct altmdm_sys_flag_s xfer_flag; /* Used for event handling of xfer + * task. + */ + struct altmdm_sys_flag_s dma_done_flag; /* Notify that DMA transfer has + * been completed. + */ + + /* Parameter for recieve buffer */ + + struct altmdm_spi_rxbuffinfo_s rxbuffinfo; + + /* Parameter for send data */ + + struct altmdm_spi_tx_s tx_param; + + /* Parameter for recieve data */ + + struct altmdm_spi_rx_s rx_param; + + /* Parameters for sleep modem */ + + struct altmdm_spi_sleepmodem_s sleep_param; + }; + +#endif +#endif /* __DRIVERS_MODEM_ALTMDM_ALTMDM_SPI_H */ diff --git a/drivers/modem/altair/altmdm_sys.c b/drivers/modem/altair/altmdm_sys.c new file mode 100644 index 0000000000..5ec532047c --- /dev/null +++ b/drivers/modem/altair/altmdm_sys.c @@ -0,0 +1,827 @@ +/**************************************************************************** + * drivers/modem/altmdm/altmdm_sys.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 "altmdm_dev.h" +#include "altmdm_sys.h" + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +# define MY_TIMER_SIGNAL SIGUSR1 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_sys_initlock + * + * Description: + * Initialize lock resource. + * + ****************************************************************************/ + +int altmdm_sys_initlock(FAR struct altmdm_sys_lock_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_init(&handle->sem, 0, 1); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_init() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_deletelock + * + * Description: + * Delete lock resource + * + ****************************************************************************/ + +int altmdm_sys_deletelock(FAR struct altmdm_sys_lock_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_destroy(&handle->sem); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_destroy() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_lock + * + * Description: + * Acquire lock. + * + ****************************************************************************/ + +int altmdm_sys_lock(FAR struct altmdm_sys_lock_s *handle) +{ + int ret; + int l_errno; + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + while (1) + { + ret = sem_wait(&handle->sem); + if (ret == ERROR) + { + l_errno = errno; + if (l_errno == EINTR) + { + continue; + } + m_err("sem_wait() failed:%d\n", l_errno); + } + break; + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_unlock + * + * Description: + * Relese lock. + * + ****************************************************************************/ + +int altmdm_sys_unlock(FAR struct altmdm_sys_lock_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_post(&handle->sem); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_post() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_initcsem + * + * Description: + * Initialize counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_initcsem(FAR struct altmdm_sys_csem_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_init(&handle->sem, 0, 0); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_init() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_deletecsem + * + * Description: + * Delete counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_deletecsem(FAR struct altmdm_sys_csem_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_destroy(&handle->sem); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_destroy() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_waitcsem + * + * Description: + * Wait counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_waitcsem(FAR struct altmdm_sys_csem_s *handle) +{ + int ret; + int l_errno; + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + while (1) + { + ret = sem_wait(&handle->sem); + if (ret == ERROR) + { + l_errno = errno; + if (l_errno == EINTR) + { + continue; + } + m_err("sem_wait() failed:%d\n", l_errno); + } + break; + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_postcsem + * + * Description: + * Post counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_postcsem(FAR struct altmdm_sys_csem_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_post(&handle->sem); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_post() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_getcsemvalue + * + * Description: + * Get value of counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_getcsemvalue(FAR struct altmdm_sys_csem_s *handle, + FAR int *value) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if ((handle == NULL) || (value == NULL)) + { + return ERROR; + } + + ret = sem_getvalue(&handle->sem, value); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_getvalue() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_initflag + * + * Description: + * Initialize event flag resource. + * + ****************************************************************************/ + +int altmdm_sys_initflag(FAR struct altmdm_sys_flag_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + handle->flag = 0; + ret = sem_init(&handle->sem, 0, 0); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_init() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_deleteflag + * + * Description: + * Delete event flag resource. + * + ****************************************************************************/ + +int altmdm_sys_deleteflag(FAR struct altmdm_sys_flag_s *handle) +{ + int ret; +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + int l_errno; +# endif + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + ret = sem_destroy(&handle->sem); + +# ifdef CONFIG_MODEM_ALTMDM_DEBUG + if (ret == ERROR) + { + l_errno = errno; + m_err("sem_destroy() failed:%d\n", l_errno); + } +# endif + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_waitflag + * + * Description: + * Wait event flag. + * + ****************************************************************************/ + +int altmdm_sys_waitflag(FAR struct altmdm_sys_flag_s *handle, + uint32_t wait_pattern, uint32_t wait_mode, + FAR uint32_t * pattern, uint32_t timeout_ms) +{ + int ret = OK; + int ret2; + int l_errno; + struct timespec abs_time; + struct timespec curr_time; + irqstate_t flags; + uint32_t ptn; + + /* Check argument. */ + + if ((handle == NULL) || (pattern == NULL)) + { + m_err("invalid parameter\n"); + + return ERROR; + } + + switch (wait_mode) + { + case ALTMDM_SYS_FLAG_WMODEOR: + case ALTMDM_SYS_FLAG_WMODEAND: + break; + default: + m_err("invalid wait mode:%d\n", wait_mode); + return ERROR; + } + + if (timeout_ms != ALTMDM_SYS_FLAG_TMOFEVR) + { + /* Get current time. */ + + ret = clock_gettime(CLOCK_REALTIME, &curr_time); + if (ret != OK) + { + return ret; + } + + abs_time.tv_sec = timeout_ms / 1000; + abs_time.tv_nsec = (timeout_ms - (abs_time.tv_sec * 1000)) * 1000 * 1000; + + abs_time.tv_sec += curr_time.tv_sec; + abs_time.tv_nsec += curr_time.tv_nsec; + + /* Check more than 1 sec. */ + + if (abs_time.tv_nsec >= (1000 * 1000 * 1000)) + { + abs_time.tv_sec += 1; + abs_time.tv_nsec -= (1000 * 1000 * 1000); + } + } + + *pattern = 0; + + while (1) + { + if (wait_mode == ALTMDM_SYS_FLAG_WMODEOR) + { + flags = enter_critical_section(); + + ptn = (handle->flag & wait_pattern); + if (ptn != 0) + { + /* Wait pattern matched. */ + + *pattern = ptn; + handle->flag = (handle->flag & ~ptn); + + /* Clear the semaphore posted by altmdm_sys_setflag. */ + + while (1) + { + ret2 = sem_trywait(&handle->sem); + if (ret2 == ERROR) + { + break; + } + } + leave_critical_section(flags); + + ret = OK; + break; + } + leave_critical_section(flags); + } + else + { + flags = enter_critical_section(); + + ptn = (handle->flag & wait_pattern); + if (ptn == wait_pattern) + { + /* Wait pattern matched. */ + + *pattern = ptn; + handle->flag = (handle->flag & ~ptn); + + /* Clear the semaphore posted by altmdm_sys_setflag. */ + + while (1) + { + ret2 = sem_trywait(&handle->sem); + if (ret2 == ERROR) + { + break; + } + } + leave_critical_section(flags); + + ret = OK; + break; + } + leave_critical_section(flags); + } + + if (timeout_ms != ALTMDM_SYS_FLAG_TMOFEVR) + { + /* Wait for the semaphore to be posted until timeout occurs. */ + + ret = sem_timedwait(&handle->sem, &abs_time); + if (ret == ERROR) + { + l_errno = errno; + if (l_errno == EINTR) + { + continue; + } + m_err("sem_timedwait() failed:%d\n", l_errno); + break; + } + } + else + { + /* Wait for the semaphore to be posted forever. */ + + ret = sem_wait(&handle->sem); + if (ret == ERROR) + { + l_errno = errno; + if (l_errno == EINTR) + { + continue; + } + m_err("sem_wait() failed:%d\n", l_errno); + break; + } + } + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_setflag + * + * Description: + * Set event flag. + * + ****************************************************************************/ + +int altmdm_sys_setflag(FAR struct altmdm_sys_flag_s *handle, uint32_t pattern) +{ + int ret; + irqstate_t flags; + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + flags = enter_critical_section(); + + handle->flag = (handle->flag | pattern); + + leave_critical_section(flags); + + ret = sem_post(&handle->sem); + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_clearflag + * + * Description: + * Clear event flag. + * + ****************************************************************************/ + +int altmdm_sys_clearflag(FAR struct altmdm_sys_flag_s *handle, + uint32_t pattern) +{ + irqstate_t flags; + + /* Check argument. */ + + if (handle == NULL) + { + return ERROR; + } + + flags = enter_critical_section(); + + handle->flag = (handle->flag & ~pattern); + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: altmdm_sys_referflag + * + * Description: + * Refer event flag. + * + ****************************************************************************/ + +int altmdm_sys_referflag(FAR struct altmdm_sys_flag_s *handle, + FAR struct altmdm_sys_flagstate_s *status) +{ + irqstate_t flags; + + /* Check argument. */ + + if ((handle == NULL) || (status == NULL)) + { + return ERROR; + } + + flags = enter_critical_section(); + + status->flag_pattern = handle->flag; + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: altmdm_sys_starttimer + * + * Description: + * Start timer. + * + ****************************************************************************/ + +timer_t altmdm_sys_starttimer(int first_ms, int interval_ms, + FAR void *handler, int int_param, + FAR void *ptr_param) +{ + int ret; + sigset_t mask; + struct sigaction sa; + struct sigevent sev; + struct itimerspec timer; + timer_t timerid; + + /* Check argument. */ + + if (handler == NULL) + { + return NULL; + } + + sigemptyset(&mask); + sigaddset(&mask, MY_TIMER_SIGNAL); + + ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); + if (ret != OK) + { + m_err("sigprocmask() failed:%d\n", ret); + return NULL; + } + + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO; + sigfillset(&sa.sa_mask); + sigdelset(&sa.sa_mask, MY_TIMER_SIGNAL); + + ret = sigaction(MY_TIMER_SIGNAL, &sa, NULL); + if (ret != OK) + { + m_err("sigaction() failed:%d\n", ret); + return NULL; + } + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = MY_TIMER_SIGNAL; + sev.sigev_value.sival_int = int_param; + sev.sigev_value.sival_ptr = ptr_param; + + ret = timer_create(CLOCK_REALTIME, &sev, &timerid); + if (ret != OK) + { + m_err("timer_create() failed:%d\n", ret); + return NULL; + } + + timer.it_value.tv_sec = first_ms / 1000; + timer.it_value.tv_nsec = (first_ms % 1000) * 1000 * 1000; + timer.it_interval.tv_sec = interval_ms / 1000; + timer.it_interval.tv_nsec = (interval_ms % 1000) * 1000 * 1000; + + ret = timer_settime(timerid, 0, &timer, NULL); + if (ret != OK) + { + m_err("timer_settime() failed:%d\n", ret); + return NULL; + } + + return timerid; +} + +/**************************************************************************** + * Name: altmdm_sys_restarttimer + * + * Description: + * Restart timer. + * + ****************************************************************************/ + +int altmdm_sys_restarttimer(timer_t timerid, int first_ms, int interval_ms) +{ + int ret; + struct itimerspec timer; + + timer.it_value.tv_sec = first_ms / 1000; + timer.it_value.tv_nsec = (first_ms % 1000) * 1000 * 1000; + timer.it_interval.tv_sec = interval_ms / 1000; + timer.it_interval.tv_nsec = (interval_ms % 1000) * 1000 * 1000; + + ret = timer_settime(timerid, 0, &timer, NULL); + if (ret != OK) + { + m_err("timer_settime() failed:%d\n", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: altmdm_sys_stoptimer + * + * Description: + * Stop timer. + * + ****************************************************************************/ + +void altmdm_sys_stoptimer(timer_t timerid) +{ + sigset_t mask; + + timer_delete(timerid); + + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, NULL); +} + +#endif diff --git a/drivers/modem/altair/altmdm_sys.h b/drivers/modem/altair/altmdm_sys.h new file mode 100644 index 0000000000..4e6552f7c9 --- /dev/null +++ b/drivers/modem/altair/altmdm_sys.h @@ -0,0 +1,274 @@ +/**************************************************************************** + * drivers/modem/altmdm/altmdm_sys.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __DRIVERS_MODEM_ALTMDM_ALTMDM_SYS_H +#define __DRIVERS_MODEM_ALTMDM_ALTMDM_SYS_H + +#if defined(CONFIG_MODEM_ALTMDM) + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ALTMDM_SYS_FLAG_WMODEOR 0 +#define ALTMDM_SYS_FLAG_WMODEAND 1 +#define ALTMDM_SYS_FLAG_TMOFEVR 0 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct altmdm_sys_lock_s + { + sem_t sem; + }; + +struct altmdm_sys_csem_s + { + sem_t sem; + }; + +struct altmdm_sys_flag_s + { + sem_t sem; + uint32_t flag; + }; + +struct altmdm_sys_flagstate_s + { + uint32_t flag_pattern; + }; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: altmdm_sys_initlock + * + * Description: + * Initialize lock resource. + * + ****************************************************************************/ + +int altmdm_sys_initlock(FAR struct altmdm_sys_lock_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_deletelock + * + * Description: + * Delete lock resource + * + ****************************************************************************/ + +int altmdm_sys_deletelock(FAR struct altmdm_sys_lock_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_lock + * + * Description: + * Acquire lock. + * + ****************************************************************************/ + +int altmdm_sys_lock(FAR struct altmdm_sys_lock_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_unlock + * + * Description: + * Relese lock. + * + ****************************************************************************/ + +int altmdm_sys_unlock(FAR struct altmdm_sys_lock_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_initcsem + * + * Description: + * Initialize counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_initcsem(FAR struct altmdm_sys_csem_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_deletecsem + * + * Description: + * Delete counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_deletecsem(FAR struct altmdm_sys_csem_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_waitcsem + * + * Description: + * Wait counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_waitcsem(FAR struct altmdm_sys_csem_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_postcsem + * + * Description: + * Post counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_postcsem(FAR struct altmdm_sys_csem_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_getcsemvalue + * + * Description: + * Get value of counting semaphore. + * + ****************************************************************************/ + +int altmdm_sys_getcsemvalue(FAR struct altmdm_sys_csem_s *handle, + FAR int *value); + +/**************************************************************************** + * Name: altmdm_sys_initflag + * + * Description: + * Initialize event flag resource. + * + ****************************************************************************/ + +int altmdm_sys_initflag(FAR struct altmdm_sys_flag_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_deleteflag + * + * Description: + * Delete event flag resource. + * + ****************************************************************************/ + +int altmdm_sys_deleteflag(FAR struct altmdm_sys_flag_s *handle); + +/**************************************************************************** + * Name: altmdm_sys_waitflag + * + * Description: + * Wait event flag. + * + ****************************************************************************/ + +int altmdm_sys_waitflag(FAR struct altmdm_sys_flag_s *handle, + uint32_t wait_pattern, uint32_t wait_mode, + FAR uint32_t * pattern, uint32_t timeout_ms); + +/**************************************************************************** + * Name: altmdm_sys_setflag + * + * Description: + * Set event flag. + * + ****************************************************************************/ + +int altmdm_sys_setflag(FAR struct altmdm_sys_flag_s *handle, + uint32_t pattern); + +/**************************************************************************** + * Name: altmdm_sys_clearflag + * + * Description: + * Clear event flag. + * + ****************************************************************************/ + +int altmdm_sys_clearflag(FAR struct altmdm_sys_flag_s *handle, + uint32_t pattern); + +/**************************************************************************** + * Name: altmdm_sys_referflag + * + * Description: + * Refer event flag. + * + ****************************************************************************/ + +int altmdm_sys_referflag(FAR struct altmdm_sys_flag_s *handle, + FAR struct altmdm_sys_flagstate_s *status); + +/**************************************************************************** + * Name: altmdm_sys_starttimer + * + * Description: + * Start timer. + * + ****************************************************************************/ + +timer_t altmdm_sys_starttimer(int first_ms, int interval_ms, + FAR void *handler, int int_param, + FAR void *ptr_param); + +/**************************************************************************** + * Name: altmdm_sys_restarttimer + * + * Description: + * Restart timer. + * + ****************************************************************************/ + +int altmdm_sys_restarttimer(timer_t timerid, int first_ms, int interval_ms); + +/**************************************************************************** + * Name: altmdm_sys_stoptimer + * + * Description: + * Stop timer. + * + ****************************************************************************/ + +void altmdm_sys_stoptimer(timer_t timerid); + +#endif +#endif /* __DRIVERS_MODEM_ALTMDM_ALTMDM_SYS_H */ diff --git a/include/nuttx/modem/altmdm.h b/include/nuttx/modem/altmdm.h new file mode 100644 index 0000000000..f7ed237f67 --- /dev/null +++ b/include/nuttx/modem/altmdm.h @@ -0,0 +1,152 @@ +/**************************************************************************** + * include/nuttx/modem/altmdm.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * 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 of Sony Semiconductor Solutions Corporation 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 __INCLUDE_NUTTX_MODEM_ALTMDM_H +#define __INCLUDE_NUTTX_MODEM_ALTMDM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Debug ********************************************************************/ + +/* Non-standard debug that may be enabled just for testing the modem driver */ + +#ifdef CONFIG_MODEM_ALTMDM_DEBUG +# define m_err logerr +# define m_info loginfo +#else +# define m_err(x...) +# define m_info(x...) +#endif + +#define MODEM_IOC_POWERON _MODEMIOC(1) +#define MODEM_IOC_POWEROFF _MODEMIOC(2) +#define MODEM_IOC_READABORT _MODEMIOC(3) +#define MODEM_IOC_SLEEP _MODEMIOC(4) +#define MODEM_IOC_PM_REGISTERCB _MODEMIOC(5) +#define MODEM_IOC_PM_DEREGISTERCB _MODEMIOC(6) +#define MODEM_IOC_PM_GETSTATE _MODEMIOC(7) +#define MODEM_IOC_PM_INITWAKELOCK _MODEMIOC(8) +#define MODEM_IOC_PM_ACQUIREWAKELOCK _MODEMIOC(9) +#define MODEM_IOC_PM_RELEASEWAKELOCK _MODEMIOC(10) +#define MODEM_IOC_PM_GETNUMOFWAKELOCK _MODEMIOC(11) +#define MODEM_IOC_PM_GETWAKELOCKSTATE _MODEMIOC(12) +#define MODEM_IOC_PM_ERR_REGISTERCB _MODEMIOC(13) +#define MODEM_IOC_PM_ERR_DEREGISTERCB _MODEMIOC(14) + +#define MODEM_PM_CB_TYPE_NORMAL 0 +#define MODEM_PM_CB_TYPE_ERROR 1 +#define MODEM_PM_STATE_SLEEP 0 +#define MODEM_PM_STATE_WAKE 1 +#define MODEM_PM_ERR_RESET_BOOTSTAT_NONE 0x00 +#define MODEM_PM_ERR_RESET_BOOTSTAT_BOOTING 0x01 +#define MODEM_PM_ERR_RESET_BOOTSTAT_UPDATING 0x02 +#define MODEM_PM_ERR_RESET_BOOTSTAT_DONE 0x10 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct altmdm_pm_wakelock_s + { + sq_entry_t queue; + int count; + }; + +typedef void (*altmdm_pm_cbfunc_t) (uint32_t state); + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: altmdm_register + * + * Description: + * Register the ALTMDM character device as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/altmdm". + * dev - An instance of the SPI interface to use to communicate with + * ALTMDM. + * + * Returned Value: + * Not NULL on success; NULL on failure. + * + ****************************************************************************/ + +FAR void *altmdm_register(FAR const char *devpath, FAR struct spi_dev_s *dev); + +/**************************************************************************** + * Name: altmdm_unregister + * + * Description: + * Unregister the ALTMDM character device. + * + * Input Parameters: + * handle - The pointer that getting from altmdm_register. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void altmdm_unregister(FAR void *handle); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_MODEM_ALTMDM_H */