wdt: dw: Add support for optional clock gating

Clock gating is platform specific and not mandatory. Thus making it
Kconfig based as well as generic.

Change-Id: I4ea10eadb077ac3d57c9337b43b1a9fb14763302
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Tomasz Bursztyka 2015-12-03 14:05:51 +01:00 committed by Anas Nashif
commit 04f5cfb889
6 changed files with 78 additions and 14 deletions

View file

@ -129,9 +129,6 @@ struct scss_interrupt {
/* Watchdog */ /* Watchdog */
#define WDT_DW_INT_MASK (SCSS_INT_BASE + 0x7C) #define WDT_DW_INT_MASK (SCSS_INT_BASE + 0x7C)
#define SCSS_PERIPH_CFG0 0x4 #define SCSS_PERIPH_CFG0 0x4
#define SCSS_PERIPH_CFG0_WDT_ENABLE (1 << 1)
#define CCU_WDT_PCLK_EN_SW (1 << 10)
/* RTC */ /* RTC */
#define RTC_DW_INT_MASK (SCSS_INT_BASE + 0x78) #define RTC_DW_INT_MASK (SCSS_INT_BASE + 0x78)

View file

@ -170,6 +170,12 @@ endif
if WATCHDOG if WATCHDOG
config WDT_DW config WDT_DW
def_bool y def_bool y
config WDT_DW_CLOCK_GATE
def_bool n
config WDT_DW_CLOCK_GATE_DRV_NAME
default CLOCK_CONTROL_QUARK_SE_PERIPHERAL_DRV_NAME
config WDT_DW_CLOCK_GATE_SUBSYS
default 10
config WDT_DW_BASE_ADDR config WDT_DW_BASE_ADDR
default 0xB0000000 default 0xB0000000
config WDT_DW_IRQ config WDT_DW_IRQ

View file

@ -207,9 +207,6 @@ struct scss_interrupt {
#define SCSS_CCU_SYS_CLK_CTL 0x38 #define SCSS_CCU_SYS_CLK_CTL 0x38
/* Peripheral Configuration */
#define SCSS_PERIPH_CFG0 (0x4)
/* Peripheral Clock Gate Control */ /* Peripheral Clock Gate Control */
#define SCSS_CCU_PERIPH_CLK_GATE_CTL 0x18 #define SCSS_CCU_PERIPH_CLK_GATE_CTL 0x18
#define CCU_PERIPH_CLK_EN (1 << 1) #define CCU_PERIPH_CLK_EN (1 << 1)
@ -221,8 +218,7 @@ struct scss_interrupt {
/* Watchdog */ /* Watchdog */
#define WDT_DW_INT_MASK (SCSS_INT_BASE + 0x7C) #define WDT_DW_INT_MASK (SCSS_INT_BASE + 0x7C)
#define SCSS_PERIPH_CFG0_WDT_ENABLE (1 << 1) #define SCSS_PERIPH_CFG0 (0x4)
#define CCU_WDT_PCLK_EN_SW (1 << 10)
/* RTC */ /* RTC */
#define RTC_DW_INT_MASK (SCSS_INT_BASE + 0x78) #define RTC_DW_INT_MASK (SCSS_INT_BASE + 0x78)

View file

@ -33,6 +33,24 @@ config WDT_DW
help help
Enable watchdog timer. Enable watchdog timer.
config WDT_DW_CLOCK_GATE
bool "Enable clock gating"
depends on WDT_DW
select CLOCK_CONTROL
default n
help
Enable clock gating on WDT DesignWare controller
config WDT_DW_CLOCK_GATE_DRV_NAME
string "Clock gating driver name"
depends on WDT_DW_CLOCK_GATE
default ""
config WDT_DW_CLOCK_GATE_SUBSYS
int "Clock controller's subsystem"
depends on WDT_DW_CLOCK_GATE
default 0
config WDT_DW_DRV_NAME config WDT_DW_DRV_NAME
string "Driver instance name" string "Driver instance name"
default "WDT_DW" default "WDT_DW"

View file

@ -16,6 +16,7 @@
#include <nanokernel.h> #include <nanokernel.h>
#include <init.h> #include <init.h>
#include <clock_control.h>
#include "wdt_dw.h" #include "wdt_dw.h"
#ifdef WDT_DW_INT_MASK #ifdef WDT_DW_INT_MASK
@ -28,25 +29,60 @@ static inline void _wdt_dw_int_unmask(void)
#define _wdt_dw_int_unmask() #define _wdt_dw_int_unmask()
#endif #endif
#ifdef CONFIG_WDT_DW_CLOCK_GATE
static inline void _wdt_dw_clock_config(struct device *dev)
{
char *drv = CONFIG_WDT_DW_CLOCK_GATE_DRV_NAME;
struct device *clk;
clk = device_get_binding(drv);
if (clk) {
struct wdt_dw_runtime *context = dev->driver_data;
context->clock = clk;
}
}
static inline void _wdt_dw_clock_on(struct device *dev)
{
struct wdt_dw_dev_config *config = dev->config->config_info;
struct wdt_dw_runtime *context = dev->driver_data;
clock_control_on(context->clock, config->clock_data);
}
static inline void _wdt_dw_clock_off(struct device *dev)
{
struct wdt_dw_dev_config *config = dev->config->config_info;
struct wdt_dw_runtime *context = dev->driver_data;
clock_control_off(context->clock, config->clock_data);
}
#else
#define _wdt_dw_clock_config(...)
#define _wdt_dw_clock_on(...)
#define _wdt_dw_clock_off(...)
#endif
/** /**
* Enables the clock for the peripheral watchdog * Enables the clock for the peripheral watchdog
*/ */
static void wdt_dw_enable(struct device *dev) static void wdt_dw_enable(struct device *dev)
{ {
struct wdt_dw_dev_config *wdt_dev = dev->config->config_info; _wdt_dw_clock_on(dev);
sys_set_bit(wdt_dev->base_address + WDT_CR, 0); #if defined(CONFIG_PLATFORM_QUARK_SE) || defined(CONFIG_PLATFORM_QUARK_D2000)
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 1);
sys_set_bit(SCSS_PERIPHERAL_BASE + SCSS_PERIPH_CFG0, 1); sys_set_bit(SCSS_PERIPHERAL_BASE + SCSS_PERIPH_CFG0, 1);
#endif
} }
static void wdt_dw_disable(struct device *dev) static void wdt_dw_disable(struct device *dev)
{ {
ARG_UNUSED(dev); _wdt_dw_clock_off(dev);
/* Disable the clock for the peripheral watchdog */ #if defined(CONFIG_PLATFORM_QUARK_SE) || defined(CONFIG_PLATFORM_QUARK_D2000)
sys_clear_bit(SCSS_PERIPHERAL_BASE + SCSS_PERIPH_CFG0, 1); sys_clear_bit(SCSS_PERIPHERAL_BASE + SCSS_PERIPH_CFG0, 1);
#endif
} }
void wdt_dw_isr(void *arg) void wdt_dw_isr(void *arg)
@ -126,6 +162,8 @@ int wdt_dw_init(struct device *dev)
_wdt_dw_int_unmask(); _wdt_dw_int_unmask();
_wdt_dw_clock_config(dev);
return 0; return 0;
} }
@ -133,6 +171,9 @@ struct wdt_dw_runtime wdt_runtime;
struct wdt_dw_dev_config wdt_dev = { struct wdt_dw_dev_config wdt_dev = {
.base_address = CONFIG_WDT_DW_BASE_ADDR, .base_address = CONFIG_WDT_DW_BASE_ADDR,
#ifdef CONFIG_WDT_DW_CLOCK_GATE
.clock_data = UINT_TO_POINTER(CONFIG_WDT_DW_CLOCK_GATE_SUBSYS),
#endif
}; };
DECLARE_DEVICE_INIT_CONFIG(wdt, CONFIG_WDT_DW_DRV_NAME, DECLARE_DEVICE_INIT_CONFIG(wdt, CONFIG_WDT_DW_DRV_NAME,

View file

@ -47,10 +47,16 @@
struct wdt_dw_runtime { struct wdt_dw_runtime {
void (*cb_fn)(struct device *dev); void (*cb_fn)(struct device *dev);
#ifdef CONFIG_WDT_DW_CLOCK_GATE
struct device *clock;
#endif
}; };
struct wdt_dw_dev_config { struct wdt_dw_dev_config {
uint32_t base_address; uint32_t base_address;
#ifdef CONFIG_WDT_DW_CLOCK_GATE
void *clock_data;
#endif
}; };
#endif /* WDT_DW_H_ */ #endif /* WDT_DW_H_ */