From 92892a8dd784c45d7149d39512164feda5e1d855 Mon Sep 17 00:00:00 2001 From: Alin Jerpelea Date: Fri, 14 Jun 2019 18:40:06 +0000 Subject: [PATCH] Merged in alinjerpelea/nuttx (pull request #902) arch: arm: cxd56xx: PM and PWM * configs: spresense: add SPI configuration add SPI configuration for spresense board Signed-off-by: Alin Jerpelea * arch: arm: cxd56xx: add support for PWM add support for PWM for cxd56xx Signed-off-by: Alin Jerpelea * configs: spresense: enable PWM support enable PWM support on spresense board Signed-off-by: Alin Jerpelea * arch: arm: cxd56xx: add Power Management PROCFS support the powermanager procfs support will export /proc/pm: clock power Signed-off-by: Alin Jerpelea * configs: spresense: enable powermanager procfs support The powermanager procfs is disabled by default and need to be enabled by the CONFIG_CXD56_PM_PROCFS option Signed-off-by: Alin Jerpelea * arch: arm: cxd56xx: add timer driver Add timer driver for cxd56xx. NOTE The timer allows a divider of 1, 16 and 256 options Signed-off-by: Alin Jerpelea * arch: arm: cxd56xx: add Watch Dog Timer Add Watch Dog Timer on cxd56xx Signed-off-by: Alin Jerpelea * configs: spresense: enable timer the platform support has been added and now we can use the timers on spresense board. Signed-off-by: Alin Jerpelea * configs: spresense: enable WatchDog timer The platform support has been added and now we can use the WatchDog Timer on spresense board. Signed-off-by: Alin Jerpelea Approved-by: Gregory Nutt --- arch/arm/include/cxd56xx/timer.h | 69 ++ arch/arm/src/cxd56xx/Kconfig | 102 ++- arch/arm/src/cxd56xx/Make.defs | 16 + arch/arm/src/cxd56xx/cxd56_powermgr_procfs.c | 794 +++++++++++++++++++ arch/arm/src/cxd56xx/cxd56_powermgr_procfs.h | 88 ++ arch/arm/src/cxd56xx/cxd56_pwm.c | 495 ++++++++++++ arch/arm/src/cxd56xx/cxd56_pwm.h | 103 +++ arch/arm/src/cxd56xx/cxd56_timer.c | 583 ++++++++++++++ arch/arm/src/cxd56xx/cxd56_timer.h | 99 +++ arch/arm/src/cxd56xx/cxd56_wdt.c | 690 ++++++++++++++++ arch/arm/src/cxd56xx/cxd56_wdt.h | 94 +++ arch/arm/src/cxd56xx/hardware/cxd56_timer.h | 117 +++ arch/arm/src/cxd56xx/hardware/cxd56_wdt.h | 108 +++ configs/spresense/include/board.h | 1 + configs/spresense/include/cxd56_pwm.h | 84 ++ configs/spresense/include/cxd56_wdt.h | 84 ++ configs/spresense/src/Makefile | 8 + configs/spresense/src/cxd56_bringup.c | 60 ++ configs/spresense/src/cxd56_pwm.c | 141 ++++ configs/spresense/src/cxd56_spi.c | 174 ++++ 20 files changed, 3909 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/cxd56xx/timer.h create mode 100644 arch/arm/src/cxd56xx/cxd56_powermgr_procfs.c create mode 100644 arch/arm/src/cxd56xx/cxd56_powermgr_procfs.h create mode 100644 arch/arm/src/cxd56xx/cxd56_pwm.c create mode 100644 arch/arm/src/cxd56xx/cxd56_pwm.h create mode 100644 arch/arm/src/cxd56xx/cxd56_timer.c create mode 100644 arch/arm/src/cxd56xx/cxd56_timer.h create mode 100644 arch/arm/src/cxd56xx/cxd56_wdt.c create mode 100644 arch/arm/src/cxd56xx/cxd56_wdt.h create mode 100644 arch/arm/src/cxd56xx/hardware/cxd56_timer.h create mode 100644 arch/arm/src/cxd56xx/hardware/cxd56_wdt.h create mode 100644 configs/spresense/include/cxd56_pwm.h create mode 100644 configs/spresense/include/cxd56_wdt.h create mode 100644 configs/spresense/src/cxd56_pwm.c create mode 100644 configs/spresense/src/cxd56_spi.c diff --git a/arch/arm/include/cxd56xx/timer.h b/arch/arm/include/cxd56xx/timer.h new file mode 100644 index 0000000000..8c4e9cfe20 --- /dev/null +++ b/arch/arm/include/cxd56xx/timer.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * arch/arm/include/cxd56xx/timer.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. + * + ****************************************************************************/ +/** + * @file timer.h + */ + +#ifndef __ARCH_ARM_INCLUDE_CXD56XX_TIMER_H +#define __ARCH_ARM_INCLUDE_CXD56XX_TIMER_H + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/** + * Set callback handler + * + * @param A pointer to struct timer_sethandler_s + * @return ioctl return value provides success/failure indication + */ + +#define TCIOC_SETHANDLER _TCIOC(0x0020) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This is the type of the argument passed to the TCIOC_SETHANDLER ioctl */ + +struct timer_sethandler_s +{ + FAR void *arg; /* An argument */ + CODE tccb_t handler; /* The timer interrupt handler */ +}; + +#endif /* __ARCH_ARM_INCLUDE_CXD56XX_TIMER_H */ diff --git a/arch/arm/src/cxd56xx/Kconfig b/arch/arm/src/cxd56xx/Kconfig index d2fd2be001..694cace710 100644 --- a/arch/arm/src/cxd56xx/Kconfig +++ b/arch/arm/src/cxd56xx/Kconfig @@ -61,7 +61,6 @@ config CXD56_FARAPI_VERSION_CHECK if CXD56_FARAPI_VERSION_CHECK - config CXD56_FARAPI_VERSION_FAILED_PANIC bool "Far API Version Check Failed to PANIC" default n @@ -76,6 +75,8 @@ endmenu # Far API Configuration comment "Timer Options" +menu "Timer Options" + menuconfig CXD56_RTC bool "Real Time Clock (RTC)" default y @@ -94,6 +95,74 @@ config CXD56_RTC_LATEINIT endif # CXD56_RTC +menuconfig CXD56_TIMER + bool "Timer" + default y + select TIMER + +if CXD56_TIMER + +choice + prompt "Timer divider selection" + default CXD56_TIMER_DIVIDER_1 + ---help--- + Timer divider selects 1, 16 or 256. The smaller the divider, the higher + time resolution, but the shorter the maximum time until wrap-around. + +config CXD56_TIMER_DIVIDER_1 + bool "Divider 1" + +config CXD56_TIMER_DIVIDER_16 + bool "Divider 16" + +config CXD56_TIMER_DIVIDER_256 + bool "Divider 256" + +endchoice +endif # CXD56_TIMER + +menuconfig CXD56_WDT + bool "Watchdog Timer (WDT)" + default y + select WATCHDOG + +if CXD56_WDT + +config CXD56_WDT_INTERRUPT + bool "Interrupt on timeout" + default y + ---help--- + This watchdog timer run 2 laps as long as the counter is not reloaded. + In the first lap, the watchdog interrupt occurs. Without interrupt + clear, The reset signal is asserted in the second timeout. This setting + enables the first interrupt. + +config CXD56_WDT_REGDEBUG + bool "Register level debug" + default n + ---help--- + Enable low-level register debug output + +endif # CXD56_WDT + +endmenu + +comment "Power Management Options" + +menuconfig CXD56_PM + bool "Power Management" + default y + +if CXD56_PM + +config CXD56_PM_PROCFS + bool "Power Management PROCFS support" + default n + ---help--- + Enable the power domain status or the clock frequency monitor. + +endif # CXD56_PM + comment "Peripheral Support" menu "Peripheral Support" @@ -297,6 +366,37 @@ config CXD56_USBDEV default n ---help--- Enables USB + +config CXD56_PWM + bool "PWM" + +if CXD56_PWM + +config CXD56_PWM0 + bool "PWM0" + default n + ---help--- + Enable PWM channel 0 + +config CXD56_PWM1 + bool "PWM1" + default n + ---help--- + Enable PWM channel 1 + +config CXD56_PWM2 + bool "PWM2" + default n + ---help--- + Enable PWM channel 2 + +config CXD56_PWM3 + bool "PWM3" + default n + ---help--- + Enable PWM channel 3 + +endif # CXD56_PWM endmenu comment "Storage Options" diff --git a/arch/arm/src/cxd56xx/Make.defs b/arch/arm/src/cxd56xx/Make.defs index 9afa5f6650..aad532cdda 100644 --- a/arch/arm/src/cxd56xx/Make.defs +++ b/arch/arm/src/cxd56xx/Make.defs @@ -99,6 +99,10 @@ CHIP_CSRCS += cxd56_powermgr.c CHIP_CSRCS += cxd56_farapi.c CHIP_CSRCS += cxd56_sysctl.c +ifeq ($(CONFIG_CXD56_PM_PROCFS),y) +CHIP_CSRCS += cxd56_powermgr_procfs.c +endif + ifeq ($(CONFIG_CXD56_RTC),y) CHIP_CSRCS += cxd56_rtc.c ifeq ($(CONFIG_RTC_DRIVER),y) @@ -129,3 +133,15 @@ endif ifeq ($(CONFIG_CXD56_DMAC),y) CHIP_CSRCS += cxd56_dmac.c endif + +ifeq ($(CONFIG_CXD56_PWM),y) +CHIP_CSRCS += cxd56_pwm.c +endif + +ifeq ($(CONFIG_CXD56_TIMER),y) +CHIP_CSRCS += cxd56_timer.c +endif + +ifeq ($(CONFIG_CXD56_WDT),y) +CHIP_CSRCS += cxd56_wdt.c +endif diff --git a/arch/arm/src/cxd56xx/cxd56_powermgr_procfs.c b/arch/arm/src/cxd56xx/cxd56_powermgr_procfs.c new file mode 100644 index 0000000000..3b219c1c71 --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_powermgr_procfs.c @@ -0,0 +1,794 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_powermgr_procfs.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. + * + ****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "cxd56_clock.h" +#include "cxd56_powermgr.h" +#include "up_arch.h" +#include "hardware/cxd56_crg.h" +#include "hardware/cxd5602_topreg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_CXD56_PM_DEBUG +# define pmerr(format, ...) _err(format, ##__VA_ARGS__) +# define pmwarn(format, ...) _warn(format, ##__VA_ARGS__) +# define pminfo(format, ...) _info(format, ##__VA_ARGS__) +#else +# define pmerr(x...) +# define pmwarn(x...) +# define pminfo(x...) +#endif + +#define PWD_STAT(val, shift) ((val >> shift) & 0x1) +#define DSP_NUM (6) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct cxd56_powermgr_procfs_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + int fileno; + int readcnt; +}; + +struct cxd56_powermgr_procfs_dir_s +{ + struct procfs_dir_priv_s base; /* Base directory private data */ + int index; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int cxd56_powermgr_procfs_open(FAR struct file *filep, + FAR const char *relpath, int oflags, mode_t mode); +static int cxd56_powermgr_procfs_close(FAR struct file *filep); +static ssize_t cxd56_powermgr_procfs_read(FAR struct file *filep, + FAR char *buffer, size_t buflen); +static int cxd56_powermgr_procfs_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int cxd56_powermgr_procfs_opendir(FAR const char *relpath, + FAR struct fs_dirent_s *dir); +static int cxd56_powermgr_procfs_closedir(FAR struct fs_dirent_s *dir); +static int cxd56_powermgr_procfs_readdir(struct fs_dirent_s *dir); +static int cxd56_powermgr_procfs_rewinddir(struct fs_dirent_s *dir); +static int cxd56_powermgr_procfs_stat(FAR const char *relpath, + FAR struct stat *buf); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +const struct procfs_operations cxd56_powermgr_procfs_operations = +{ + cxd56_powermgr_procfs_open, /* open */ + cxd56_powermgr_procfs_close, /* close */ + cxd56_powermgr_procfs_read, /* read */ + NULL, /* write */ + cxd56_powermgr_procfs_dup, /* dup */ + cxd56_powermgr_procfs_opendir, /* opendir */ + cxd56_powermgr_procfs_closedir, /* closedir */ + cxd56_powermgr_procfs_readdir, /* readdir */ + cxd56_powermgr_procfs_rewinddir, /* rewinddir */ + cxd56_powermgr_procfs_stat /* stat */ +}; + +static const struct procfs_entry_s g_powermgr_procfs1 = + {"pm**", &cxd56_powermgr_procfs_operations}; +static const struct procfs_entry_s g_powermgr_procfs2 = + {"pm/" , &cxd56_powermgr_procfs_operations}; +static FAR char *g_powermg_procfs_buffer; +static size_t g_powermg_procfs_size; +static size_t g_powermg_procfs_len; + +static const char* g_powermg_procfs_clock_source_name[] + = {"RCOSC", "SYSPLL", "XOSC", "RTC"}; +static const char* g_powermg_procfs_power_state[] + = {"-", "o"}; +static const char* g_powermg_procfs_dir[] + = {"clock", "power"}; +/**************************************************************************** + * Private Function + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_step_buffer + * + * Description: + * step buffer position + * + ****************************************************************************/ + +static void cxd56_powermgr_procfs_step_buffer(size_t len) +{ + DEBUGASSERT(g_powermg_procfs_size > (g_powermg_procfs_len + len)); + g_powermg_procfs_len = g_powermg_procfs_len + len; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_clock_base + * + * Description: + * collect clock base value + * + ****************************************************************************/ + +static void cxd56_powermgr_procfs_clock_base(void) +{ + uint32_t sys_clk_sel; + uint32_t app_clk_sel; + size_t len; + + /* Collect clock base value */ + + sys_clk_sel = getreg32(CXD56_TOPREG_CKSEL_ROOT) >> 22 & 0x3; + app_clk_sel = getreg32(CXD56_TOPREG_APP_CKSEL) >> 8 & 0x3; + + /* Store data in buffer */ + + len = snprintf(g_powermg_procfs_buffer + g_powermg_procfs_len, + g_powermg_procfs_size - g_powermg_procfs_len, + "Clock Source\n" + " SYS:%s\n" + " APP:%s\n\n", + g_powermg_procfs_clock_source_name[sys_clk_sel], + g_powermg_procfs_clock_source_name[app_clk_sel]); + + /* Step buffer position */ + + cxd56_powermgr_procfs_step_buffer(len); +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_clock + * + * Description: + * collect clock value + * + ****************************************************************************/ + +static void cxd56_powermgr_procfs_clock(void) +{ + size_t len; + uint32_t scu; + uint32_t hpadc; + uint32_t lpadc; + uint32_t gps; + uint32_t gpsahb; + uint32_t val; + uint32_t emmc; + int dsp; + uint32_t dsptabl[DSP_NUM]; + + /* collect clock value + * and store data in buffer + */ + + /* Check SCU clock status */ + + scu = cxd56_get_scu_baseclock(); + hpadc = cxd56_get_hpadc_baseclock(); + lpadc = cxd56_get_lpadc_baseclock(); + val = getreg32(CXD56_TOPREG_SYSIOP_CKEN); + if ((val & CKEN_BRG_SCU) != CKEN_BRG_SCU) + { + scu = 0; + hpadc = 0; + lpadc = 0; + } + + /* Check GPS clock status */ + + gps = cxd56_get_gps_cpu_baseclock(); + gpsahb = cxd56_get_gps_ahb_baseclock(); + val = getreg32(CXD56_TOPREG_GNSDSP_CKEN); + if (((val & GNSDSP_CKEN_P1) != GNSDSP_CKEN_P1) + && ((val & GNSDSP_CKEN_COP) != GNSDSP_CKEN_COP)) + { + gps = 0; + gpsahb = 0; + } + + /* Check DSP clock status */ + + val = getreg32(CXD56_CRG_CK_GATE_AHB); + val = (val >> 16) & 0x3f; + for (dsp = 0; dsp < DSP_NUM; dsp++) + { + if ((val & (1 << dsp)) == (1 << dsp)) + { + dsptabl[dsp] = cxd56_get_cpu_baseclk(); + } + else + { + dsptabl[dsp] = 0; + } + } + + val = getreg32(CXD56_CRG_CKEN_EMMC); + val = val & 0x7; + if (val == 0x7) + { + emmc = cxd56_get_cpu_baseclk(); + } + else + { + emmc = 0; + } + + len = snprintf(g_powermg_procfs_buffer + g_powermg_procfs_len, + g_powermg_procfs_size - g_powermg_procfs_len, + "Clock Status [Hz]\n" + " |-RTC : %9d"" |-APP : %9d\n" + " |-RCOSC : %9d"" ||-DSP0 : %9d\n" + " |-XOSC : %9d"" ||-DSP1 : %9d\n" + " |-SYSPLL : %9d"" ||-DSP2 : %9d\n" + " |-M0P : %9d"" ||-DSP3 : %9d\n" + " ||-AHB : %9d"" ||-DSP4 : %9d\n" + " | |-APB : %9d"" ||-DSP5 : %9d\n" + " |-UART1 : %9d"" ||-UART2 : %9d\n" + " |-SFC : %9d"" ||-SPI4 : %9d\n" + " |-SCU : %9d"" ||-SPI5 : %9d\n" + " ||-LPADC : %9d"" ||-USB : %9d\n" + " ||-HPADC : %9d"" ||-EMMC : %9d\n" + " |-I2C4 : %9d"" ||-SDIO : %9d\n" + " |-GPS : %9d"" ||-VSYNC : %9d\n" + " ||-AHB : %9d\n", + cxd56_get_rtc_clock(), cxd56_get_appsmp_baseclock(), + cxd56_get_rcosc_clock(), dsptabl[0], + cxd56_get_xosc_clock(), dsptabl[1], + cxd56_get_syspll_clock(), dsptabl[2], + cxd56_get_sys_baseclock(), dsptabl[3], + cxd56_get_sys_ahb_baseclock(), dsptabl[4], + cxd56_get_sys_apb_baseclock(), dsptabl[5], + cxd56_get_com_baseclock(), cxd56_get_img_uart_baseclock(), + cxd56_get_sys_sfc_baseclock(), cxd56_get_img_spi_baseclock(), + scu, cxd56_get_img_wspi_baseclock(), + lpadc, cxd56_get_usb_baseclock(), + hpadc, emmc, + cxd56_get_pmui2c_baseclock(), cxd56_get_sdio_baseclock(), + gps, cxd56_get_img_vsync_baseclock(), + gpsahb); + + /* Step buffer position */ + + cxd56_powermgr_procfs_step_buffer(len); +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_power_state + * + * Description: + * collect clock power state + * + ****************************************************************************/ + +static void cxd56_powermgr_procfs_power_state(void) +{ + uint32_t reg_pwd_stat; + uint32_t reg_ana_pw_stat; + uint32_t rf; + size_t len; + + /* Collect power status */ + + reg_pwd_stat = getreg32(CXD56_TOPREG_PWD_STAT); + reg_ana_pw_stat = getreg32(CXD56_TOPREG_ANA_PW_STAT); + + /* Check RF_xxx power status */ + + rf = reg_ana_pw_stat & 0x3f0; + if (rf != 0) + { + rf = 1; + } + + /* Store data in buffer */ + + len = snprintf(g_powermg_procfs_buffer + g_powermg_procfs_len, + g_powermg_procfs_size - g_powermg_procfs_len, + "Power Status\n" + "|-RCOSC : %s\n" + "|-XOSC : %s\n" + "|-SYSPLL : %s\n" + "|-SCU : %s\n" + "||-LPADC : %s\n" + "||-HPADC : %s\n" + "|-CORE : %s\n" + "||-GNSS_ITP : %s\n" + "||-SYSIOP : %s\n" + "| |-SYSIOP_SUB : %s\n" + "| |-GNSS : %s\n" + "| ||-RF : %s\n" + "| |-APP : %s\n" + "| ||-APP_DSP : %s\n" + "| ||-APP_SUB : %s\n" + "| ||-APP_AUD : %s\n", + g_powermg_procfs_power_state[PWD_STAT(reg_ana_pw_stat, 0)], + g_powermg_procfs_power_state[PWD_STAT(reg_ana_pw_stat, 1)], + g_powermg_procfs_power_state[PWD_STAT(reg_ana_pw_stat, 2)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 0)], + g_powermg_procfs_power_state[PWD_STAT(reg_ana_pw_stat, 13)], + g_powermg_procfs_power_state[PWD_STAT(reg_ana_pw_stat, 12)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 4)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 12)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 5)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 6)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 13)], + g_powermg_procfs_power_state[rf], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 8)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 9)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 10)], + g_powermg_procfs_power_state[PWD_STAT(reg_pwd_stat, 14)]); + + /* step buffer position */ + + cxd56_powermgr_procfs_step_buffer(len); +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_check_path + * + * Description: + * Check path power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_check_dir(char *relpath, + mode_t *mode, int *level, int *fileno) +{ + char *temp; + int ret = OK; + + *level = 0; + *mode = S_IFDIR; + *fileno = 0; + temp = strtok(relpath, "/"); + if (strncmp (temp, "pm", 3) == 0) + { + while ((temp = strtok (NULL, "/")) != NULL) + { + *level = *level + 1; + if (*level == 1) + { + if (strncmp(temp, g_powermg_procfs_dir[0], + strlen(g_powermg_procfs_dir[0])+1) == 0) + { + *mode = S_IFREG; + *fileno = 1; + } + else if (strncmp(temp, g_powermg_procfs_dir[1], + strlen(g_powermg_procfs_dir[1])+1) == 0) + { + *mode = S_IFREG; + *fileno = 2; + } + else + { + ret = -ENOENT; + break; + } + } + else + { + ret = -ENOENT; + break; + } + } + } + else + { + ret = -ENOENT; + } + + return ret; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_open + * + * Description: + * Request Open power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_open(FAR struct file *filep, + FAR const char *relpath, int oflags, mode_t mode) +{ + FAR struct cxd56_powermgr_procfs_file_s *priv; + int ret; + mode_t getmode; + int level; + int fileno; + char temp[16]; + + pminfo("Open '%s'\n", relpath); + + /* PROCFS is read-only. Any attempt to open with any kind of write + * access is not permitted. + * + * REVISIT: Write-able proc files could be quite useful. + */ + + if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)) + { + pmerr("ERROR: Only O_RDONLY supported\n"); + return -EACCES; + } + + memset(temp, 0, sizeof(temp)); + snprintf(temp, sizeof(temp)-1, "%s", relpath); + ret = cxd56_powermgr_procfs_check_dir(temp, &getmode, &level, &fileno); + + if (ret != OK) + { + return ret; + } + + /* Allocate the open file structure */ + + priv = (FAR struct cxd56_powermgr_procfs_file_s *) + kmm_zalloc(sizeof(struct cxd56_powermgr_procfs_file_s)); + if (!priv) + { + pmerr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + priv->fileno = fileno; + priv->readcnt = 0; + filep->f_priv = (void *)priv; + + return OK; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_close + * + * Description: + * Request Close power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_close(FAR struct file *filep) +{ + pminfo("Close\n"); + + DEBUGASSERT(filep->f_priv); + kmm_free(filep->f_priv); + filep->f_priv = NULL; + + return OK; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_read + * + * Description: + * Request Read power manager procfs + * + ****************************************************************************/ + +static ssize_t cxd56_powermgr_procfs_read(FAR struct file *filep, + FAR char *buffer, size_t buflen) +{ + size_t len; + FAR struct cxd56_powermgr_procfs_file_s *priv; + + pminfo("READ buffer=%p buflen=%lu len=%lu\n", buffer, + (unsigned long)buflen, g_powermg_procfs_len); + + DEBUGASSERT(filep && filep->f_priv); + + priv = (FAR struct cxd56_powermgr_procfs_file_s *)filep->f_priv; + + if (priv->fileno == 0) + { + /* pm directory */ + + return 0; + } + + if (priv->readcnt == 0) + { + /* Collect data and store data in buffer */ + + g_powermg_procfs_buffer = buffer; + g_powermg_procfs_size = buflen; + g_powermg_procfs_len = 0; + + if (priv->fileno == 1) + { + cxd56_powermgr_procfs_clock_base(); + cxd56_powermgr_procfs_clock(); + } + else + { + cxd56_powermgr_procfs_power_state(); + } + + len = g_powermg_procfs_len; + priv->readcnt++; + } + else + { + /* Indicate already provided all data */ + + len = 0; + priv->readcnt = 0; + } + + return len; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_dup + * + * Description: + * Request Dup power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_dup(FAR const struct file *oldp, + FAR struct file *newp) +{ + void *oldpriv; + void *newpriv; + + pminfo("Dup %p->%p\n", oldp, newp); + + /* Recover our private data from the old struct file instance */ + + oldpriv = oldp->f_priv; + DEBUGASSERT(oldpriv); + + /* Allocate a new container to hold the task and attribute selection */ + + newpriv = kmm_malloc(sizeof(struct cxd56_powermgr_procfs_file_s)); + if (!newpriv) + { + pmerr("ERROR: Failed to allocate file attributes\n"); + return -ENOMEM; + } + + /* The copy the file attributes from the old attributes to the new */ + + memcpy(newpriv, oldpriv, sizeof(struct cxd56_powermgr_procfs_file_s)); + + /* Save the new attributes in the new file structure */ + + newp->f_priv = newpriv; + + return OK; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_stat + * + * Description: + * Request Stat power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_stat(FAR const char *relpath, + FAR struct stat *buf) +{ + int ret; + mode_t mode; + int level; + int fileno; + char temp[16]; + + memset(temp, 0, sizeof(temp)); + snprintf(temp, sizeof(temp)-1, "%s", relpath); + ret = cxd56_powermgr_procfs_check_dir(temp, &mode, &level, &fileno); + + pminfo("Stat %s %d %d %d\n", relpath, mode, level, ret); + + buf->st_mode = mode | S_IROTH | S_IRGRP | S_IRUSR; + buf->st_size = 0; + buf->st_blksize = 0; + buf->st_blocks = 0; + + return ret; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_opendir + * + * Description: + * Request Opendir power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_opendir(FAR const char *relpath, + FAR struct fs_dirent_s *dir) +{ + FAR struct cxd56_powermgr_procfs_dir_s *procfs; + int ret; + mode_t mode; + int level; + int fileno; + char temp[16]; + + memset(temp, 0, sizeof(temp)); + snprintf(temp, sizeof(temp)-1, "%s", relpath); + ret = cxd56_powermgr_procfs_check_dir(temp, &mode, &level, &fileno); + + pminfo("Opendir '%s' %d %d\n", relpath, ret, level); + + if (ret != OK) + { + return ret; + } + if (level > 0) + { + return -ENOENT; + } + + procfs = (FAR struct cxd56_powermgr_procfs_dir_s *) + kmm_malloc(sizeof(struct cxd56_powermgr_procfs_dir_s)); + if (!procfs) + { + pmerr("ERROR: Failed to allocate dir attributes\n"); + return -ENOMEM; + } + + procfs->index = 0; + dir->u.procfs = (FAR void *)procfs; + + return OK; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_closedir + * + * Description: + * Request Closedir power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_closedir(FAR struct fs_dirent_s *dir) +{ + FAR struct smartfs_level1_s *priv; + + pminfo("Closedir\n"); + + DEBUGASSERT(dir && dir->u.procfs); + priv = dir->u.procfs; + + if (priv) + { + kmm_free(priv); + } + + dir->u.procfs = NULL; + return OK; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_readdir + * + * Description: + * Request Readdir power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_readdir(struct fs_dirent_s *dir) +{ + FAR struct cxd56_powermgr_procfs_dir_s *procfs; + + DEBUGASSERT(dir && dir->u.procfs); + + procfs = (FAR struct cxd56_powermgr_procfs_dir_s *)dir->u.procfs; + + pminfo("Readdir %d\n", procfs->index); + + if (procfs->index > ((sizeof(g_powermg_procfs_dir) + / sizeof(g_powermg_procfs_dir[0])) - 1)) + { + return -ENOENT; + } + + dir->fd_dir.d_type = DTYPE_FILE; + strncpy(dir->fd_dir.d_name, g_powermg_procfs_dir[procfs->index], + strlen(g_powermg_procfs_dir[procfs->index])+1); + procfs->index++; + + return OK; +} + +/**************************************************************************** + * Name: cxd56_powermgr_procfs_rewinddir + * + * Description: + * Request Rewind power manager procfs + * + ****************************************************************************/ + +static int cxd56_powermgr_procfs_rewinddir(struct fs_dirent_s *dir) +{ + FAR struct cxd56_powermgr_procfs_dir_s *procfs; + + DEBUGASSERT(dir && dir->u.procfs); + + procfs = (FAR struct cxd56_powermgr_procfs_dir_s *)dir->u.procfs; + pminfo("Rewind %d\n", procfs->index); + procfs->index = 0; + + return OK; +} + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_pm_initialize_procfs + * + * Description: + * Initialize power manager procfs + * + ****************************************************************************/ + +int cxd56_pm_initialize_procfs(void) +{ + int ret; + ret = procfs_register(&g_powermgr_procfs1); + if (ret < 0) + return -EPERM; + ret = procfs_register(&g_powermgr_procfs2); + if (ret < 0) + return -EPERM; + return ret; +} diff --git a/arch/arm/src/cxd56xx/cxd56_powermgr_procfs.h b/arch/arm/src/cxd56xx/cxd56_powermgr_procfs.h new file mode 100644 index 0000000000..9a55b5cb38 --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_powermgr_procfs.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_timerisr.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_CXD56XX_CXD56_POWERMGR_PROCFS_H +#define __ARCH_ARM_SRC_CXD56XX_CXD56_POWERMGR_PROCFS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_pm_initialize_procfs + * + * Description: + * Initialize power manager procfs + * + ****************************************************************************/ + +int cxd56_pm_initialize_procfs(void); + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_CXD56XX_CXD56_POWERMGR_PROCFS_H */ diff --git a/arch/arm/src/cxd56xx/cxd56_pwm.c b/arch/arm/src/cxd56xx/cxd56_pwm.c new file mode 100644 index 0000000000..db3fcd9918 --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_pwm.c @@ -0,0 +1,495 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_pwm.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 +#include + +#include "chip.h" +#include "up_arch.h" + +#include "cxd56_pinconfig.h" +#include "cxd56_clock.h" +#include "cxd56_pwm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PWM_REG_BASE (0x04195600) +#define PWM_PHASE_REG_BASE (0x04195630) + +#define PWM_REG(ch) \ + ( \ + (PWM_REG_t*)(PWM_REG_BASE + (sizeof(PWM_REG_t) * (ch))) \ + ) + +#define PWM_PHASE_REG(ch) \ + ( \ + (PWM_PHASE_REG_t*) \ + (PWM_PHASE_REG_BASE + (sizeof(PWM_PHASE_REG_t) * (ch))) \ + ) + +#define PWM_PARAM_OFFPERIOD_SHIFT (16) + +#ifndef itemsof +# define itemsof(array) (sizeof(array)/sizeof(array[0])) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the state of one PWM channel */ + +struct cxd56_pwm_chan_s +{ + const struct pwm_ops_s *ops; /* PWM operations */ + uint8_t ch; /* PWM channel: {0..3} */ + uint8_t prescale; /* prescale (reserved) */ +}; + +typedef struct +{ + volatile uint32_t PARAM; + volatile uint32_t EN; + volatile uint32_t UPDATE; +} PWM_REG_t; + +typedef struct +{ + volatile uint32_t PHASE; +} PWM_PHASE_REG_t; + +/**************************************************************************** + * Static Function Prototypes + ****************************************************************************/ + +/* PWM driver methods */ + +static int pwm_setup(FAR struct pwm_lowerhalf_s *dev); +static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev); +static int pwm_start(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info); +static int pwm_stop(FAR struct pwm_lowerhalf_s *dev); +static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the list of lower half PWM driver methods used by the upper half + * driver + */ + +static const struct pwm_ops_s g_pwmops = +{ + .setup = pwm_setup, + .shutdown = pwm_shutdown, + .start = pwm_start, + .stop = pwm_stop, + .ioctl = pwm_ioctl, +}; + +#ifdef CONFIG_CXD56_PWM0 +static struct cxd56_pwm_chan_s g_pwm_ch0 = +{ + .ops = &g_pwmops, + .ch = CXD56_PWM_CH0, + .prescale = 0, +}; +#endif + +#ifdef CONFIG_CXD56_PWM1 +static struct cxd56_pwm_chan_s g_pwm_ch1 = +{ + .ops = &g_pwmops, + .ch = CXD56_PWM_CH1, + .prescale = 0, +}; +#endif + +#ifdef CONFIG_CXD56_PWM2 +static struct cxd56_pwm_chan_s g_pwm_ch2 = +{ + .ops = &g_pwmops, + .ch = CXD56_PWM_CH2, + .prescale = 0, +}; +#endif + +#ifdef CONFIG_CXD56_PWM3 +static struct cxd56_pwm_chan_s g_pwm_ch3 = +{ + .ops = &g_pwmops, + .ch = CXD56_PWM_CH3, + .prescale = 0, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pwm_pin_config + * + * Description: + * Configure PWM pin + * + * Input Parameters: + * channel - pwm channel number. + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int pwm_pin_config(uint32_t channel) +{ + int ret = 0; + uint32_t pingroupa[] = PINCONFS_PWMA; + uint32_t pingroupb[] = PINCONFS_PWMB; + + if ((channel == CXD56_PWM_CH0) || (channel == CXD56_PWM_CH1)) + { + ret = cxd56_pin_configs(pingroupa, itemsof(pingroupa)); + } + else + { + ret = cxd56_pin_configs(pingroupb, itemsof(pingroupb)); + } + + return ret; +} + +/**************************************************************************** + * Name: convert_freq2period + * + * Description: + * Convert frequency and duty to period and offperiod of param register. + * + * Input Parameters: + * freq - pwm frequency [Hz] + * duty - duty + * + * Output Parameters: + * param - set value of PWM_PARAM register + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int convert_freq2period(uint32_t freq, ub16_t duty, uint32_t *param) +{ + DEBUGASSERT(param); + + uint32_t pwmfreq = 0; + uint32_t period = 0; + uint32_t offperiod = 0; + + /* Get frequency of pwm base clock */ + + pwmfreq = cxd56_get_pwm_baseclock(); + if (pwmfreq == 0) + { + pwmerr("Unknown pwm frequency\n"); + return -1; + } + + /* check frequency range */ + + if ((freq > ((pwmfreq + 1) >> 1)) || (freq < (pwmfreq >> 16))) + { + pwmerr("Frequency out of range. %d [Effective range:%d - %d]\n", + freq, pwmfreq >> 16, (pwmfreq + 1) >> 1); + return -1; + } + + /* check duty range */ + + if ((duty < 0x00000001) || (duty > 0x0000ffff)) + { + pwmerr("Duty out of range. %d\n", duty); + return -1; + } + + /* calcurate period and offperiod */ + + period = (pwmfreq * 10 / freq - 5) / 10; + if (period > 0xffff) + { + period = 0xffff; + } + offperiod = ((0x10000 - duty) * (period + 1) + 0x8000) >> 16; + if (offperiod == 0) + { + offperiod = 0; + } + else if (period < offperiod) + { + offperiod = period; + } + *param = (period & 0xffff) | + ((offperiod & 0xffff) << PWM_PARAM_OFFPERIOD_SHIFT); + + return OK; +} + +/**************************************************************************** + * Name: pwm_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int pwm_setup(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct cxd56_pwm_chan_s *priv = (FAR struct cxd56_pwm_chan_s *)dev; + int ret; + + ret = pwm_pin_config(priv->ch); + if (ret < 0) + { + pwmerr("Failed to pinconf():%d\n", channel); + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Name: pwm_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev) +{ + return OK; +} + +/**************************************************************************** + * Name: pwm_start + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int pwm_start(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info) +{ + FAR struct cxd56_pwm_chan_s *priv = (FAR struct cxd56_pwm_chan_s *)dev; + uint32_t param; + int ret; + + if (info->duty <= 0) + { + /* Output low level if duty cycle is almost 0% */ + + PWM_REG(priv->ch)->EN = 0x0; + } + else if (info->duty >= 65536) + { + /* Output high level if duty cycle is almost 100% */ + + PWM_REG(priv->ch)->PARAM = 1; + PWM_REG(priv->ch)->EN = 0x1; + } + else + { + ret = convert_freq2period(info->frequency, info->duty, ¶m); + if (ret < 0) + { + return -EINVAL; + } + + if (PWM_REG(priv->ch)->EN & 1) + { + /* Change duty cycle dynamically if already running */ + + PWM_REG(priv->ch)->PARAM = param; + return OK; + } + + PWM_REG(priv->ch)->EN = 0x0; + PWM_REG(priv->ch)->PARAM = param; + + /* Since prescale is not supported, always set to a fixed value '0' */ + + PWM_PHASE_REG(priv->ch)->PHASE = 0x0; + + PWM_REG(priv->ch)->EN = 0x1; + } + + return OK; +} + +/**************************************************************************** + * Name: pwm_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int pwm_stop(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct cxd56_pwm_chan_s *priv = (FAR struct cxd56_pwm_chan_s *)dev; + + PWM_REG(priv->ch)->EN = 0x0; + + return OK; +} + +/**************************************************************************** + * Name: pwm_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input parameters: + * dev - A reference to the lower half PWM driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * OK on success; A negated errno value on failure. + * + ****************************************************************************/ + +static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_pwminitialize + * + * Description: + * Initialize PWM channel for use with the upper_level PWM driver. + * + * Input Parameters: + * channel - pwm channel number. + * + * Returned Value: + * On success, a pointer to the CXD56 lower half PWM driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct pwm_lowerhalf_s *cxd56_pwminitialize(uint32_t channel) +{ + FAR struct cxd56_pwm_chan_s *pwmch; + + switch (channel) + { +#ifdef CONFIG_CXD56_PWM0 + case CXD56_PWM_CH0: + pwmch = &g_pwm_ch0; + break; +#endif +#ifdef CONFIG_CXD56_PWM1 + case CXD56_PWM_CH1: + pwmch = &g_pwm_ch1; + break; +#endif +#ifdef CONFIG_CXD56_PWM2 + case CXD56_PWM_CH2: + pwmch = &g_pwm_ch2; + break; +#endif +#ifdef CONFIG_CXD56_PWM3 + case CXD56_PWM_CH3: + pwmch = &g_pwm_ch3; + break; +#endif + default: + pwmerr("Illeagal channel number:%d\n", channel); + return NULL; + } + + return (FAR struct pwm_lowerhalf_s *)pwmch; +} diff --git a/arch/arm/src/cxd56xx/cxd56_pwm.h b/arch/arm/src/cxd56xx/cxd56_pwm.h new file mode 100644 index 0000000000..26f32f6b90 --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_pwm.h @@ -0,0 +1,103 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_pwm.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 __ARCH_ARM_SRC_CXD56XX_CXD56_PWM_H +#define __ARCH_ARM_SRC_CXD56XX_CXD56_PWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* PWM channel definitions **************************************************/ + +#define CXD56_PWM_CH0 0 +#define CXD56_PWM_CH1 1 +#define CXD56_PWM_CH2 2 +#define CXD56_PWM_CH3 3 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_pwminitialize + * + * Description: + * Initialize PWM channel for use with the upper_level PWM driver. + * + * Input Parameters: + * channel - pwm channel number. + * + * Returned Value: + * On success, a pointer to the CXD56 lower half PWM driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct pwm_lowerhalf_s *cxd56_pwminitialize(uint32_t channel); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_CXD56XX_CXD56_PWM_H */ diff --git a/arch/arm/src/cxd56xx/cxd56_timer.c b/arch/arm/src/cxd56xx/cxd56_timer.c new file mode 100644 index 0000000000..9bd80da154 --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_timer.c @@ -0,0 +1,583 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_timer.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 + +#include +#include +#include +#include + +#include "up_arch.h" +#include "cxd56_timer.h" +#include "hardware/cxd56_timer.h" +#include "cxd56_clock.h" + +#ifdef CONFIG_TIMER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Timer divider definitions */ + +#if defined(CONFIG_CXD56_TIMER_DIVIDER_1) +#define TIMER_DIVIDER (1) +#define TIMERCTRL_DIV (TIMERCTRL_DIV_1) +#elif defined(CONFIG_CXD56_TIMER_DIVIDER_16) +#define TIMER_DIVIDER (16) +#define TIMERCTRL_DIV (TIMERCTRL_DIV_16) +#elif defined(CONFIG_CXD56_TIMER_DIVIDER_256) +#define TIMER_DIVIDER (256) +#define TIMERCTRL_DIV (TIMERCTRL_DIV_256) +#else +#define TIMER_DIVIDER (16) +#define TIMERCTRL_DIV (TIMERCTRL_DIV_16) +#endif + +/* e.g.) When the timer divider is 16, timer's max clock is about 10MHz + * (Divide max 160MHz resolution by 16) and the timer has 32bit counter. + * Therefore, the max counter is the following value to avoid counter + * wrap around. Timer's base clock is dynamically changed with cpu clock. + */ + +#define TIMER_MAXTIMEOUT (ULONG_MAX / 160 / TIMER_DIVIDER) + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * timer_lowerhalf_s structure. + */ + +struct cxd56_lowerhalf_s +{ + FAR const struct timer_ops_s *ops; /* Lower half operations */ + + /* Private data */ + + uint32_t base; /* Base address of the timer */ + tccb_t callback; /* Current user interrupt callback */ + FAR void *arg; /* Argument passed to upper half callback */ + uint32_t timeout; /* The current timeout value (us) */ + uint32_t clkticks; /* actual clock ticks for current interval */ + bool started; /* The timer has been started */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Interrupt handling *******************************************************/ + +static int cxd56_timer_interrupt(int irq, FAR void *context, + FAR void *arg); + +/* "Lower half" driver methods **********************************************/ + +static int cxd56_start(FAR struct timer_lowerhalf_s *lower); +static int cxd56_stop(FAR struct timer_lowerhalf_s *lower); +static int cxd56_getstatus(FAR struct timer_lowerhalf_s *lower, + FAR struct timer_status_s *status); +static int cxd56_settimeout(FAR struct timer_lowerhalf_s *lower, + uint32_t timeout); +static void cxd56_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, FAR void *arg); +static int cxd56_ioctl(FAR struct timer_lowerhalf_s *lower, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct timer_ops_s g_tmrops = +{ + .start = cxd56_start, + .stop = cxd56_stop, + .getstatus = cxd56_getstatus, + .settimeout = cxd56_settimeout, + .setcallback = cxd56_setcallback, + .ioctl = cxd56_ioctl, +}; + +/* "Lower half" driver state */ + +static struct cxd56_lowerhalf_s g_tmrdevs[2]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_timer_interrupt + * + * Description: + * TC interrupt + * + * Input Parameters: + * Usual interrupt callback arguments. + * + * Returned Values: + * Always returns OK. + * + ****************************************************************************/ + +static int cxd56_timer_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)arg; + uint32_t timeout; + uint32_t load; + + tmrinfo("Entry\n"); + DEBUGASSERT((irq >= CXD56_IRQ_TIMER0) && (irq <= CXD56_IRQ_TIMER1)); + + /* Is there a registered callback? If the callback has been + * nullified, the timer will be stopped. + */ + + timeout = priv->timeout; + if (priv->callback && priv->callback(&timeout, priv->arg)) + { + if (timeout != priv->timeout) + { + /* Change period dynamically */ + + priv->timeout = timeout; + load = + (((uint64_t)timeout * priv->clkticks) / TIMER_DIVIDER / 1000000); + putreg32(load, priv->base + CXD56_TIMER_LOAD); + } + } + else + { + /* No callback or the callback returned false.. stop the timer */ + + cxd56_stop((FAR struct timer_lowerhalf_s *)priv); + tmrinfo("Stopped\n"); + } + + /* Clear the interrupts */ + + putreg32(TIMER_INTERRUPT, priv->base + CXD56_TIMER_INTCLR); + + return OK; +} + +/**************************************************************************** + * Name: cxd56_start + * + * Description: + * Start the timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_start(FAR struct timer_lowerhalf_s *lower) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + + tmrinfo("Entry: started %d\n", priv->started); + + /* Has the timer already been started? */ + + if (!priv->started) + { + uint32_t ctrl = (TIMERCTRL_ENABLE | TIMERCTRL_DIV | + TIMERCTRL_SIZE_32BIT | TIMERCTRL_MODE_WRAP); + + if (priv->timeout) + { + ctrl |= (TIMERCTRL_PERIODIC | TIMERCTRL_INTENABLE); + } + else + { + ctrl |= (TIMERCTRL_FREERUN | TIMERCTRL_INTDISABLE); + } + + /* Start the timer */ + + putreg32(ctrl, priv->base + CXD56_TIMER_CONTROL); + + priv->started = true; + return OK; + } + + /* Return EBUSY to indicate that the timer was already running */ + + return -EBUSY; +} + +/**************************************************************************** + * Name: cxd56_stop + * + * Description: + * Stop the timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_stop(FAR struct timer_lowerhalf_s *lower) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + + tmrinfo("Entry: started %d\n", priv->started); + + /* Has the timer already been started? */ + + if (priv->started) + { + /* Stop the timer */ + + putreg32(0, priv->base + CXD56_TIMER_CONTROL); + + /* Clear interrupt just in case */ + + putreg32(TIMER_INTERRUPT, priv->base + CXD56_TIMER_INTCLR); + + priv->started = false; + return OK; + } + + /* Return ENODEV to indicate that the timer was not running */ + + return -ENODEV; +} + +/**************************************************************************** + * Name: cxd56_getstatus + * + * Description: + * Get the current timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower- + * half" driver state structure. + * status - The location to return the status information. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_getstatus(FAR struct timer_lowerhalf_s *lower, + FAR struct timer_status_s *status) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + uint64_t remaining; + + tmrinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Return the status bit */ + + status->flags = 0; + if (priv->started) + { + status->flags |= TCFLAGS_ACTIVE; + } + + if (priv->callback) + { + status->flags |= TCFLAGS_HANDLER; + } + + /* Return the actual timeout in microseconds */ + + status->timeout = priv->timeout; + + /* Get the time remaining until the timer expires (in microseconds). */ + + remaining = (uint64_t)getreg32(priv->base + CXD56_TIMER_VALUE); + status->timeleft = + (uint32_t)(remaining * 1000000ULL * TIMER_DIVIDER / priv->clkticks); + + tmrinfo(" flags : %08x\n", status->flags); + tmrinfo(" timeout : %d\n", status->timeout); + tmrinfo(" timeleft : %d\n", status->timeleft); + return OK; +} + +/**************************************************************************** + * Name: cxd56_settimeout + * + * Description: + * Set a new timeout value (and reset the timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower + * half" driver state structure. + * timeout - The new timeout value in milliseconds. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_settimeout(FAR struct timer_lowerhalf_s *lower, + uint32_t timeout) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + uint32_t load; + + DEBUGASSERT(priv); + + if (priv->started) + { + return -EPERM; + } + + tmrinfo("Entry: timeout=%d\n", timeout); + + /* Can this timeout be represented? */ + + if (timeout < 1 || timeout > TIMER_MAXTIMEOUT) + { + tmrerr("ERROR: Cannot represent timeout=%lu > %lu\n", timeout, + TIMER_MAXTIMEOUT); + return -ERANGE; + } + + /* Intended timeout */ + + priv->timeout = timeout; + + /* Actual clock ticks */ + + priv->clkticks = cxd56_get_cpu_baseclk(); + + load = (((uint64_t)timeout * priv->clkticks) / TIMER_DIVIDER / 1000000); + putreg32(load, priv->base + CXD56_TIMER_LOAD); + modifyreg32(priv->base + CXD56_TIMER_CONTROL, 0, + TIMERCTRL_PERIODIC | TIMERCTRL_INTENABLE); + + tmrinfo("clkticks=%d timeout=%d load=%d\n", priv->clkticks, priv->timeout, + load); + + return OK; +} + +/**************************************************************************** + * Name: cxd56_setcallback + * + * Description: + * Call this user provided timeout callback. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * newhandler - The new timer expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * + * Returned Values: + * The previous timer expiration function pointer or NULL is there was + * no previous function pointer. + * + ****************************************************************************/ + +static void cxd56_setcallback(struct timer_lowerhalf_s *lower, + tccb_t callback, FAR void *arg) +{ + FAR struct cxd56_lowerhalf_s *priv = (struct cxd56_lowerhalf_s *)lower; + irqstate_t flags; + + flags = enter_critical_section(); + + DEBUGASSERT(priv); + tmrinfo("Entry: callback=%p\n", callback); + + /* Save the new callback and argument */ + + priv->callback = callback; + priv->arg = arg; + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: cxd56_ioctl + * + * Description: + * Any ioctl commands that are not recognized by the "upper-half" driver + * are forwarded to the lower half driver through this method. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * cmd - The ioctl command value + * arg - The optional argument that accompanies the 'cmd'. The + * interpretation of this argument depends on the particular + * command. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_ioctl(FAR struct timer_lowerhalf_s *lower, int cmd, + unsigned long arg) +{ + int ret = -ENOTTY; + + tmrinfo("Entry: cmd=%d arg=%ld\n", cmd, arg); + + /* Handle ioctl commands */ + + switch (cmd) + { + /* cmd: TCIOC_SETHANDLER + * Description: Set interrupt callback function + * Argument: A pointer to struct timer_sethandler_s + */ + + case TCIOC_SETHANDLER: + { + FAR struct timer_sethandler_s *param; + + /* Set user provided timeout callback function */ + + param = (FAR struct timer_sethandler_s *)((uintptr_t)arg); + + if (param != NULL) + { + cxd56_setcallback(lower, param->handler, param->arg); + ret = OK; + } + else + { + ret = -EINVAL; + } + } + break; + default: + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_timer_initialize + * + * Description: + * Initialize the timer. The timer is initialized and + * registers as 'devpath'. + * + * Input Parameters: + * devpath - The full path to the timer. This should be of the form + * /dev/timer0 + * timer - the timer's number. + * + * Returned Values: + * None + * + ****************************************************************************/ + +void cxd56_timer_initialize(FAR const char *devpath, int timer) +{ + FAR struct cxd56_lowerhalf_s *priv = &g_tmrdevs[timer]; + int irq; + + tmrinfo("Entry: devpath=%s\n", devpath); + DEBUGASSERT((timer >= CXD56_TIMER0) && (timer <= CXD56_TIMER1)); + + /* Initialize the driver state structure. Here we assume: (1) the state + * structure lies in .bss and was zeroed at reset time. (2) This function + * is only called once so it is never necessary to re-zero the structure. + */ + + switch (timer) + { + case CXD56_TIMER0: + priv->base = CXD56_TIMER0_BASE; + irq = CXD56_IRQ_TIMER0; + tmrinfo("Using: Timer 0"); + break; + + case CXD56_TIMER1: + priv->base = CXD56_TIMER1_BASE; + irq = CXD56_IRQ_TIMER1; + tmrinfo("Using: Timer 1"); + break; + + default: + ASSERT(0); + } + + priv->ops = &g_tmrops; + + (void)irq_attach(irq, cxd56_timer_interrupt, priv); + + /* Enable NVIC interrupt. */ + + up_enable_irq(irq); + + /* Register the timer driver as /dev/timerX */ + + (void)timer_register(devpath, (FAR struct timer_lowerhalf_s *)priv); +} + +#endif /* CONFIG_TIMER */ diff --git a/arch/arm/src/cxd56xx/cxd56_timer.h b/arch/arm/src/cxd56xx/cxd56_timer.h new file mode 100644 index 0000000000..b7c666367d --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_timer.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_timer.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 __ARCH_ARM_SRC_CXD56XX_CXD56_TIMER_H +#define __ARCH_ARM_SRC_CXD56XX_CXD56_TIMER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_TIMER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Channel ******************************************************************/ + +#define CXD56_TIMER0 (0) +#define CXD56_TIMER1 (1) +#define CXD56_TIMER_NUM (2) + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_timer_initialize + * + * Description: + * Initialize the timer. The timer is initialized and + * registers as 'devpath. The initial state of the timer is + * disabled. + * + * Input Parameters: + * devpath - The full path to the timer. This should be of the form + * /dev/timer0 + * timer - the timer's number. + * + * Returned Values: + * None + * + ****************************************************************************/ + +void cxd56_timer_initialize(FAR const char *devpath, int timer); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_TIMER */ +#endif /* __ARCH_ARM_SRC_CXD56XX_CXD56_TIMER_H */ diff --git a/arch/arm/src/cxd56xx/cxd56_wdt.c b/arch/arm/src/cxd56xx/cxd56_wdt.c new file mode 100644 index 0000000000..25c828efdc --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_wdt.c @@ -0,0 +1,690 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_wdt.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 +#ifdef CONFIG_DEBUG_FEATURES +#include +#endif +#include + +#include +#include + +#include +#include +#include + +#include "up_arch.h" +#include "cxd56_clock.h" +#include "cxd56_wdt.h" +#include "cxd56_powermgr.h" + +#ifdef CONFIG_CXD56_WDT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Select the path to the registered watchdog timer device */ + +#ifdef CONFIG_WATCHDOG_DEVPATH +#define DEVPATH CONFIG_WATCHDOG_DEVPATH +#else +#define DEVPATH "/dev/watchdog0" +#endif + +/* watchdog timeout maximum value */ + +#define WDT_MAX_TIMEOUT (40000) /* 40 sec */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * well-known watchdog_lowerhalf_s structure. + */ + +struct cxd56_lowerhalf_s +{ + FAR const struct watchdog_ops_s *ops; /* Lower half operations */ +#ifdef CONFIG_CXD56_WDT_INTERRUPT + xcpt_t handler; /* Current WDT interrupt handler */ +#endif + uint32_t timeout; /* The actual timeout value (milliseconds) */ + uint32_t reload; /* The 32-bit watchdog reload value */ + bool started; /* The timer has been started */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations */ + +#if defined(CONFIG_CXD56_WDT_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES) +static uint32_t cxd56_getreg(uintptr_t regaddr); +static void cxd56_putreg(uint32_t regval, uintptr_t regaddr); +#else +# define cxd56_getreg(regaddr) getreg32(regaddr) +# define cxd56_putreg(regval, regaddr) putreg32(regval, regaddr) +#endif + +/* Interrupt hanlding *******************************************************/ + +#ifdef CONFIG_CXD56_WDT_INTERRUPT +static int cxd56_wdtinterrupt(int irq, FAR void *context, FAR void *arg); +#endif + +/* "Lower half" driver methods **********************************************/ + +static int cxd56_start(FAR struct watchdog_lowerhalf_s *lower); +static int cxd56_stop(FAR struct watchdog_lowerhalf_s *lower); +static int cxd56_keepalive(FAR struct watchdog_lowerhalf_s *lower); +static int cxd56_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status); +static int cxd56_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout); +static xcpt_t cxd56_capture(FAR struct watchdog_lowerhalf_s *lower, + xcpt_t handler); +static int cxd56_ioctl(FAR struct watchdog_lowerhalf_s *lower, int cmd, + unsigned long arg); +static int cxd56_pm_event(uint8_t id); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct watchdog_ops_s g_wdgops = +{ + .start = cxd56_start, + .stop = cxd56_stop, + .keepalive = cxd56_keepalive, + .getstatus = cxd56_getstatus, + .settimeout = cxd56_settimeout, + .capture = cxd56_capture, + .ioctl = cxd56_ioctl, +}; + +/* "Lower half" driver state */ + +static struct cxd56_lowerhalf_s g_wdtdev; + +/* pm handle */ + +static void *pmhandle = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_getreg + * + * Description: + * Get the contents of an CXD56 register + * + ****************************************************************************/ + +# if defined(CONFIG_CXD56_WDT_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES) +static uint32_t cxd56_getreg(uintptr_t regaddr) +{ + static uint32_t prevaddr = 0; + static uint32_t count = 0; + static uint32_t preval = 0; + + /* Read the value from the register */ + + uint32_t regval = getreg32(regaddr); + + /* Is this the same value that we read from the same registe last time? Are + * we polling the register? If so, suppress some of the output. + */ + + if (regaddr == prevaddr && regval == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + logdebug("...\n"); + } + + return regval; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + logdebug("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = regaddr; + preval = regval; + count = 1; + } + + /* Show the register value read */ + + logdebug("%08x->%08\n", regaddr, regval); + return regval; +} +#endif + +/**************************************************************************** + * Name: cxd56_putreg + * + * Description: + * Set the contents of an CXD56 register to a value + * + ****************************************************************************/ + +#if defined(CONFIG_CXD56_WDT_REGDEBUG) && defined(CONFIG_DEBUG_FEATURES) +static void cxd56_putreg(uint32_t regval, uintptr_t regaddr) +{ + /* Show the register value being written */ + + logdebug("%08x<-%08x\n", regaddr, regval); + + /* Write the value */ + + putreg32(regval, regaddr); +} +#endif + +/**************************************************************************** + * Name: cxd56_wdtinterrupt + * + * Description: + * WDT early warning interrupt + * + * Input Parameters: + * Usual interrupt handler arguments. + * + * Returned Values: + * Always returns OK. + * + ****************************************************************************/ + +#ifdef CONFIG_CXD56_WDT_INTERRUPT +static int cxd56_wdtinterrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct cxd56_lowerhalf_s *priv = arg; + + /* Is there a registered handler? */ + + if (priv->handler) + { + /* Yes... NOTE: This interrupt service routine (ISR) must reload + * the WDT counter to prevent the reset. Otherwise, we will reset + * upon return. + */ + + priv->handler(irq, context, NULL); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: cxd56_start + * + * Description: + * Start the watchdog timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_start(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + + wdinfo("Entry\n"); + + cxd56_putreg(WDOGLOCK_UNLOCK_KEY, CXD56_WDT_WDOGLOCK); + cxd56_putreg(WDOGCONTROL_RESEN | WDOGCONTROL_INTEN, CXD56_WDT_WDOGCONTROL); + cxd56_putreg(0, CXD56_WDT_WDOGLOCK); + + priv->started = true; + return OK; +} + +/**************************************************************************** + * Name: cxd56_stop + * + * Description: + * Stop the watchdog timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_stop(FAR struct watchdog_lowerhalf_s *lower) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + + wdinfo("Entry\n"); + cxd56_putreg(WDOGLOCK_UNLOCK_KEY, CXD56_WDT_WDOGLOCK); + cxd56_putreg(WDOGCONTROL_STOP, CXD56_WDT_WDOGCONTROL); + priv->started = false; + return OK; +} + +/**************************************************************************** + * Name: cxd56_keepalive + * + * Description: + * Reset the watchdog timer to the current timeout value, prevent any + * imminent watchdog timeouts. This is sometimes referred as "pinging" + * the atchdog timer or "petting the dog". + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_keepalive(FAR struct watchdog_lowerhalf_s *lower) +{ + wdinfo("Entry\n"); + cxd56_putreg(WDOGLOCK_UNLOCK_KEY, CXD56_WDT_WDOGLOCK); + cxd56_putreg(0, CXD56_WDT_WDOGINTCLR); /* reload by write any value */ + cxd56_putreg(0, CXD56_WDT_WDOGLOCK); + return OK; +} + +/**************************************************************************** + * Name: cxd56_getstatus + * + * Description: + * Get the current watchdog timer status + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * stawtus - The location to return the watchdog status information. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_getstatus(FAR struct watchdog_lowerhalf_s *lower, + FAR struct watchdog_status_s *status) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + uint64_t remain; + + wdinfo("Entry\n"); + DEBUGASSERT(priv); + + /* Return the status bit */ + + status->flags = WDFLAGS_RESET; + if (priv->started) + { + status->flags |= WDFLAGS_ACTIVE; + } + +#ifdef CONFIG_CXD56_WDT_INTERRUPT + if (priv->handler) + { + status->flags |= WDFLAGS_CAPTURE; + } +#endif + + /* Return the actual timeout is milliseconds */ + + status->timeout = priv->timeout; + + /* Get the time remaining until the watchdog expires (in miliseconds) */ + + remain = (uint64_t)cxd56_getreg(CXD56_WDT_WDOGVALUE); + status->timeleft = (uint32_t)(remain * 1000 / cxd56_get_cpu_baseclk()); + if (cxd56_getreg(CXD56_WDT_WDOGRIS) != WDOGRIS_RAWINT) + { + status->timeleft += status->timeout / 2; + } + + wdinfo("Status :\n"); + wdinfo(" flags : %08x\n", status->flags); + wdinfo(" timeout : %d\n", status->timeout); + wdinfo(" timeleft : %d\n", status->timeleft); + return OK; +} + +/**************************************************************************** + * Name: cxd56_settimeout + * + * Description: + * Set a new timeout value (and reset the watchdog timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * timeout - The new timeout value in millisecnds. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_settimeout(FAR struct watchdog_lowerhalf_s *lower, + uint32_t timeout) +{ + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + uint32_t reload; + uint32_t freq; + uint64_t llreload; + + DEBUGASSERT(priv); + wdinfo("Entry: timeout=%d\n", timeout); + + if ((timeout == 0) || (timeout > WDT_MAX_TIMEOUT)) + { + return -EINVAL; + } + + /* Calculate the reload value to achiee this (appoximate) timeout. */ + + freq = cxd56_get_cpu_baseclk(); + + if (!freq) + { + return -EIO; + } + + llreload = ((uint64_t)freq * (uint64_t)timeout + 500) / 1000; + + /* Actual register value is half of timeout value because watchdog makes + * two laps until reset signal is asserted. At 1st lap, interrupt signal + * is asserted. At 2nd lap, reset signal is asserted. + */ + + llreload /= 2; + + if (llreload >> 32) + { + return -ERANGE; + } + + reload = (uint32_t)llreload; + + /* Calculate and save the actual timeout value in milliseconds */ + + priv->timeout = (uint32_t)((llreload * 1000 + freq / 2) / freq) * 2; + + /* Remember the selected values */ + + priv->reload = reload; + + wdinfo("reload=%u timout: %d->%d\n", reload, timeout, priv->timeout); + + /* Set the WDT register according to calculated value */ + + cxd56_putreg(WDOGLOCK_UNLOCK_KEY, CXD56_WDT_WDOGLOCK); + cxd56_putreg(reload, CXD56_WDT_WDOGLOAD); + cxd56_putreg(WDOGCONTROL_RESEN | WDOGCONTROL_INTEN, CXD56_WDT_WDOGCONTROL); + cxd56_putreg(0, CXD56_WDT_WDOGLOCK); + + priv->started = true; + + return OK; +} + +/**************************************************************************** + * Name: cxd56_capture + * + * Description: + * Don't reset on watchdog timer timeout; instead, call this user provider + * timeout handler. NOTE: Providing handler==NULL will restore the reset + * behavior. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * newhandler - The new watchdog expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * + * Returned Values: + * The previous watchdog expiration function pointer or NULL is there was + * no previous function pointer, i.e., if the previous behavior was + * reset-on-expiration (NULL is also returned if an error occurs). + * + ****************************************************************************/ + +static xcpt_t cxd56_capture(FAR struct watchdog_lowerhalf_s *lower, + xcpt_t handler) +{ +#ifndef CONFIG_CXD56_WDT_INTERRUPT + wderr("ERROR: Not configured for this mode\n"); + return NULL; +#else + FAR struct cxd56_lowerhalf_s *priv = (FAR struct cxd56_lowerhalf_s *)lower; + irqstate_t flags; + xcpt_t oldhandler; + + DEBUGASSERT(priv); + wdinfo("Entry: handler=%p\n", handler); + + /* Get the old handler return value */ + + flags = enter_critical_section(); + oldhandler = priv->handler; + + /* Save the new handler */ + + priv->handler = handler; + + /* Are we attaching or detaching the handler? */ + + if (handler) + { + /* Attaching... Enable the WDT interrupt */ + + up_enable_irq(CXD56_IRQ_WDT_INT); + } + else + { + /* Detaching... Disable the WDT interrupt */ + + up_disable_irq(CXD56_IRQ_WDT_INT); + } + + leave_critical_section(flags); + return oldhandler; +#endif +} + +/**************************************************************************** + * Name: cxd56_ioctl + * + * Description: + * Any ioctl commands that are not recognized by the "upper-half" driver + * are forwarded to the lower half driver through this method. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * cmd - The ioctol command value + * arg - The optional argument that accompanies the 'cmd'. The + * interpretation of this argument depends on the particular + * command. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_ioctl(FAR struct watchdog_lowerhalf_s *lower, int cmd, + unsigned long arg) +{ + wdinfo("cmd=%d arg=%ld\n", cmd, arg); + + /* No ioctls are supported */ + + return -ENOTTY; +} + +/**************************************************************************** + * Name: cxd56_pm_event + * + * Description: + * A callback function to receive events from power manager + * + * Input Parameters: + * id - A event identifier from power manager + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int cxd56_pm_event(uint8_t id) +{ + FAR struct cxd56_lowerhalf_s *priv = &g_wdtdev; + + switch (id) + { + case CXD56_PM_CALLBACK_ID_CLK_CHG_START: + case CXD56_PM_CALLBACK_ID_HOT_SLEEP: + + /* do nothing, but watchdog is automatically stopped in hot sleep */ + + break; + + case CXD56_PM_CALLBACK_ID_CLK_CHG_END: + case CXD56_PM_CALLBACK_ID_HOT_BOOT: + /* If watchdog has been already running before the clock is changed or + * entering in hot sleep , re-start the watchdog timer with a timeout + * value based on the new watchdog timer clock. + */ + + if (priv->started) + { + cxd56_settimeout((struct watchdog_lowerhalf_s *)priv, + priv->timeout); + } + break; + + default: + break; + } + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_wdt_initialize + * + * Description: + * Initialize the WDT watchdog time. The watchdog timer is initialized and + * registered as 'devpath. The initial state of the watchdog time is + * disabled. + * + * Input Parameters: + * None + * + * Returned Values: + * None + * + ****************************************************************************/ + +int cxd56_wdt_initialize(void) +{ + FAR struct cxd56_lowerhalf_s *priv = &g_wdtdev; + + /* set load value to max and lock */ + + cxd56_putreg(0xffffffffu, CXD56_WDT_WDOGLOAD); + cxd56_putreg(0, CXD56_WDT_WDOGLOCK); + + wdinfo("Entry: devpath=%s\n", DEVPATH); + + priv->ops = &g_wdgops; + +#ifdef CONFIG_CXD56_WDT_INTERRUPT + /* Attach our WDT interrupt handler (But don't enable it yet) */ + + (void)irq_attach(CXD56_IRQ_WDT_INT, cxd56_wdtinterrupt, priv); +#endif + + /* Register the watchdog driver as /dev/watchdog0 */ + + (void)watchdog_register(DEVPATH, (FAR struct watchdog_lowerhalf_s *)priv); + + /* Register pm event callback */ + + pmhandle = cxd56_pm_register_callback(PM_CLOCK_APP_CPU, cxd56_pm_event); + + return OK; +} + +#endif /* CONFIG_CXD56_WDT */ diff --git a/arch/arm/src/cxd56xx/cxd56_wdt.h b/arch/arm/src/cxd56xx/cxd56_wdt.h new file mode 100644 index 0000000000..0cea0e7f56 --- /dev/null +++ b/arch/arm/src/cxd56xx/cxd56_wdt.h @@ -0,0 +1,94 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/cxd56_wdt.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 __ARCH_ARM_SRC_CXD56XX_CXD56_WDT_H +#define __ARCH_ARM_SRC_CXD56XX_CXD56_WDT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/cxd56_wdt.h" + +#ifdef CONFIG_CXD56_WDT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_wdt_initialize + * + * Description: + * Initialize the WDT watchdog time. The watchdog timer is initialized and + * registered as 'devpath. The initial state of the watchdog time is + * disabled. + * + * Input Parameters: + * None + * + * Returned Values: + * None + * + ****************************************************************************/ + +int cxd56_wdt_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_CXD56_WDT */ +#endif /* __ARCH_ARM_SRC_CXD56XX_CXD56_WDT_H */ diff --git a/arch/arm/src/cxd56xx/hardware/cxd56_timer.h b/arch/arm/src/cxd56xx/hardware/cxd56_timer.h new file mode 100644 index 0000000000..ad9e3a68a1 --- /dev/null +++ b/arch/arm/src/cxd56xx/hardware/cxd56_timer.h @@ -0,0 +1,117 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/hardware/cxd56_timer.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 __ARCH_ARM_SRC_CXD56XX_CHIP_CXD56_TIMER_H +#define __ARCH_ARM_SRC_CXD56XX_CHIP_CXD56_TIMER_H + +/**************************************************************************************** + * Included Files + ****************************************************************************************/ + +#include +#include + +#include "hardware/cxd5602_memorymap.h" + +/**************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************/ + +/* Register addresses *******************************************************************/ + +#define CXD56_TIMER0_BASE (CXD56_TIMER_BASE) +#define CXD56_TIMER1_BASE (CXD56_TIMER_BASE + 0x0020) +#define CXD56_TIMER_LOAD (0x0000) /* Load register */ +#define CXD56_TIMER_VALUE (0x0004) /* Value register [RO] */ +#define CXD56_TIMER_CONTROL (0x0008) /* Control register */ +#define CXD56_TIMER_INTCLR (0x000C) /* Clear Interrupt register [WO] */ +#define CXD56_TIMER_RIS (0x0010) /* Raw Interrupt Status register [RO] */ +#define CXD56_TIMER_MIS (0x0014) /* Interrupt Status register [RO] */ +#define CXD56_TIMER_BGLOAD (0x0018) /* Backround Load register [RO] */ +#define CXD56_TIMER_ITCR (0x0F00) /* Integration Test Control register */ +#define CXD56_TIMER_ITOP (0x0F04) /* Integration Test Output register [WO] */ +#define CXD56_TIMER_PERIPHID0 (0x0FE0) /* Peripheral ID0 register [RO] */ +#define CXD56_TIMER_PERIPHID1 (0x0FE4) /* Peripheral ID1 register [RO] */ +#define CXD56_TIMER_PERIPHID2 (0x0FE8) /* Peripheral ID2 register [RO] */ +#define CXD56_TIMER_PERIPHID3 (0x0FFC) /* Peripheral ID3 register [RO] */ +#define CXD56_TIMER_PCELLID0 (0x0FF0) /* PrimeCell ID0 register [RO] */ +#define CXD56_TIMER_PCELLID1 (0x0FF4) /* PrimeCell ID1 register [RO] */ +#define CXD56_TIMER_PCELLID2 (0x0FF8) /* PrimeCell ID2 register [RO] */ +#define CXD56_TIMER_PCELLID3 (0x0FFC) /* PrimeCell ID3 register [RO] */ + +/* Register bit definitions *************************************************************/ + +/* Control Register */ + +#define TIMERCTRL_ENABLE (0x1u << 7) +#define TIMERCTRL_DISABLE (0x0u << 7) +#define TIMERCTRL_PERIODIC (0x1u << 6) +#define TIMERCTRL_FREERUN (0x0u << 6) +#define TIMERCTRL_INTENABLE (0x1u << 5) +#define TIMERCTRL_INTDISABLE (0x0u << 5) +#define TIMERCTRL_DIV_256 (0x2u << 2) +#define TIMERCTRL_DIV_16 (0x1u << 2) +#define TIMERCTRL_DIV_1 (0x0u << 2) +#define TIMERCTRL_SIZE_32BIT (0x1u << 1) +#define TIMERCTRL_SIZE_16BIT (0x0u << 1) +#define TIMERCTRL_MODE_ONESHOT (0x1u << 0) +#define TIMERCTRL_MODE_WRAP (0x0u << 0) + +/* Interrupt Register */ + +#define TIMER_INTERRUPT (0x1u << 0) + +/* Integration Test Control register */ + +#define TIMERITCR_ENABLE (0x1u << 0) + +/* Integration Test Output register */ + +#define TIMERITOP_TIMINT1 (0x1u << 0) +#define TIMERITOP_TIMINT2 (0x1u << 1) + +/**************************************************************************************** + * Public Types + ****************************************************************************************/ + +/**************************************************************************************** + * Public Data + ****************************************************************************************/ + +/**************************************************************************************** + * Public Functions + ****************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_CXD56XX_CHIP_CXD56_TIMER_H */ diff --git a/arch/arm/src/cxd56xx/hardware/cxd56_wdt.h b/arch/arm/src/cxd56xx/hardware/cxd56_wdt.h new file mode 100644 index 0000000000..86b0f89a52 --- /dev/null +++ b/arch/arm/src/cxd56xx/hardware/cxd56_wdt.h @@ -0,0 +1,108 @@ +/**************************************************************************** + * arch/arm/src/cxd56xx/hardware/cxd56_wdt.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 __ARCH_ARM_SRC_CXD56XX_CHIP_CXD56_WDT_H +#define __ARCH_ARM_SRC_CXD56XX_CHIP_CXD56_WDT_H + +/**************************************************************************************** + * Included Files + ****************************************************************************************/ + +#include + +#include "hardware/cxd5602_memorymap.h" + +/**************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************/ + +/* WDT register addresses ***************************************************************/ + +#define CXD56_WDT_WDOGLOAD (CXD56_WDOG_BASE + 0x0000) /* Load register */ +#define CXD56_WDT_WDOGVALUE (CXD56_WDOG_BASE + 0x0004) /* Value register [RO] */ +#define CXD56_WDT_WDOGCONTROL (CXD56_WDOG_BASE + 0x0008) /* Control register */ +#define CXD56_WDT_WDOGINTCLR (CXD56_WDOG_BASE + 0x000C) /* Clear Interrupt register [WO] */ +#define CXD56_WDT_WDOGRIS (CXD56_WDOG_BASE + 0x0010) /* Raw Interrupt Status register [RO] */ +#define CXD56_WDT_WDOGMIS (CXD56_WDOG_BASE + 0x0014) /* Interrupt Status register [RO] */ +#define CXD56_WDT_WDOGLOCK (CXD56_WDOG_BASE + 0x0C00) /* Lock register */ +#define CXD56_WDT_WDOGITCR (CXD56_WDOG_BASE + 0x0F00) /* Integration Test Control register */ +#define CXD56_WDT_WDOGITOP (CXD56_WDOG_BASE + 0x0F04) /* Integration Test Output register [WO] */ +#define CXD56_WDT_WDOGPERIPHID0 (CXD56_WDOG_BASE + 0x0FE0) /* Peripheral ID0 register [RO] */ +#define CXD56_WDT_WDOGPERIPHID1 (CXD56_WDOG_BASE + 0x0FE4) /* Peripheral ID1 register [RO] */ +#define CXD56_WDT_WDOGPERIPHID2 (CXD56_WDOG_BASE + 0x0FE8) /* Peripheral ID2 register [RO] */ +#define CXD56_WDT_WDOGPERIPHID3 (CXD56_WDOG_BASE + 0x0FFC) /* Peripheral ID3 register [RO] */ +#define CXD56_WDT_WDOGPCELLID0 (CXD56_WDOG_BASE + 0x0FF0) /* PrimeCell ID0 register [RO] */ +#define CXD56_WDT_WDOGPCELLID1 (CXD56_WDOG_BASE + 0x0FF4) /* PrimeCell ID1 register [RO] */ +#define CXD56_WDT_WDOGPCELLID2 (CXD56_WDOG_BASE + 0x0FF8) /* PrimeCell ID2 register [RO] */ +#define CXD56_WDT_WDOGPCELLID3 (CXD56_WDOG_BASE + 0x0FFC) /* PrimeCell ID3 register [RO] */ + +/* WDT register bit definitions *********************************************************/ + +/* Control Register */ + +#define WDOGCONTROL_RESEN (0x1 << 1) /* enable reset output */ +#define WDOGCONTROL_INTEN (0x1 << 0) /* enable interrupt output */ +#define WDOGCONTROL_STOP (0x0) /* stop */ + +/* Interrupt Register */ + +#define WDOGRIS_RAWINT (0x1 << 0) /* raw interrupt status */ +#define WDOGRIS_INT (0x1 << 0) /* interrupt status */ + +/* Lock Register */ + +#define WDOGLOCK_UNLOCK_KEY (0x1ACCE551) /* unlock key */ +#define WDOGLOCK_ACCESS_ENABLE (0x0 << 0) /* enable write access */ +#define WDOGLOCK_ACCESS_DISABLE (0x1 << 0) /* disable write access */ + +/* Test Register */ + +#define WDOGITCR_ENABLE (0x1 << 0) /* enable test mode */ +#define WDOGITOP_WDOGINT (0x1 << 1) /* output interrupt */ +#define WDOGITOP_WDOGRES (0x1 << 0) /* output reset */ + +/**************************************************************************************** + * Public Types + ****************************************************************************************/ + +/**************************************************************************************** + * Public Data + ****************************************************************************************/ + +/**************************************************************************************** + * Public Functions + ****************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_CXD56XX_CHIP_CXD56_WDT_H */ diff --git a/configs/spresense/include/board.h b/configs/spresense/include/board.h index f9147906ac..07c895aaac 100644 --- a/configs/spresense/include/board.h +++ b/configs/spresense/include/board.h @@ -49,6 +49,7 @@ #include "cxd56_power.h" #include "cxd56_flash.h" #include "cxd56_sdcard.h" +#include "cxd56_wdt.h" /**************************************************************************** * Pre-processor Definitions diff --git a/configs/spresense/include/cxd56_pwm.h b/configs/spresense/include/cxd56_pwm.h new file mode 100644 index 0000000000..734f31e8df --- /dev/null +++ b/configs/spresense/include/cxd56_pwm.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * configs/spresense/include/cxd56_pwm.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 __BOARD_COMMON_INCLUDE_CXD56_PWM_H +#define __BOARD_COMMON_INCLUDE_CXD56_PWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * 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 + ****************************************************************************/ + +/**************************************************************************** + * Name: board_pwm_setup + * + * Description: + * Initialize PWM on the board. + * + ****************************************************************************/ + +int board_pwm_setup(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARD_COMMON_INCLUDE_CXD56_PWM_H */ diff --git a/configs/spresense/include/cxd56_wdt.h b/configs/spresense/include/cxd56_wdt.h new file mode 100644 index 0000000000..2e4c40d86e --- /dev/null +++ b/configs/spresense/include/cxd56_wdt.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * configs/spresense/include/cxd56_wdt.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 __BOARD_COMMON_INCLUDE_CXD56_WDT_H +#define __BOARD_COMMON_INCLUDE_CXD56_WDT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * 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 + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_wdt_initialize + * + * Description: + * Initialize WDT on the board. + * + ****************************************************************************/ + +int cxd56_wdt_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARD_COMMON_INCLUDE_CXD56_WDT_H */ diff --git a/configs/spresense/src/Makefile b/configs/spresense/src/Makefile index 359d5158cd..57703a3170 100644 --- a/configs/spresense/src/Makefile +++ b/configs/spresense/src/Makefile @@ -60,10 +60,18 @@ ifeq ($(CONFIG_ARCH_LEDS),y) CSRCS += cxd56_leds.c endif +ifeq ($(CONFIG_CXD56_PWM),y) +CSRCS += cxd56_pwm.c +endif + ifeq ($(CONFIG_CXD56_SFC),y) CSRCS += cxd56_flash.c endif +ifeq ($(CONFIG_SPI),y) +CSRCS += cxd56_spi.c +endif + ifeq ($(CONFIG_CXD56_SDIO),y) CSRCS += cxd56_sdcard.c endif diff --git a/configs/spresense/src/cxd56_bringup.c b/configs/spresense/src/cxd56_bringup.c index 4862e9d3a0..892ccfd3b9 100644 --- a/configs/spresense/src/cxd56_bringup.c +++ b/configs/spresense/src/cxd56_bringup.c @@ -39,6 +39,7 @@ #include +#include #include #include #include @@ -62,6 +63,18 @@ #include "cxd56_gpio.h" #include "cxd56_pinconfig.h" +#ifdef CONFIG_CXD56_PM_PROCFS +#include "cxd56_powermgr_procfs.h" +#endif + +#ifdef CONFIG_TIMER +#include "cxd56_timer.h" +#endif + +#ifdef CONFIG_WDT +#include "cxd56_wdt.h" +#endif + #ifdef CONFIG_CXD56_RTC #include #include "cxd56_rtc.h" @@ -83,6 +96,10 @@ #include "cxd56_usbdev.h" #endif +#ifdef CONFIG_PWM +#include "cxd56_pwm.h" +#endif + #include "spresense.h" /**************************************************************************** @@ -127,6 +144,21 @@ static int nsh_cpucom_initialize(void) # define nsh_cpucom_initialize() (OK) #endif +#ifdef CONFIG_TIMER +static void timer_initialize(void) +{ + int i; + char devname[16]; + + for (i = 0; i < CXD56_TIMER_NUM; i++) + { + snprintf(devname, sizeof(devname), "/dev/timer%d", i); + cxd56_timer_initialize(devname, i); + } + return; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -162,6 +194,14 @@ int cxd56_bringup(void) _err("ERROR: Failed to initialize powermgr.\n"); } +#ifdef CONFIG_CXD56_PM_PROCFS + ret = cxd56_pm_initialize_procfs(); + if (ret < 0) + { + _err("ERROR: Failed to initialize powermgr.\n"); + } +#endif + wlock.info = PM_CPUWAKELOCK_TAG('C', 'A', 0); wlock.count = 0; up_pm_acquire_wakelock(&wlock); @@ -170,6 +210,18 @@ int cxd56_bringup(void) rtc_initialize(0, cxd56_rtc_lowerhalf()); #endif +#ifdef CONFIG_TIMER + timer_initialize(); +#endif + +#ifdef CONFIG_CXD56_WDT + ret = cxd56_wdt_initialize(); + if (ret < 0) + { + _err("ERROR: Failed to initialize WDT.\n"); + } +#endif + cxd56_uart_initialize(); cxd56_timerisr_initialize(); @@ -208,6 +260,14 @@ int cxd56_bringup(void) } #endif +#ifdef CONFIG_PWM + ret = board_pwm_setup(); + if (ret < 0) + { + _err("ERROR: Failed to initialze pwm. \n"); + } +#endif + #ifdef CONFIG_CXD56_SFC ret = board_flash_initialize(); if (ret < 0) diff --git a/configs/spresense/src/cxd56_pwm.c b/configs/spresense/src/cxd56_pwm.c new file mode 100644 index 0000000000..70dcbd4f7b --- /dev/null +++ b/configs/spresense/src/cxd56_pwm.c @@ -0,0 +1,141 @@ +/**************************************************************************** + * configs/spresense/src/cxd56_pwm.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 "cxd56_pwm.h" + +#ifdef CONFIG_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if defined(CONFIG_CXD56_PWM0) || defined(CONFIG_CXD56_PWM1) || \ + defined(CONFIG_CXD56_PWM2) || defined(CONFIG_CXD56_PWM3) +static int pwm_initialize(uint32_t channel) +{ + char devname[16]; + struct pwm_lowerhalf_s *pwm = NULL; + int ret; + + /* Call cxd56_pwminitialize() to get an instance of the PWM interface */ + + pwm = cxd56_pwminitialize(channel); + if (!pwm) + { + pwmerr("Failed to get the CXD56 PWM%d lower half\n", channel); + return -ENODEV; + } + + /* Register the PWM driver at "/dev/pwmX" */ + + snprintf(devname, sizeof(devname), "/dev/pwm%d", channel); + ret = pwm_register(devname, pwm); + if (ret < 0) + { + pwmerr("pwm_register(%s) failed: %d\n", devname, ret); + return ret; + } + + return 0; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_pwm_setup + * + * Description: + * All CXD56 architectures must provide the following interface to work + * with examples/pwm. + * + ****************************************************************************/ + +int board_pwm_setup(void) +{ + static bool initialized = false; + + /* Have we already initialized? */ + + if (!initialized) + { +#ifdef CONFIG_CXD56_PWM0 + pwm_initialize(CXD56_PWM_CH0); +#endif + +#ifdef CONFIG_CXD56_PWM1 + pwm_initialize(CXD56_PWM_CH1); +#endif + +#ifdef CONFIG_CXD56_PWM2 + pwm_initialize(CXD56_PWM_CH2); +#endif + +#ifdef CONFIG_CXD56_PWM3 + pwm_initialize(CXD56_PWM_CH3); +#endif + + /* Now we are initialized */ + + initialized = true; + } + + return OK; +} + +#endif /* CONFIG_PWM */ diff --git a/configs/spresense/src/cxd56_spi.c b/configs/spresense/src/cxd56_spi.c new file mode 100644 index 0000000000..2faf9df0e2 --- /dev/null +++ b/configs/spresense/src/cxd56_spi.c @@ -0,0 +1,174 @@ +/**************************************************************************** + * configs/spresense/src/cxd56_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 +#include + +#include "up_arch.h" +#include "chip.h" +#include "hardware/cxd56_spi.h" +#include "cxd56_clock.h" +#include "cxd56_gpio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MMCSD_DETECT PIN_AP_CLK + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cxd56_spi0/3/4/5select and cxd56_spi0/3/4/5status + * + * Description: + * The external functions, cxd56_spi1/2/3select and cxd56_spi1/2/3status must be + * provided by board-specific logic. They are implementations of the select + * and status methods of the SPI interface defined by struct spi_ops_s (see + * include/nuttx/spi/spi.h). All other methods (including cxd56_spibus_initialize()) + * are provided by common CXD56 logic. To use this common SPI logic on your + * board: + * + * 1. Provide logic in cxd56_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide cxd56_spi0/3/4/5select() and cxd56_spi0/3/4/5status() functions in your + * board-specific logic. These functions will perform chip selection and + * status operations using GPIOs in the way your board is configured. + * 3. Add a calls to cxd56_spibus_initialize() in your low level application + * initialization logic + * 4. The handle returned by cxd56_spibus_initialize() may then be used to bind the + * SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ + +#ifdef CONFIG_CXD56_SPI0 +void cxd56_spi0select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); +} + +uint8_t cxd56_spi0status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_CXD56_SPI3 +void cxd56_spi3select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); + + /* Disable clock gating (clock enable) */ + + cxd56_spi_clock_gate_disable(3); + + if (selected) + { + putreg32(0, CXD56_SPI3_CS); + } + else + { + putreg32(1, CXD56_SPI3_CS); + } + + /* Enable clock gating (clock disable) */ + + cxd56_spi_clock_gate_enable(3); +} + +uint8_t cxd56_spi3status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif + +#ifdef CONFIG_CXD56_SPI4 +void cxd56_spi4select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); +} + +uint8_t cxd56_spi4status(FAR struct spi_dev_s *dev, uint32_t devid) +{ +# ifdef CONFIG_CXD56_SPISD + if (devid == SPIDEV_MMCSD(0)) + { + static bool initialized = false; + if (initialized == false) + { + /* Input enable */ + + cxd56_gpio_config(MMCSD_DETECT, true); + + initialized = true; + } + + /* MMCSD_DETECT is mapping to SD Card detect pin + * MMCSD_DETECT = 0: Inserted + * MMCSD_DETECT = 1: Removed + */ + return cxd56_gpio_read(MMCSD_DETECT) ? 0 : SPI_STATUS_PRESENT; + } +# endif + return 0; +} +#endif + +#ifdef CONFIG_CXD56_SPI5 +void cxd56_spi5select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected) +{ + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); +} + +uint8_t cxd56_spi5status(FAR struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} +#endif