2010-04-29 12:03:17 +04:00
/*
* Watchdog driver for IMX2 and later processors
*
* Copyright ( C ) 2010 Wolfram Sang , Pengutronix e . K . < w . sang @ pengutronix . de >
2014-01-13 15:58:34 +04:00
* Copyright ( C ) 2014 Freescale Semiconductor , Inc .
2010-04-29 12:03:17 +04:00
*
* some parts adapted by similar drivers from Darius Augulis and Vladimir
* Zapolskiy , additional improvements by Wim Van Sebroeck .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* NOTE : MX1 has a slightly different Watchdog than MX2 and later :
*
* MX1 : MX2 + :
* - - - - - - - - -
* Registers : 32 - bit 16 - bit
* Stopable timer : Yes No
* Need to enable clk : No Yes
* Halt on suspend : Manual Can be automatic
*/
2014-04-04 05:33:24 +04:00
# include <linux/clk.h>
2014-09-12 11:24:36 +04:00
# include <linux/delay.h>
2010-04-29 12:03:17 +04:00
# include <linux/init.h>
2016-10-07 15:41:39 +03:00
# include <linux/interrupt.h>
2014-04-04 05:33:24 +04:00
# include <linux/io.h>
2010-04-29 12:03:17 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
2014-06-03 06:45:14 +04:00
# include <linux/of_address.h>
2010-04-29 12:03:17 +04:00
# include <linux/platform_device.h>
2014-04-04 05:33:25 +04:00
# include <linux/regmap.h>
2014-04-04 05:33:24 +04:00
# include <linux/watchdog.h>
2010-04-29 12:03:17 +04:00
# define DRIVER_NAME "imx2-wdt"
# define IMX2_WDT_WCR 0x00 /* Control Register */
# define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */
2016-08-31 14:52:49 +03:00
# define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */
# define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */
# define IMX2_WDT_WCR_WRE BIT(3) /* -> WDOG Reset Enable */
# define IMX2_WDT_WCR_WDE BIT(2) /* -> Watchdog Enable */
# define IMX2_WDT_WCR_WDZST BIT(0) /* -> Watchdog timer Suspend */
2010-04-29 12:03:17 +04:00
# define IMX2_WDT_WSR 0x02 /* Service Register */
# define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */
# define IMX2_WDT_SEQ2 0xAAAA /* -> service sequence 2 */
2012-02-16 16:17:45 +04:00
# define IMX2_WDT_WRSR 0x04 /* Reset Status Register */
2016-08-31 14:52:49 +03:00
# define IMX2_WDT_WRSR_TOUT BIT(1) /* -> Reset due to Timeout */
2012-02-16 16:17:45 +04:00
2016-10-07 15:41:39 +03:00
# define IMX2_WDT_WICR 0x06 /* Interrupt Control Register */
# define IMX2_WDT_WICR_WIE BIT(15) /* -> Interrupt Enable */
# define IMX2_WDT_WICR_WTIS BIT(14) /* -> Interrupt Status */
# define IMX2_WDT_WICR_WICT 0xFF /* -> Interrupt Count Timeout */
2014-09-08 11:14:07 +04:00
# define IMX2_WDT_WMCR 0x08 /* Misc Register */
2010-04-29 12:03:17 +04:00
# define IMX2_WDT_MAX_TIME 128
# define IMX2_WDT_DEFAULT_TIME 60 /* in seconds */
# define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
2014-04-11 10:57:14 +04:00
struct imx2_wdt_device {
2010-04-29 12:03:17 +04:00
struct clk * clk ;
2014-04-04 05:33:25 +04:00
struct regmap * regmap ;
2014-04-11 10:57:14 +04:00
struct watchdog_device wdog ;
2016-04-01 18:16:43 +03:00
bool ext_reset ;
2014-04-11 10:57:14 +04:00
} ;
2010-04-29 12:03:17 +04:00
2012-03-05 19:51:11 +04:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
2010-04-29 12:03:17 +04:00
MODULE_PARM_DESC ( nowayout , " Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2018-02-08 16:11:08 +03:00
static unsigned timeout ;
2010-04-29 12:03:17 +04:00
module_param ( timeout , uint , 0 ) ;
MODULE_PARM_DESC ( timeout , " Watchdog timeout in seconds (default= "
__MODULE_STRING ( IMX2_WDT_DEFAULT_TIME ) " ) " ) ;
static const struct watchdog_info imx2_wdt_info = {
. identity = " imx2+ watchdog " ,
. options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE ,
} ;
2016-10-07 15:41:39 +03:00
static const struct watchdog_info imx2_wdt_pretimeout_info = {
. identity = " imx2+ watchdog " ,
. options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
WDIOF_PRETIMEOUT ,
} ;
2016-02-27 04:32:49 +03:00
static int imx2_wdt_restart ( struct watchdog_device * wdog , unsigned long action ,
void * data )
2014-09-12 11:24:36 +04:00
{
2015-11-16 20:28:04 +03:00
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2014-09-12 11:24:36 +04:00
unsigned int wcr_enable = IMX2_WDT_WCR_WDE ;
2015-11-16 20:28:04 +03:00
2016-04-01 18:16:43 +03:00
/* Use internal reset or external - not both */
if ( wdev - > ext_reset )
wcr_enable | = IMX2_WDT_WCR_SRS ; /* do not assert int reset */
else
wcr_enable | = IMX2_WDT_WCR_WDA ; /* do not assert ext-reset */
2014-09-12 11:24:36 +04:00
/* Assert SRS signal */
2015-10-02 06:25:28 +03:00
regmap_write ( wdev - > regmap , IMX2_WDT_WCR , wcr_enable ) ;
2014-09-12 11:24:36 +04:00
/*
* Due to imx6q errata ERR004346 ( WDOG : WDOG SRS bit requires to be
* written twice ) , we add another two writes to ensure there must be at
* least two writes happen in the same one 32 kHz clock period . We save
* the target check here , since the writes shouldn ' t be a huge burden
* for other platforms .
*/
2015-10-02 06:25:28 +03:00
regmap_write ( wdev - > regmap , IMX2_WDT_WCR , wcr_enable ) ;
regmap_write ( wdev - > regmap , IMX2_WDT_WCR , wcr_enable ) ;
2014-09-12 11:24:36 +04:00
/* wait for reset to assert... */
mdelay ( 500 ) ;
2015-11-16 20:28:04 +03:00
return 0 ;
2014-09-12 11:24:36 +04:00
}
2014-04-11 10:57:14 +04:00
static inline void imx2_wdt_setup ( struct watchdog_device * wdog )
2010-04-29 12:03:17 +04:00
{
2014-04-11 10:57:14 +04:00
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2014-04-04 05:33:25 +04:00
u32 val ;
2014-04-11 10:57:14 +04:00
regmap_read ( wdev - > regmap , IMX2_WDT_WCR , & val ) ;
2010-04-29 12:03:17 +04:00
2014-01-13 15:58:34 +04:00
/* Suspend timer in low power mode, write once-only */
val | = IMX2_WDT_WCR_WDZST ;
2010-04-29 12:03:17 +04:00
/* Strip the old watchdog Time-Out value */
val & = ~ IMX2_WDT_WCR_WT ;
2016-04-01 18:16:43 +03:00
/* Generate internal chip-level reset if WDOG times out */
if ( ! wdev - > ext_reset )
val & = ~ IMX2_WDT_WCR_WRE ;
/* Or if external-reset assert WDOG_B reset only on time-out */
else
val | = IMX2_WDT_WCR_WRE ;
2010-04-29 12:03:17 +04:00
/* Keep Watchdog Disabled */
val & = ~ IMX2_WDT_WCR_WDE ;
/* Set the watchdog's Time-Out value */
2014-04-11 10:57:14 +04:00
val | = WDOG_SEC_TO_COUNT ( wdog - > timeout ) ;
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
regmap_write ( wdev - > regmap , IMX2_WDT_WCR , val ) ;
2010-04-29 12:03:17 +04:00
/* enable the watchdog */
val | = IMX2_WDT_WCR_WDE ;
2014-04-11 10:57:14 +04:00
regmap_write ( wdev - > regmap , IMX2_WDT_WCR , val ) ;
2010-04-29 12:03:17 +04:00
}
2014-04-11 10:57:14 +04:00
static inline bool imx2_wdt_is_running ( struct imx2_wdt_device * wdev )
2010-04-29 12:03:17 +04:00
{
2014-04-11 10:57:14 +04:00
u32 val ;
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
regmap_read ( wdev - > regmap , IMX2_WDT_WCR , & val ) ;
return val & IMX2_WDT_WCR_WDE ;
2010-04-29 12:03:17 +04:00
}
2014-04-11 10:57:14 +04:00
static int imx2_wdt_ping ( struct watchdog_device * wdog )
2010-04-29 12:03:17 +04:00
{
2014-04-11 10:57:14 +04:00
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
regmap_write ( wdev - > regmap , IMX2_WDT_WSR , IMX2_WDT_SEQ1 ) ;
regmap_write ( wdev - > regmap , IMX2_WDT_WSR , IMX2_WDT_SEQ2 ) ;
return 0 ;
2010-04-29 12:03:17 +04:00
}
2018-01-01 20:26:47 +03:00
static void __imx2_wdt_set_timeout ( struct watchdog_device * wdog ,
unsigned int new_timeout )
2010-04-29 12:03:17 +04:00
{
2014-04-11 10:57:14 +04:00
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
regmap_update_bits ( wdev - > regmap , IMX2_WDT_WCR , IMX2_WDT_WCR_WT ,
2014-04-04 05:33:25 +04:00
WDOG_SEC_TO_COUNT ( new_timeout ) ) ;
2018-01-01 20:26:47 +03:00
}
static int imx2_wdt_set_timeout ( struct watchdog_device * wdog ,
unsigned int new_timeout )
{
__imx2_wdt_set_timeout ( wdog , new_timeout ) ;
wdog - > timeout = new_timeout ;
2014-04-11 10:57:14 +04:00
return 0 ;
2010-04-29 12:03:17 +04:00
}
2016-10-07 15:41:39 +03:00
static int imx2_wdt_set_pretimeout ( struct watchdog_device * wdog ,
unsigned int new_pretimeout )
{
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
if ( new_pretimeout > = IMX2_WDT_MAX_TIME )
return - EINVAL ;
wdog - > pretimeout = new_pretimeout ;
regmap_update_bits ( wdev - > regmap , IMX2_WDT_WICR ,
IMX2_WDT_WICR_WIE | IMX2_WDT_WICR_WICT ,
IMX2_WDT_WICR_WIE | ( new_pretimeout < < 1 ) ) ;
return 0 ;
}
static irqreturn_t imx2_wdt_isr ( int irq , void * wdog_arg )
{
struct watchdog_device * wdog = wdog_arg ;
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
regmap_write_bits ( wdev - > regmap , IMX2_WDT_WICR ,
IMX2_WDT_WICR_WTIS , IMX2_WDT_WICR_WTIS ) ;
watchdog_notify_pretimeout ( wdog ) ;
return IRQ_HANDLED ;
}
2014-04-11 10:57:14 +04:00
static int imx2_wdt_start ( struct watchdog_device * wdog )
2010-04-29 12:03:17 +04:00
{
2014-04-11 10:57:14 +04:00
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2010-04-29 12:03:17 +04:00
2016-02-29 00:12:20 +03:00
if ( imx2_wdt_is_running ( wdev ) )
2014-04-11 10:57:14 +04:00
imx2_wdt_set_timeout ( wdog , wdog - > timeout ) ;
2016-02-29 00:12:20 +03:00
else
2014-04-11 10:57:14 +04:00
imx2_wdt_setup ( wdog ) ;
2016-02-29 00:12:20 +03:00
set_bit ( WDOG_HW_RUNNING , & wdog - > status ) ;
2010-04-29 12:03:17 +04:00
2016-02-29 00:12:20 +03:00
return imx2_wdt_ping ( wdog ) ;
2010-04-29 12:03:17 +04:00
}
2015-01-05 12:09:17 +03:00
static const struct watchdog_ops imx2_wdt_ops = {
2010-04-29 12:03:17 +04:00
. owner = THIS_MODULE ,
2014-04-11 10:57:14 +04:00
. start = imx2_wdt_start ,
. ping = imx2_wdt_ping ,
. set_timeout = imx2_wdt_set_timeout ,
2016-10-07 15:41:39 +03:00
. set_pretimeout = imx2_wdt_set_pretimeout ,
2015-11-16 20:28:04 +03:00
. restart = imx2_wdt_restart ,
2010-04-29 12:03:17 +04:00
} ;
2015-01-05 12:09:17 +03:00
static const struct regmap_config imx2_wdt_regmap_config = {
2014-04-04 05:33:25 +04:00
. reg_bits = 16 ,
. reg_stride = 2 ,
. val_bits = 16 ,
. max_register = 0x8 ,
} ;
2010-04-29 12:03:17 +04:00
static int __init imx2_wdt_probe ( struct platform_device * pdev )
{
2014-04-11 10:57:14 +04:00
struct imx2_wdt_device * wdev ;
struct watchdog_device * wdog ;
2010-04-29 12:03:17 +04:00
struct resource * res ;
2014-04-04 05:33:25 +04:00
void __iomem * base ;
int ret ;
2014-04-11 10:57:14 +04:00
u32 val ;
wdev = devm_kzalloc ( & pdev - > dev , sizeof ( * wdev ) , GFP_KERNEL ) ;
if ( ! wdev )
return - ENOMEM ;
2010-04-29 12:03:17 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2014-04-04 05:33:25 +04:00
base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2014-04-11 10:57:14 +04:00
wdev - > regmap = devm_regmap_init_mmio_clk ( & pdev - > dev , NULL , base ,
& imx2_wdt_regmap_config ) ;
if ( IS_ERR ( wdev - > regmap ) ) {
2014-04-04 05:33:25 +04:00
dev_err ( & pdev - > dev , " regmap init failed \n " ) ;
2014-04-11 10:57:14 +04:00
return PTR_ERR ( wdev - > regmap ) ;
2014-04-04 05:33:25 +04:00
}
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
wdev - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( wdev - > clk ) ) {
2010-04-29 12:03:17 +04:00
dev_err ( & pdev - > dev , " can't get Watchdog clock \n " ) ;
2014-04-11 10:57:14 +04:00
return PTR_ERR ( wdev - > clk ) ;
2010-04-29 12:03:17 +04:00
}
2014-04-11 10:57:14 +04:00
wdog = & wdev - > wdog ;
wdog - > info = & imx2_wdt_info ;
wdog - > ops = & imx2_wdt_ops ;
wdog - > min_timeout = 1 ;
2018-02-08 16:11:08 +03:00
wdog - > timeout = IMX2_WDT_DEFAULT_TIME ;
2016-02-29 00:12:20 +03:00
wdog - > max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000 ;
2015-06-02 15:46:18 +03:00
wdog - > parent = & pdev - > dev ;
2010-04-29 12:03:17 +04:00
2016-10-07 15:41:39 +03:00
ret = platform_get_irq ( pdev , 0 ) ;
if ( ret > 0 )
if ( ! devm_request_irq ( & pdev - > dev , ret , imx2_wdt_isr , 0 ,
dev_name ( & pdev - > dev ) , wdog ) )
wdog - > info = & imx2_wdt_pretimeout_info ;
2015-06-22 07:16:18 +03:00
ret = clk_prepare_enable ( wdev - > clk ) ;
if ( ret )
return ret ;
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
regmap_read ( wdev - > regmap , IMX2_WDT_WRSR , & val ) ;
wdog - > bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0 ;
2010-04-29 12:03:17 +04:00
2016-04-01 18:16:43 +03:00
wdev - > ext_reset = of_property_read_bool ( pdev - > dev . of_node ,
" fsl,ext-reset-output " ) ;
2014-04-11 10:57:14 +04:00
platform_set_drvdata ( pdev , wdog ) ;
watchdog_set_drvdata ( wdog , wdev ) ;
watchdog_set_nowayout ( wdog , nowayout ) ;
2015-11-16 20:28:04 +03:00
watchdog_set_restart_priority ( wdog , 128 ) ;
2014-04-11 10:57:14 +04:00
watchdog_init_timeout ( wdog , timeout , & pdev - > dev ) ;
2016-02-29 00:12:20 +03:00
if ( imx2_wdt_is_running ( wdev ) ) {
imx2_wdt_set_timeout ( wdog , wdog - > timeout ) ;
set_bit ( WDOG_HW_RUNNING , & wdog - > status ) ;
}
2014-04-11 10:57:14 +04:00
2014-09-08 11:14:07 +04:00
/*
* Disable the watchdog power down counter at boot . Otherwise the power
* down counter will pull down the # WDOG interrupt line for one clock
* cycle .
*/
regmap_write ( wdev - > regmap , IMX2_WDT_WMCR , 0 ) ;
2014-04-11 10:57:14 +04:00
ret = watchdog_register_device ( wdog ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " cannot register watchdog device \n " ) ;
2015-06-22 07:16:19 +03:00
goto disable_clk ;
2014-04-11 10:57:14 +04:00
}
dev_info ( & pdev - > dev , " timeout %d sec (nowayout=%d) \n " ,
wdog - > timeout , nowayout ) ;
return 0 ;
2015-06-22 07:16:19 +03:00
disable_clk :
clk_disable_unprepare ( wdev - > clk ) ;
return ret ;
2010-04-29 12:03:17 +04:00
}
static int __exit imx2_wdt_remove ( struct platform_device * pdev )
{
2014-04-11 10:57:14 +04:00
struct watchdog_device * wdog = platform_get_drvdata ( pdev ) ;
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
watchdog_unregister_device ( wdog ) ;
2010-04-29 12:03:17 +04:00
2014-04-11 10:57:14 +04:00
if ( imx2_wdt_is_running ( wdev ) ) {
imx2_wdt_ping ( wdog ) ;
dev_crit ( & pdev - > dev , " Device removed: Expect reboot! \n " ) ;
2013-04-29 13:15:53 +04:00
}
2010-04-29 12:03:17 +04:00
return 0 ;
}
static void imx2_wdt_shutdown ( struct platform_device * pdev )
{
2014-04-11 10:57:14 +04:00
struct watchdog_device * wdog = platform_get_drvdata ( pdev ) ;
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
if ( imx2_wdt_is_running ( wdev ) ) {
/*
2016-02-29 00:12:20 +03:00
* We are running , configure max timeout before reboot
* will take place .
2014-04-11 10:57:14 +04:00
*/
imx2_wdt_set_timeout ( wdog , IMX2_WDT_MAX_TIME ) ;
imx2_wdt_ping ( wdog ) ;
dev_crit ( & pdev - > dev , " Device shutdown: Expect reboot! \n " ) ;
2010-04-29 12:03:17 +04:00
}
}
2014-09-22 14:00:52 +04:00
# ifdef CONFIG_PM_SLEEP
2014-10-16 07:44:15 +04:00
/* Disable watchdog if it is active or non-active but still running */
2014-09-22 14:00:52 +04:00
static int imx2_wdt_suspend ( struct device * dev )
{
struct watchdog_device * wdog = dev_get_drvdata ( dev ) ;
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2014-10-16 07:44:15 +04:00
/* The watchdog IP block is running */
if ( imx2_wdt_is_running ( wdev ) ) {
2018-01-01 20:26:47 +03:00
/*
* Don ' t update wdog - > timeout , we ' ll restore the current value
* during resume .
*/
__imx2_wdt_set_timeout ( wdog , IMX2_WDT_MAX_TIME ) ;
2014-10-16 07:44:15 +04:00
imx2_wdt_ping ( wdog ) ;
}
2014-09-22 14:00:52 +04:00
clk_disable_unprepare ( wdev - > clk ) ;
return 0 ;
}
/* Enable watchdog and configure it if necessary */
static int imx2_wdt_resume ( struct device * dev )
{
struct watchdog_device * wdog = dev_get_drvdata ( dev ) ;
struct imx2_wdt_device * wdev = watchdog_get_drvdata ( wdog ) ;
2015-06-22 07:16:18 +03:00
int ret ;
2014-09-22 14:00:52 +04:00
2015-06-22 07:16:18 +03:00
ret = clk_prepare_enable ( wdev - > clk ) ;
if ( ret )
return ret ;
2014-09-22 14:00:52 +04:00
if ( watchdog_active ( wdog ) & & ! imx2_wdt_is_running ( wdev ) ) {
2014-10-16 07:44:15 +04:00
/*
* If the watchdog is still active and resumes
* from deep sleep state , need to restart the
* watchdog again .
2014-09-22 14:00:52 +04:00
*/
imx2_wdt_setup ( wdog ) ;
2016-02-29 00:12:20 +03:00
}
if ( imx2_wdt_is_running ( wdev ) ) {
2014-09-22 14:00:52 +04:00
imx2_wdt_set_timeout ( wdog , wdog - > timeout ) ;
imx2_wdt_ping ( wdog ) ;
}
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( imx2_wdt_pm_ops , imx2_wdt_suspend ,
imx2_wdt_resume ) ;
2011-07-18 07:15:21 +04:00
static const struct of_device_id imx2_wdt_dt_ids [ ] = {
{ . compatible = " fsl,imx21-wdt " , } ,
{ /* sentinel */ }
} ;
2013-07-29 11:38:18 +04:00
MODULE_DEVICE_TABLE ( of , imx2_wdt_dt_ids ) ;
2011-07-18 07:15:21 +04:00
2010-04-29 12:03:17 +04:00
static struct platform_driver imx2_wdt_driver = {
. remove = __exit_p ( imx2_wdt_remove ) ,
. shutdown = imx2_wdt_shutdown ,
. driver = {
. name = DRIVER_NAME ,
2014-09-22 14:00:52 +04:00
. pm = & imx2_wdt_pm_ops ,
2011-07-18 07:15:21 +04:00
. of_match_table = imx2_wdt_dt_ids ,
2010-04-29 12:03:17 +04:00
} ,
} ;
2013-01-09 15:15:27 +04:00
module_platform_driver_probe ( imx2_wdt_driver , imx2_wdt_probe ) ;
2010-04-29 12:03:17 +04:00
MODULE_AUTHOR ( " Wolfram Sang " ) ;
MODULE_DESCRIPTION ( " Watchdog driver for IMX2 and later " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;