This watchdog driver will be working on IMX2+, Vybrid, LS1, LS2+
platforms, and will be in different endianness mode in those SoCs:
SoCs CPU endian mode WDT endian mode
------------------------------------------------
IMX2+ LE LE
Vybird LE LE
LS1 LE BE
LS2 LE LE
Other possible SoCs:
SoCs CPU endian mode WDT endian mode
------------------------------------------------
Soc1 BE BE
Soc2 BE LE
And also the watchdog's registers will be 32-bits for some versions,
and though it is 16-bits in IMX2+, Vybird and LS+.
Using the regmap APIs, could be more easy to support different
endianness and also more easy to support 32-bits version...
Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
config IMX2_WDT
tristate "IMX2+ Watchdog"
depends on ARCH_MXC
config IMX2_WDT
tristate "IMX2+ Watchdog"
depends on ARCH_MXC
help
This is the driver for the hardware watchdog
on the Freescale IMX2 and later processors.
help
This is the driver for the hardware watchdog
on the Freescale IMX2 and later processors.
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
static struct {
struct clk *clk;
static struct {
struct clk *clk;
unsigned timeout;
unsigned long status;
struct timer_list timer; /* Pings the watchdog when closed */
unsigned timeout;
unsigned long status;
struct timer_list timer; /* Pings the watchdog when closed */
static inline void imx2_wdt_setup(void)
{
static inline void imx2_wdt_setup(void)
{
- u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
+ u32 val;
+
+ regmap_read(imx2_wdt.regmap, IMX2_WDT_WCR, &val);
/* Suspend timer in low power mode, write once-only */
val |= IMX2_WDT_WCR_WDZST;
/* Suspend timer in low power mode, write once-only */
val |= IMX2_WDT_WCR_WDZST;
/* Set the watchdog's Time-Out value */
val |= WDOG_SEC_TO_COUNT(imx2_wdt.timeout);
/* Set the watchdog's Time-Out value */
val |= WDOG_SEC_TO_COUNT(imx2_wdt.timeout);
- __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+ regmap_write(imx2_wdt.regmap, IMX2_WDT_WCR, val);
/* enable the watchdog */
val |= IMX2_WDT_WCR_WDE;
/* enable the watchdog */
val |= IMX2_WDT_WCR_WDE;
- __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+ regmap_write(imx2_wdt.regmap, IMX2_WDT_WCR, val);
}
static inline void imx2_wdt_ping(void)
{
}
static inline void imx2_wdt_ping(void)
{
- __raw_writew(IMX2_WDT_SEQ1, imx2_wdt.base + IMX2_WDT_WSR);
- __raw_writew(IMX2_WDT_SEQ2, imx2_wdt.base + IMX2_WDT_WSR);
+ regmap_write(imx2_wdt.regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
+ regmap_write(imx2_wdt.regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
}
static void imx2_wdt_timer_ping(unsigned long arg)
}
static void imx2_wdt_timer_ping(unsigned long arg)
static void imx2_wdt_set_timeout(int new_timeout)
{
static void imx2_wdt_set_timeout(int new_timeout)
{
- u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
-
- /* set the new timeout value in the WSR */
- val &= ~IMX2_WDT_WCR_WT;
- val |= WDOG_SEC_TO_COUNT(new_timeout);
- __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+ regmap_update_bits(imx2_wdt.regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
+ WDOG_SEC_TO_COUNT(new_timeout));
}
static int imx2_wdt_open(struct inode *inode, struct file *file)
}
static int imx2_wdt_open(struct inode *inode, struct file *file)
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
void __user *argp = (void __user *)arg;
int __user *p = argp;
int new_value;
switch (cmd) {
case WDIOC_GETSUPPORT:
switch (cmd) {
case WDIOC_GETSUPPORT:
return put_user(0, p);
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_GETBOOTSTATUS:
- val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
+ regmap_read(imx2_wdt.regmap, IMX2_WDT_WRSR, &val);
new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
return put_user(new_value, p);
new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
return put_user(new_value, p);
.fops = &imx2_wdt_fops,
};
.fops = &imx2_wdt_fops,
};
+static struct regmap_config imx2_wdt_regmap_config = {
+ .reg_bits = 16,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .max_register = 0x8,
+};
+
static int __init imx2_wdt_probe(struct platform_device *pdev)
{
static int __init imx2_wdt_probe(struct platform_device *pdev)
{
+ void __iomem *base;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- imx2_wdt.base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(imx2_wdt.base))
- return PTR_ERR(imx2_wdt.base);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ imx2_wdt.regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
+ &imx2_wdt_regmap_config);
+ if (IS_ERR(imx2_wdt.regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(imx2_wdt.regmap);
+ }
imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(imx2_wdt.clk)) {
imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(imx2_wdt.clk)) {