1*e4e0848aSCL Wang // SPDX-License-Identifier: GPL-2.0-or-later 2*e4e0848aSCL Wang /* 3*e4e0848aSCL Wang * Andes ATCWDT200 watchdog timer driver. 4*e4e0848aSCL Wang * 5*e4e0848aSCL Wang * Copyright (C) 2025 Andes Technology Corporation 6*e4e0848aSCL Wang */ 7*e4e0848aSCL Wang 8*e4e0848aSCL Wang #include <linux/bitfield.h> 9*e4e0848aSCL Wang #include <linux/clk.h> 10*e4e0848aSCL Wang #include <linux/device.h> 11*e4e0848aSCL Wang #include <linux/dev_printk.h> 12*e4e0848aSCL Wang #include <linux/math64.h> 13*e4e0848aSCL Wang #include <linux/minmax.h> 14*e4e0848aSCL Wang #include <linux/moduleparam.h> 15*e4e0848aSCL Wang #include <linux/module.h> 16*e4e0848aSCL Wang #include <linux/of.h> 17*e4e0848aSCL Wang #include <linux/of_platform.h> 18*e4e0848aSCL Wang #include <linux/platform_device.h> 19*e4e0848aSCL Wang #include <linux/pm.h> 20*e4e0848aSCL Wang #include <linux/pm_runtime.h> 21*e4e0848aSCL Wang #include <linux/regmap.h> 22*e4e0848aSCL Wang #include <linux/watchdog.h> 23*e4e0848aSCL Wang 24*e4e0848aSCL Wang /* Register definitions */ 25*e4e0848aSCL Wang #define REG_CTRL 0x10 26*e4e0848aSCL Wang #define REG_RESTART 0x14 27*e4e0848aSCL Wang #define REG_WRITE_EN 0x18 28*e4e0848aSCL Wang #define REG_STATUS 0x1C 29*e4e0848aSCL Wang 30*e4e0848aSCL Wang /* Control Register */ 31*e4e0848aSCL Wang #define CTRL_RST_TIME_MSK GENMASK(10, 8) 32*e4e0848aSCL Wang #define CTRL_RST_TIME_SET(x) FIELD_PREP(CTRL_RST_TIME_MSK, x) 33*e4e0848aSCL Wang #define CTRL_INT_TIME_MSK GENMASK(7, 4) 34*e4e0848aSCL Wang #define CTRL_INT_TIME_SET(x) FIELD_PREP(CTRL_INT_TIME_MSK, x) 35*e4e0848aSCL Wang #define CTRL_INT_TIME_GET(x) FIELD_GET(CTRL_INT_TIME_MSK, x) 36*e4e0848aSCL Wang #define CTRL_RST_EN BIT(3) 37*e4e0848aSCL Wang #define CTRL_CLK_SEL BIT(1) 38*e4e0848aSCL Wang #define CTRL_CLK_SEL_PCLK 1 39*e4e0848aSCL Wang #define CTRL_CLK_SEL_SET(x) FIELD_PREP(CTRL_CLK_SEL, x) 40*e4e0848aSCL Wang #define CTRL_WDT_EN BIT(0) 41*e4e0848aSCL Wang 42*e4e0848aSCL Wang /* Restart Register */ 43*e4e0848aSCL Wang #define RESTART_MAGIC 0xCAFE 44*e4e0848aSCL Wang 45*e4e0848aSCL Wang /* Write Enable Register */ 46*e4e0848aSCL Wang #define WRITE_EN_MAGIC 0x5AA5 47*e4e0848aSCL Wang 48*e4e0848aSCL Wang /* Status Register */ 49*e4e0848aSCL Wang #define STATUS_INT_EXPIRED BIT(1) 50*e4e0848aSCL Wang 51*e4e0848aSCL Wang /* The default timeout value in seconds */ 52*e4e0848aSCL Wang #define ATCWDT_TIMEOUT 4 53*e4e0848aSCL Wang 54*e4e0848aSCL Wang /* Define the array size for each timer type */ 55*e4e0848aSCL Wang #define TMR_SZ_RST 8 56*e4e0848aSCL Wang #define TMR_SZ_INT_16 8 57*e4e0848aSCL Wang #define TMR_SZ_INT_32 16 58*e4e0848aSCL Wang 59*e4e0848aSCL Wang #define DRV_NAME "atcwdt200" 60*e4e0848aSCL Wang /** 61*e4e0848aSCL Wang * enum timer_type - Supported timer types for ATCWDT200 watchdog driver 62*e4e0848aSCL Wang * @TMR_RST: Reset timer (non-interrupt). 63*e4e0848aSCL Wang * @TMR_INT_16: 16-bit interrupt timer supported by hardware. 64*e4e0848aSCL Wang * @TMR_INT_32: 32-bit interrupt timer supported by hardware. 65*e4e0848aSCL Wang * @TMR_UNKNOWN: Timer type cannot be determined. 66*e4e0848aSCL Wang */ 67*e4e0848aSCL Wang enum timer_type { 68*e4e0848aSCL Wang TMR_RST, 69*e4e0848aSCL Wang TMR_INT_16, 70*e4e0848aSCL Wang TMR_INT_32, 71*e4e0848aSCL Wang TMR_UNKNOWN 72*e4e0848aSCL Wang }; 73*e4e0848aSCL Wang 74*e4e0848aSCL Wang static unsigned int timeout = ATCWDT_TIMEOUT; 75*e4e0848aSCL Wang static bool nowayout = WATCHDOG_NOWAYOUT; 76*e4e0848aSCL Wang 77*e4e0848aSCL Wang /** 78*e4e0848aSCL Wang * struct atcwdt_drv - ATCWDT200 watchdog driver private data 79*e4e0848aSCL Wang * @wdt_dev: Watchdog device used by the watchdog framework. 80*e4e0848aSCL Wang * @regmap: Register map for accessing hardware registers. 81*e4e0848aSCL Wang * @clk: Hardware clock used by the watchdog timer. 82*e4e0848aSCL Wang * @lock: Spinlock protecting register accesses and driver state. 83*e4e0848aSCL Wang * @clk_freq: Input clock frequency of the ATCWDT200. 84*e4e0848aSCL Wang * @clk_src: Selected clock source for the watchdog timer. 85*e4e0848aSCL Wang * @int_timer_type: Detected interrupt timer type (16-bit, 32-bit, or unknown). 86*e4e0848aSCL Wang */ 87*e4e0848aSCL Wang struct atcwdt_drv { 88*e4e0848aSCL Wang struct watchdog_device wdt_dev; 89*e4e0848aSCL Wang struct regmap *regmap; 90*e4e0848aSCL Wang struct clk *clk; 91*e4e0848aSCL Wang spinlock_t lock; 92*e4e0848aSCL Wang unsigned int clk_freq; 93*e4e0848aSCL Wang unsigned char clk_src; 94*e4e0848aSCL Wang unsigned char int_timer_type; 95*e4e0848aSCL Wang }; 96*e4e0848aSCL Wang 97*e4e0848aSCL Wang static const struct watchdog_info atcwdt_info = { 98*e4e0848aSCL Wang .identity = DRV_NAME, 99*e4e0848aSCL Wang .options = WDIOF_SETTIMEOUT | 100*e4e0848aSCL Wang WDIOF_KEEPALIVEPING | 101*e4e0848aSCL Wang WDIOF_MAGICCLOSE, 102*e4e0848aSCL Wang }; 103*e4e0848aSCL Wang 104*e4e0848aSCL Wang /** 105*e4e0848aSCL Wang * atcwdt_get_index - Get the interval value for the specified timer type 106*e4e0848aSCL Wang * @index: The index of the interval in the array 107*e4e0848aSCL Wang * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or 108*e4e0848aSCL Wang * TMR_INT_32. 109*e4e0848aSCL Wang * 110*e4e0848aSCL Wang * This function retrieves the interval value based on the timer type and 111*e4e0848aSCL Wang * ensures the index stays within the valid range for the given timer type. 112*e4e0848aSCL Wang * For TMR_RST: 113*e4e0848aSCL Wang * - The maximum array size is 8 (index range: 0-7). 114*e4e0848aSCL Wang * For TMR_INT_16: 115*e4e0848aSCL Wang * - The maximum array size is 8 (index range: 0-7). 116*e4e0848aSCL Wang * For TMR_INT_32: 117*e4e0848aSCL Wang * - The maximum array size is 16 (index range: 0-15). 118*e4e0848aSCL Wang * 119*e4e0848aSCL Wang * If the index exceeds the maximum array size, the function will return 120*e4e0848aSCL Wang * the last element of the respective array. 121*e4e0848aSCL Wang */ 122*e4e0848aSCL Wang static inline unsigned char atcwdt_get_index(unsigned char index, 123*e4e0848aSCL Wang enum timer_type timer_type) 124*e4e0848aSCL Wang { 125*e4e0848aSCL Wang static const unsigned char rst_timer_interval[TMR_SZ_RST] = { 126*e4e0848aSCL Wang 7, 8, 9, 10, 11, 12, 13, 14}; 127*e4e0848aSCL Wang static const unsigned char int_timer_interval[TMR_SZ_INT_32] = { 128*e4e0848aSCL Wang 6, 8, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}; 129*e4e0848aSCL Wang unsigned char array_index; 130*e4e0848aSCL Wang 131*e4e0848aSCL Wang if (timer_type == TMR_RST) { 132*e4e0848aSCL Wang array_index = min(index, TMR_SZ_RST - 1); 133*e4e0848aSCL Wang return rst_timer_interval[array_index]; 134*e4e0848aSCL Wang } 135*e4e0848aSCL Wang 136*e4e0848aSCL Wang if (timer_type == TMR_INT_32) 137*e4e0848aSCL Wang array_index = min(index, TMR_SZ_INT_32 - 1); 138*e4e0848aSCL Wang else 139*e4e0848aSCL Wang array_index = min(index, TMR_SZ_INT_16 - 1); 140*e4e0848aSCL Wang 141*e4e0848aSCL Wang return int_timer_interval[array_index]; 142*e4e0848aSCL Wang } 143*e4e0848aSCL Wang 144*e4e0848aSCL Wang /** 145*e4e0848aSCL Wang * atcwdt_get_clock_period - Calculate the closest clock period based on a 146*e4e0848aSCL Wang * given tick count 147*e4e0848aSCL Wang * @tick: The target tick count to match 148*e4e0848aSCL Wang * @timer_type: The type of timer, which can be TMR_RST, TMR_INT_16, or 149*e4e0848aSCL Wang * TMR_INT_32. 150*e4e0848aSCL Wang * @index: Pointer to store the index of the selected parameter 151*e4e0848aSCL Wang * 152*e4e0848aSCL Wang * This function calculates the closest clock period to the given tick count 153*e4e0848aSCL Wang * by iterating through the timer parameters and selecting the one that 154*e4e0848aSCL Wang * minimizes the difference between the target tick count and the calculated 155*e4e0848aSCL Wang * clock period. The function determines the index of the closest parameter 156*e4e0848aSCL Wang * and returns the difference between the target tick count and the selected 157*e4e0848aSCL Wang * clock period. 158*e4e0848aSCL Wang * 159*e4e0848aSCL Wang * Return: The difference between the target tick count and the selected 160*e4e0848aSCL Wang * clock period. 161*e4e0848aSCL Wang */ 162*e4e0848aSCL Wang static long long atcwdt_get_clock_period(long long tick, 163*e4e0848aSCL Wang enum timer_type timer_type, 164*e4e0848aSCL Wang unsigned char *index) 165*e4e0848aSCL Wang { 166*e4e0848aSCL Wang long long result; 167*e4e0848aSCL Wang unsigned char size; 168*e4e0848aSCL Wang char i; 169*e4e0848aSCL Wang 170*e4e0848aSCL Wang if (timer_type == TMR_RST) 171*e4e0848aSCL Wang size = TMR_SZ_RST; 172*e4e0848aSCL Wang else if (timer_type == TMR_INT_32) 173*e4e0848aSCL Wang size = TMR_SZ_INT_32; 174*e4e0848aSCL Wang else 175*e4e0848aSCL Wang size = TMR_SZ_INT_16; 176*e4e0848aSCL Wang 177*e4e0848aSCL Wang *index = size - 1; 178*e4e0848aSCL Wang for (i = 0; i < size; i++) { 179*e4e0848aSCL Wang result = tick - (1LL << atcwdt_get_index(i, timer_type)); 180*e4e0848aSCL Wang 181*e4e0848aSCL Wang if (result <= 1) { 182*e4e0848aSCL Wang *index = i; 183*e4e0848aSCL Wang break; 184*e4e0848aSCL Wang } 185*e4e0848aSCL Wang } 186*e4e0848aSCL Wang 187*e4e0848aSCL Wang return result; 188*e4e0848aSCL Wang } 189*e4e0848aSCL Wang 190*e4e0848aSCL Wang /** 191*e4e0848aSCL Wang * atcwdt_get_timeout_params - Calculate optimal parameters for Watchdog Timer 192*e4e0848aSCL Wang * @drv_data: Pointer to the Watchdog driver data structure 193*e4e0848aSCL Wang * @timeout: Desired timeout value (in seconds) 194*e4e0848aSCL Wang * @int_timer_params: Pointer to store the calculated interrupt timer 195*e4e0848aSCL Wang * parameter index 196*e4e0848aSCL Wang * @rst_timer_params: Pointer to store the calculated reset timer parameter 197*e4e0848aSCL Wang * index 198*e4e0848aSCL Wang * 199*e4e0848aSCL Wang * This function calculates the optimal parameter combination for the 200*e4e0848aSCL Wang * interrupt timer and reset timer of the Watchdog Timer to achieve a 201*e4e0848aSCL Wang * timeout value closest to, but not less than the specified timeout. 202*e4e0848aSCL Wang * 203*e4e0848aSCL Wang * Algorithm: 204*e4e0848aSCL Wang * 1. The parameters for both the interrupt timer and reset timer are 205*e4e0848aSCL Wang * predefined as a series of options represented as powers of 2. 206*e4e0848aSCL Wang * 2. The function first determines the interrupt timer's parameter index 207*e4e0848aSCL Wang * that provides a time closest to and not exceeding the desired timeout. 208*e4e0848aSCL Wang * 3. Based on the selected interrupt timer, it calculates the required 209*e4e0848aSCL Wang * reset timer parameter to ensure the total timeout matches the target. 210*e4e0848aSCL Wang * 211*e4e0848aSCL Wang * Return: The calculated parameter indices are stored in the provided 212*e4e0848aSCL Wang * pointers. 213*e4e0848aSCL Wang */ 214*e4e0848aSCL Wang static void atcwdt_get_timeout_params(struct atcwdt_drv *drv_data, 215*e4e0848aSCL Wang unsigned int timeout, 216*e4e0848aSCL Wang unsigned char *int_timer_params, 217*e4e0848aSCL Wang unsigned char *rst_timer_params) 218*e4e0848aSCL Wang { 219*e4e0848aSCL Wang long long rest_time_ms; 220*e4e0848aSCL Wang long long result; 221*e4e0848aSCL Wang long long tick; 222*e4e0848aSCL Wang unsigned char rst_index; 223*e4e0848aSCL Wang unsigned char int_index; 224*e4e0848aSCL Wang unsigned char above; 225*e4e0848aSCL Wang unsigned char below; 226*e4e0848aSCL Wang 227*e4e0848aSCL Wang tick = (long long)timeout * drv_data->clk_freq; 228*e4e0848aSCL Wang result = atcwdt_get_clock_period(tick, 229*e4e0848aSCL Wang drv_data->int_timer_type, 230*e4e0848aSCL Wang &above); 231*e4e0848aSCL Wang if (result == 0 || above == 0) { 232*e4e0848aSCL Wang *int_timer_params = above; 233*e4e0848aSCL Wang *rst_timer_params = 0; 234*e4e0848aSCL Wang return; 235*e4e0848aSCL Wang } 236*e4e0848aSCL Wang below = above - 1; 237*e4e0848aSCL Wang 238*e4e0848aSCL Wang int_index = atcwdt_get_index(below, drv_data->int_timer_type); 239*e4e0848aSCL Wang rest_time_ms = timeout * 1000LL 240*e4e0848aSCL Wang - div64_s64(1000LL << int_index, drv_data->clk_freq); 241*e4e0848aSCL Wang 242*e4e0848aSCL Wang result = atcwdt_get_clock_period(rest_time_ms * drv_data->clk_freq, 243*e4e0848aSCL Wang TMR_RST, 244*e4e0848aSCL Wang &rst_index); 245*e4e0848aSCL Wang 246*e4e0848aSCL Wang if (result > 1) { 247*e4e0848aSCL Wang *int_timer_params = above; 248*e4e0848aSCL Wang *rst_timer_params = 0; 249*e4e0848aSCL Wang } else { 250*e4e0848aSCL Wang *int_timer_params = below; 251*e4e0848aSCL Wang *rst_timer_params = rst_index; 252*e4e0848aSCL Wang } 253*e4e0848aSCL Wang } 254*e4e0848aSCL Wang 255*e4e0848aSCL Wang /** 256*e4e0848aSCL Wang * atcwdt_get_int_timer_type - Get the supported interrupt timer type. 257*e4e0848aSCL Wang * @drv_data: Pointer to the watchdog driver data structure. 258*e4e0848aSCL Wang * 259*e4e0848aSCL Wang * This function tests the writable bits in the IntTime field of the control 260*e4e0848aSCL Wang * register to determine the interrupt timer type supported by the hardware. 261*e4e0848aSCL Wang * 262*e4e0848aSCL Wang * Note: This function must only be called when the ATCWDT200 watchdog is 263*e4e0848aSCL Wang * disabled. If the watchdog is enabled, this function returns TMR_UNKNOWN. 264*e4e0848aSCL Wang * 265*e4e0848aSCL Wang * Returns: The interrupt timer type supported by the hardware. 266*e4e0848aSCL Wang */ 267*e4e0848aSCL Wang static int atcwdt_get_int_timer_type(struct atcwdt_drv *drv_data) 268*e4e0848aSCL Wang { 269*e4e0848aSCL Wang struct device *dev = drv_data->wdt_dev.parent; 270*e4e0848aSCL Wang unsigned int val; 271*e4e0848aSCL Wang int ret = 0; 272*e4e0848aSCL Wang 273*e4e0848aSCL Wang spin_lock(&drv_data->lock); 274*e4e0848aSCL Wang regmap_read(drv_data->regmap, REG_CTRL, &val); 275*e4e0848aSCL Wang if (val & CTRL_WDT_EN) { 276*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 277*e4e0848aSCL Wang return TMR_UNKNOWN; 278*e4e0848aSCL Wang } 279*e4e0848aSCL Wang 280*e4e0848aSCL Wang /* 281*e4e0848aSCL Wang * Configures the IntTime field with the maximum mask value 282*e4e0848aSCL Wang * (CTRL_INT_TIME_MSK), reads its value from the control register 283*e4e0848aSCL Wang * to identify the maximum writable bits. 284*e4e0848aSCL Wang */ 285*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); 286*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_CTRL, CTRL_INT_TIME_MSK); 287*e4e0848aSCL Wang regmap_read(drv_data->regmap, REG_CTRL, &val); 288*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 289*e4e0848aSCL Wang 290*e4e0848aSCL Wang val = CTRL_INT_TIME_GET(val); 291*e4e0848aSCL Wang switch (val) { 292*e4e0848aSCL Wang case 7: 293*e4e0848aSCL Wang drv_data->int_timer_type = TMR_INT_16; 294*e4e0848aSCL Wang break; 295*e4e0848aSCL Wang case 15: 296*e4e0848aSCL Wang drv_data->int_timer_type = TMR_INT_32; 297*e4e0848aSCL Wang break; 298*e4e0848aSCL Wang default: 299*e4e0848aSCL Wang drv_data->int_timer_type = TMR_UNKNOWN; 300*e4e0848aSCL Wang ret = dev_err_probe(dev, -ENODEV, 301*e4e0848aSCL Wang "Failed to detect interrupt timer type\n"); 302*e4e0848aSCL Wang } 303*e4e0848aSCL Wang 304*e4e0848aSCL Wang return ret; 305*e4e0848aSCL Wang } 306*e4e0848aSCL Wang 307*e4e0848aSCL Wang static int atcwdt_ping(struct watchdog_device *wdt_dev) 308*e4e0848aSCL Wang { 309*e4e0848aSCL Wang struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); 310*e4e0848aSCL Wang 311*e4e0848aSCL Wang spin_lock(&drv_data->lock); 312*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); 313*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_RESTART, RESTART_MAGIC); 314*e4e0848aSCL Wang regmap_update_bits(drv_data->regmap, REG_STATUS, STATUS_INT_EXPIRED, 315*e4e0848aSCL Wang STATUS_INT_EXPIRED); 316*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 317*e4e0848aSCL Wang 318*e4e0848aSCL Wang return 0; 319*e4e0848aSCL Wang } 320*e4e0848aSCL Wang 321*e4e0848aSCL Wang static int atcwdt_set_timeout(struct watchdog_device *wdt_dev, 322*e4e0848aSCL Wang unsigned int timeout) 323*e4e0848aSCL Wang { 324*e4e0848aSCL Wang struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); 325*e4e0848aSCL Wang unsigned int value; 326*e4e0848aSCL Wang unsigned char rst_val; 327*e4e0848aSCL Wang unsigned char int_val; 328*e4e0848aSCL Wang 329*e4e0848aSCL Wang wdt_dev->timeout = timeout; 330*e4e0848aSCL Wang atcwdt_get_timeout_params(drv_data, timeout, &int_val, &rst_val); 331*e4e0848aSCL Wang 332*e4e0848aSCL Wang spin_lock(&drv_data->lock); 333*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); 334*e4e0848aSCL Wang 335*e4e0848aSCL Wang value = CTRL_RST_TIME_SET(rst_val) | 336*e4e0848aSCL Wang CTRL_INT_TIME_SET(int_val) | 337*e4e0848aSCL Wang CTRL_CLK_SEL_SET(drv_data->clk_src); 338*e4e0848aSCL Wang regmap_update_bits(drv_data->regmap, 339*e4e0848aSCL Wang REG_CTRL, 340*e4e0848aSCL Wang CTRL_RST_TIME_MSK | 341*e4e0848aSCL Wang CTRL_INT_TIME_MSK | 342*e4e0848aSCL Wang CTRL_CLK_SEL, 343*e4e0848aSCL Wang value); 344*e4e0848aSCL Wang 345*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 346*e4e0848aSCL Wang atcwdt_ping(wdt_dev); 347*e4e0848aSCL Wang 348*e4e0848aSCL Wang return 0; 349*e4e0848aSCL Wang } 350*e4e0848aSCL Wang 351*e4e0848aSCL Wang static int atcwdt_start(struct watchdog_device *wdt_dev) 352*e4e0848aSCL Wang { 353*e4e0848aSCL Wang struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); 354*e4e0848aSCL Wang 355*e4e0848aSCL Wang atcwdt_set_timeout(wdt_dev, wdt_dev->timeout); 356*e4e0848aSCL Wang 357*e4e0848aSCL Wang spin_lock(&drv_data->lock); 358*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); 359*e4e0848aSCL Wang regmap_update_bits(drv_data->regmap, 360*e4e0848aSCL Wang REG_CTRL, 361*e4e0848aSCL Wang CTRL_RST_EN | CTRL_WDT_EN, 362*e4e0848aSCL Wang CTRL_RST_EN | CTRL_WDT_EN); 363*e4e0848aSCL Wang 364*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 365*e4e0848aSCL Wang 366*e4e0848aSCL Wang return 0; 367*e4e0848aSCL Wang } 368*e4e0848aSCL Wang 369*e4e0848aSCL Wang static int atcwdt_stop(struct watchdog_device *wdt_dev) 370*e4e0848aSCL Wang { 371*e4e0848aSCL Wang struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); 372*e4e0848aSCL Wang 373*e4e0848aSCL Wang spin_lock(&drv_data->lock); 374*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); 375*e4e0848aSCL Wang regmap_update_bits(drv_data->regmap, 376*e4e0848aSCL Wang REG_CTRL, 377*e4e0848aSCL Wang CTRL_RST_EN | CTRL_WDT_EN, 378*e4e0848aSCL Wang 0); 379*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 380*e4e0848aSCL Wang 381*e4e0848aSCL Wang return 0; 382*e4e0848aSCL Wang } 383*e4e0848aSCL Wang 384*e4e0848aSCL Wang static int atcwdt_restart(struct watchdog_device *wdt_dev, 385*e4e0848aSCL Wang unsigned long action, void *data) 386*e4e0848aSCL Wang { 387*e4e0848aSCL Wang struct atcwdt_drv *drv_data = watchdog_get_drvdata(wdt_dev); 388*e4e0848aSCL Wang 389*e4e0848aSCL Wang atcwdt_set_timeout(wdt_dev, 0); 390*e4e0848aSCL Wang 391*e4e0848aSCL Wang spin_lock(&drv_data->lock); 392*e4e0848aSCL Wang regmap_write(drv_data->regmap, REG_WRITE_EN, WRITE_EN_MAGIC); 393*e4e0848aSCL Wang regmap_update_bits(drv_data->regmap, 394*e4e0848aSCL Wang REG_CTRL, 395*e4e0848aSCL Wang CTRL_RST_EN | CTRL_WDT_EN, 396*e4e0848aSCL Wang CTRL_RST_EN | CTRL_WDT_EN); 397*e4e0848aSCL Wang spin_unlock(&drv_data->lock); 398*e4e0848aSCL Wang 399*e4e0848aSCL Wang return 0; 400*e4e0848aSCL Wang } 401*e4e0848aSCL Wang 402*e4e0848aSCL Wang static const struct watchdog_ops atcwdt_ops = { 403*e4e0848aSCL Wang .owner = THIS_MODULE, 404*e4e0848aSCL Wang .start = atcwdt_start, 405*e4e0848aSCL Wang .stop = atcwdt_stop, 406*e4e0848aSCL Wang .ping = atcwdt_ping, 407*e4e0848aSCL Wang .set_timeout = atcwdt_set_timeout, 408*e4e0848aSCL Wang .restart = atcwdt_restart, 409*e4e0848aSCL Wang }; 410*e4e0848aSCL Wang 411*e4e0848aSCL Wang static int atcwdt_init_resource(struct platform_device *pdev, 412*e4e0848aSCL Wang struct atcwdt_drv *drv_data) 413*e4e0848aSCL Wang { 414*e4e0848aSCL Wang struct device *dev = &pdev->dev; 415*e4e0848aSCL Wang void __iomem *base; 416*e4e0848aSCL Wang const struct regmap_config cfg = { 417*e4e0848aSCL Wang .name = "atcwdt", 418*e4e0848aSCL Wang .reg_bits = 32, 419*e4e0848aSCL Wang .val_bits = 32, 420*e4e0848aSCL Wang .cache_type = REGCACHE_NONE, 421*e4e0848aSCL Wang .reg_stride = 4, 422*e4e0848aSCL Wang .max_register = REG_STATUS, 423*e4e0848aSCL Wang }; 424*e4e0848aSCL Wang 425*e4e0848aSCL Wang base = devm_platform_ioremap_resource(pdev, 0); 426*e4e0848aSCL Wang if (IS_ERR(base)) 427*e4e0848aSCL Wang return dev_err_probe(dev, PTR_ERR(base), 428*e4e0848aSCL Wang "Failed to ioremap I/O resource\n"); 429*e4e0848aSCL Wang 430*e4e0848aSCL Wang drv_data->regmap = devm_regmap_init_mmio(dev, base, &cfg); 431*e4e0848aSCL Wang if (IS_ERR(drv_data->regmap)) 432*e4e0848aSCL Wang return dev_err_probe(dev, PTR_ERR(drv_data->regmap), 433*e4e0848aSCL Wang "Failed to create regmap\n"); 434*e4e0848aSCL Wang 435*e4e0848aSCL Wang return 0; 436*e4e0848aSCL Wang } 437*e4e0848aSCL Wang 438*e4e0848aSCL Wang static int atcwdt_enable_clk(struct atcwdt_drv *drv_data) 439*e4e0848aSCL Wang { 440*e4e0848aSCL Wang struct device *dev = drv_data->wdt_dev.parent; 441*e4e0848aSCL Wang unsigned int val; 442*e4e0848aSCL Wang int clk_src; 443*e4e0848aSCL Wang 444*e4e0848aSCL Wang drv_data->clk = devm_clk_get_enabled(dev, NULL); 445*e4e0848aSCL Wang if (IS_ERR(drv_data->clk)) 446*e4e0848aSCL Wang return dev_err_probe(dev, PTR_ERR(drv_data->clk), 447*e4e0848aSCL Wang "Failed to get watchdog clock\n"); 448*e4e0848aSCL Wang 449*e4e0848aSCL Wang drv_data->clk_freq = clk_get_rate(drv_data->clk); 450*e4e0848aSCL Wang if (!drv_data->clk_freq) 451*e4e0848aSCL Wang return dev_err_probe(dev, -EINVAL, 452*e4e0848aSCL Wang "Failed to get clock rate\n"); 453*e4e0848aSCL Wang 454*e4e0848aSCL Wang clk_src = device_property_read_u32(dev, "andestech,clock-source", &val); 455*e4e0848aSCL Wang drv_data->clk_src = (!clk_src && val != 0) ? CTRL_CLK_SEL_PCLK : 0; 456*e4e0848aSCL Wang 457*e4e0848aSCL Wang return 0; 458*e4e0848aSCL Wang } 459*e4e0848aSCL Wang 460*e4e0848aSCL Wang static int atcwdt_init_wdt_device(struct device *dev, 461*e4e0848aSCL Wang struct atcwdt_drv *drv_data) 462*e4e0848aSCL Wang { 463*e4e0848aSCL Wang struct watchdog_device *wdd = &drv_data->wdt_dev; 464*e4e0848aSCL Wang 465*e4e0848aSCL Wang wdd->parent = dev; 466*e4e0848aSCL Wang wdd->info = &atcwdt_info; 467*e4e0848aSCL Wang wdd->ops = &atcwdt_ops; 468*e4e0848aSCL Wang wdd->timeout = ATCWDT_TIMEOUT; 469*e4e0848aSCL Wang wdd->min_timeout = 1; 470*e4e0848aSCL Wang 471*e4e0848aSCL Wang watchdog_set_nowayout(wdd, nowayout); 472*e4e0848aSCL Wang watchdog_set_drvdata(wdd, drv_data); 473*e4e0848aSCL Wang 474*e4e0848aSCL Wang return 0; 475*e4e0848aSCL Wang } 476*e4e0848aSCL Wang 477*e4e0848aSCL Wang static void atcwdt_calc_max_timeout(struct atcwdt_drv *drv_data) 478*e4e0848aSCL Wang { 479*e4e0848aSCL Wang unsigned char rst_idx = atcwdt_get_index(0xFF, TMR_RST); 480*e4e0848aSCL Wang unsigned char int_idx = atcwdt_get_index(0xFF, 481*e4e0848aSCL Wang drv_data->int_timer_type); 482*e4e0848aSCL Wang 483*e4e0848aSCL Wang drv_data->wdt_dev.max_timeout = 484*e4e0848aSCL Wang ((1U << rst_idx) + (1U << int_idx)) / drv_data->clk_freq; 485*e4e0848aSCL Wang } 486*e4e0848aSCL Wang 487*e4e0848aSCL Wang static int atcwdt_probe(struct platform_device *pdev) 488*e4e0848aSCL Wang { 489*e4e0848aSCL Wang struct device *dev = &pdev->dev; 490*e4e0848aSCL Wang struct atcwdt_drv *drv_data; 491*e4e0848aSCL Wang int ret; 492*e4e0848aSCL Wang 493*e4e0848aSCL Wang drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); 494*e4e0848aSCL Wang if (!drv_data) 495*e4e0848aSCL Wang return -ENOMEM; 496*e4e0848aSCL Wang 497*e4e0848aSCL Wang platform_set_drvdata(pdev, drv_data); 498*e4e0848aSCL Wang spin_lock_init(&drv_data->lock); 499*e4e0848aSCL Wang 500*e4e0848aSCL Wang ret = atcwdt_init_wdt_device(dev, drv_data); 501*e4e0848aSCL Wang if (ret) 502*e4e0848aSCL Wang return ret; 503*e4e0848aSCL Wang 504*e4e0848aSCL Wang ret = atcwdt_init_resource(pdev, drv_data); 505*e4e0848aSCL Wang if (ret) 506*e4e0848aSCL Wang return ret; 507*e4e0848aSCL Wang 508*e4e0848aSCL Wang ret = atcwdt_enable_clk(drv_data); 509*e4e0848aSCL Wang if (ret) 510*e4e0848aSCL Wang return ret; 511*e4e0848aSCL Wang 512*e4e0848aSCL Wang ret = atcwdt_get_int_timer_type(drv_data); 513*e4e0848aSCL Wang if (ret) 514*e4e0848aSCL Wang return ret; 515*e4e0848aSCL Wang 516*e4e0848aSCL Wang atcwdt_calc_max_timeout(drv_data); 517*e4e0848aSCL Wang 518*e4e0848aSCL Wang ret = devm_watchdog_register_device(dev, &drv_data->wdt_dev); 519*e4e0848aSCL Wang 520*e4e0848aSCL Wang return ret; 521*e4e0848aSCL Wang } 522*e4e0848aSCL Wang 523*e4e0848aSCL Wang static int atcwdt_suspend(struct device *dev) 524*e4e0848aSCL Wang { 525*e4e0848aSCL Wang struct atcwdt_drv *drv_data = dev_get_drvdata(dev); 526*e4e0848aSCL Wang 527*e4e0848aSCL Wang if (watchdog_active(&drv_data->wdt_dev)) { 528*e4e0848aSCL Wang atcwdt_stop(&drv_data->wdt_dev); 529*e4e0848aSCL Wang clk_disable_unprepare(drv_data->clk); 530*e4e0848aSCL Wang } 531*e4e0848aSCL Wang 532*e4e0848aSCL Wang return 0; 533*e4e0848aSCL Wang } 534*e4e0848aSCL Wang 535*e4e0848aSCL Wang static int atcwdt_resume(struct device *dev) 536*e4e0848aSCL Wang { 537*e4e0848aSCL Wang struct atcwdt_drv *drv_data = dev_get_drvdata(dev); 538*e4e0848aSCL Wang int ret = 0; 539*e4e0848aSCL Wang 540*e4e0848aSCL Wang if (watchdog_active(&drv_data->wdt_dev)) { 541*e4e0848aSCL Wang ret = clk_prepare_enable(drv_data->clk); 542*e4e0848aSCL Wang if (ret) 543*e4e0848aSCL Wang return ret; 544*e4e0848aSCL Wang atcwdt_start(&drv_data->wdt_dev); 545*e4e0848aSCL Wang atcwdt_ping(&drv_data->wdt_dev); 546*e4e0848aSCL Wang } 547*e4e0848aSCL Wang 548*e4e0848aSCL Wang return ret; 549*e4e0848aSCL Wang } 550*e4e0848aSCL Wang 551*e4e0848aSCL Wang static const struct of_device_id atcwdt_match[] = { 552*e4e0848aSCL Wang { .compatible = "andestech,ae350-wdt" }, 553*e4e0848aSCL Wang { /* sentinel */ }, 554*e4e0848aSCL Wang }; 555*e4e0848aSCL Wang MODULE_DEVICE_TABLE(of, atcwdt_match); 556*e4e0848aSCL Wang 557*e4e0848aSCL Wang static DEFINE_SIMPLE_DEV_PM_OPS(atcwdt_pm_ops, atcwdt_suspend, atcwdt_resume); 558*e4e0848aSCL Wang 559*e4e0848aSCL Wang static struct platform_driver atcwdt_driver = { 560*e4e0848aSCL Wang .probe = atcwdt_probe, 561*e4e0848aSCL Wang .driver = { 562*e4e0848aSCL Wang .name = DRV_NAME, 563*e4e0848aSCL Wang .of_match_table = atcwdt_match, 564*e4e0848aSCL Wang .pm = pm_sleep_ptr(&atcwdt_pm_ops), 565*e4e0848aSCL Wang }, 566*e4e0848aSCL Wang }; 567*e4e0848aSCL Wang 568*e4e0848aSCL Wang module_platform_driver(atcwdt_driver); 569*e4e0848aSCL Wang 570*e4e0848aSCL Wang module_param(timeout, uint, 0); 571*e4e0848aSCL Wang MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" 572*e4e0848aSCL Wang __MODULE_STRING(ATCWDT_TIMEOUT) ")"); 573*e4e0848aSCL Wang 574*e4e0848aSCL Wang module_param(nowayout, bool, 0); 575*e4e0848aSCL Wang MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 576*e4e0848aSCL Wang __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 577*e4e0848aSCL Wang 578*e4e0848aSCL Wang MODULE_LICENSE("GPL"); 579*e4e0848aSCL Wang MODULE_AUTHOR("CL Wang <cl634@andestech.com>"); 580*e4e0848aSCL Wang MODULE_DESCRIPTION("Andes ATCWDT200 Watchdog timer driver"); 581