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 <alin.jerpelea@sony.com>

* arch: arm: cxd56xx: add support for PWM

    add support for PWM for cxd56xx

    Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>

* configs: spresense: enable PWM support

    enable PWM support on spresense board

    Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>

* arch: arm: cxd56xx: add Power Management PROCFS support

    the powermanager procfs support will export
    /proc/pm:
     clock
     power

    Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>

* 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 <alin.jerpelea@sony.com>

* 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 <alin.jerpelea@sony.com>

* arch: arm: cxd56xx: add Watch Dog Timer

    Add Watch Dog Timer on cxd56xx

    Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>

* 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 <alin.jerpelea@sony.com>

* 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 <alin.jerpelea@sony.com>

Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
Alin Jerpelea 2019-06-14 18:40:06 +00:00 committed by Gregory Nutt
parent ae2506619f
commit 92892a8dd7
20 changed files with 3909 additions and 1 deletions

View File

@ -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 <nuttx/timers/timer.h>
/****************************************************************************
* 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 */

View File

@ -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"

View File

@ -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

View File

@ -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 <nuttx/config.h>
#include <nuttx/fs/procfs.h>
#include <nuttx/fs/dirent.h>
#include <nuttx/kmalloc.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <debug.h>
#include <errno.h>
#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;
}

View File

@ -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 <gnutt@nuttx.org>
*
* 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 */

View File

@ -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 <nuttx/config.h>
#include <nuttx/drivers/pwm.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#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, &param);
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;
}

View File

@ -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 <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
/****************************************************************************
* 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 */

View File

@ -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 <nuttx/config.h>
#include <nuttx/arch.h>
#include <sys/types.h>
#include <stdint.h>
#include <limits.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/timers/timer.h>
#include <arch/board/board.h>
#include <arch/chip/timer.h>
#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 */

View File

@ -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 <nuttx/config.h>
#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 */

View File

@ -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 <nuttx/config.h>
#ifdef CONFIG_DEBUG_FEATURES
#include <nuttx/debug.h>
#endif
#include <nuttx/arch.h>
#include <stdint.h>
#include <errno.h>
#include <nuttx/irq.h>
#include <nuttx/timers/watchdog.h>
#include <arch/board/board.h>
#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 */

View File

@ -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 <nuttx/config.h>
#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 */

View File

@ -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 <nuttx/config.h>
#include <arch/cxd56xx/chip.h>
#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 */

View File

@ -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 <arch/cxd56xx/chip.h>
#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 */

View File

@ -49,6 +49,7 @@
#include "cxd56_power.h"
#include "cxd56_flash.h"
#include "cxd56_sdcard.h"
#include "cxd56_wdt.h"
/****************************************************************************
* Pre-processor Definitions

View File

@ -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 <nuttx/config.h>
/****************************************************************************
* 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 */

View File

@ -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 <nuttx/config.h>
/****************************************************************************
* 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 */

View File

@ -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

View File

@ -39,6 +39,7 @@
#include <nuttx/config.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <errno.h>
@ -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 <nuttx/timers/rtc.h>
#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)

View File

@ -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 <nuttx/config.h>
#include <stdio.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/board.h>
#include <nuttx/drivers/pwm.h>
#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 */

View File

@ -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 <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/spi/spi.h>
#include <arch/board/board.h>
#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