1*42cee19aSThierry Reding // SPDX-License-Identifier: GPL-2.0-only 2*42cee19aSThierry Reding /* 3*42cee19aSThierry Reding * Copyright (c) 2019-2020 NVIDIA Corporation. All rights reserved. 4*42cee19aSThierry Reding */ 5*42cee19aSThierry Reding 6*42cee19aSThierry Reding #include <linux/clocksource.h> 7*42cee19aSThierry Reding #include <linux/module.h> 8*42cee19aSThierry Reding #include <linux/interrupt.h> 9*42cee19aSThierry Reding #include <linux/io.h> 10*42cee19aSThierry Reding #include <linux/of.h> 11*42cee19aSThierry Reding #include <linux/of_device.h> 12*42cee19aSThierry Reding #include <linux/platform_device.h> 13*42cee19aSThierry Reding #include <linux/pm.h> 14*42cee19aSThierry Reding #include <linux/watchdog.h> 15*42cee19aSThierry Reding 16*42cee19aSThierry Reding /* shared registers */ 17*42cee19aSThierry Reding #define TKETSC0 0x000 18*42cee19aSThierry Reding #define TKETSC1 0x004 19*42cee19aSThierry Reding #define TKEUSEC 0x008 20*42cee19aSThierry Reding #define TKEOSC 0x00c 21*42cee19aSThierry Reding 22*42cee19aSThierry Reding #define TKEIE(x) (0x100 + ((x) * 4)) 23*42cee19aSThierry Reding #define TKEIE_WDT_MASK(x, y) ((y) << (16 + 4 * (x))) 24*42cee19aSThierry Reding 25*42cee19aSThierry Reding /* timer registers */ 26*42cee19aSThierry Reding #define TMRCR 0x000 27*42cee19aSThierry Reding #define TMRCR_ENABLE BIT(31) 28*42cee19aSThierry Reding #define TMRCR_PERIODIC BIT(30) 29*42cee19aSThierry Reding #define TMRCR_PTV(x) ((x) & 0x0fffffff) 30*42cee19aSThierry Reding 31*42cee19aSThierry Reding #define TMRSR 0x004 32*42cee19aSThierry Reding #define TMRSR_INTR_CLR BIT(30) 33*42cee19aSThierry Reding 34*42cee19aSThierry Reding #define TMRCSSR 0x008 35*42cee19aSThierry Reding #define TMRCSSR_SRC_USEC (0 << 0) 36*42cee19aSThierry Reding 37*42cee19aSThierry Reding /* watchdog registers */ 38*42cee19aSThierry Reding #define WDTCR 0x000 39*42cee19aSThierry Reding #define WDTCR_SYSTEM_POR_RESET_ENABLE BIT(16) 40*42cee19aSThierry Reding #define WDTCR_SYSTEM_DEBUG_RESET_ENABLE BIT(15) 41*42cee19aSThierry Reding #define WDTCR_REMOTE_INT_ENABLE BIT(14) 42*42cee19aSThierry Reding #define WDTCR_LOCAL_FIQ_ENABLE BIT(13) 43*42cee19aSThierry Reding #define WDTCR_LOCAL_INT_ENABLE BIT(12) 44*42cee19aSThierry Reding #define WDTCR_PERIOD_MASK (0xff << 4) 45*42cee19aSThierry Reding #define WDTCR_PERIOD(x) (((x) & 0xff) << 4) 46*42cee19aSThierry Reding #define WDTCR_TIMER_SOURCE_MASK 0xf 47*42cee19aSThierry Reding #define WDTCR_TIMER_SOURCE(x) ((x) & 0xf) 48*42cee19aSThierry Reding 49*42cee19aSThierry Reding #define WDTCMDR 0x008 50*42cee19aSThierry Reding #define WDTCMDR_DISABLE_COUNTER BIT(1) 51*42cee19aSThierry Reding #define WDTCMDR_START_COUNTER BIT(0) 52*42cee19aSThierry Reding 53*42cee19aSThierry Reding #define WDTUR 0x00c 54*42cee19aSThierry Reding #define WDTUR_UNLOCK_PATTERN 0x0000c45a 55*42cee19aSThierry Reding 56*42cee19aSThierry Reding struct tegra186_timer_soc { 57*42cee19aSThierry Reding unsigned int num_timers; 58*42cee19aSThierry Reding unsigned int num_wdts; 59*42cee19aSThierry Reding }; 60*42cee19aSThierry Reding 61*42cee19aSThierry Reding struct tegra186_tmr { 62*42cee19aSThierry Reding struct tegra186_timer *parent; 63*42cee19aSThierry Reding void __iomem *regs; 64*42cee19aSThierry Reding unsigned int index; 65*42cee19aSThierry Reding unsigned int hwirq; 66*42cee19aSThierry Reding }; 67*42cee19aSThierry Reding 68*42cee19aSThierry Reding struct tegra186_wdt { 69*42cee19aSThierry Reding struct watchdog_device base; 70*42cee19aSThierry Reding 71*42cee19aSThierry Reding void __iomem *regs; 72*42cee19aSThierry Reding unsigned int index; 73*42cee19aSThierry Reding bool locked; 74*42cee19aSThierry Reding 75*42cee19aSThierry Reding struct tegra186_tmr *tmr; 76*42cee19aSThierry Reding }; 77*42cee19aSThierry Reding 78*42cee19aSThierry Reding static inline struct tegra186_wdt *to_tegra186_wdt(struct watchdog_device *wdd) 79*42cee19aSThierry Reding { 80*42cee19aSThierry Reding return container_of(wdd, struct tegra186_wdt, base); 81*42cee19aSThierry Reding } 82*42cee19aSThierry Reding 83*42cee19aSThierry Reding struct tegra186_timer { 84*42cee19aSThierry Reding const struct tegra186_timer_soc *soc; 85*42cee19aSThierry Reding struct device *dev; 86*42cee19aSThierry Reding void __iomem *regs; 87*42cee19aSThierry Reding 88*42cee19aSThierry Reding struct tegra186_wdt *wdt; 89*42cee19aSThierry Reding struct clocksource usec; 90*42cee19aSThierry Reding struct clocksource tsc; 91*42cee19aSThierry Reding struct clocksource osc; 92*42cee19aSThierry Reding }; 93*42cee19aSThierry Reding 94*42cee19aSThierry Reding static void tmr_writel(struct tegra186_tmr *tmr, u32 value, unsigned int offset) 95*42cee19aSThierry Reding { 96*42cee19aSThierry Reding writel_relaxed(value, tmr->regs + offset); 97*42cee19aSThierry Reding } 98*42cee19aSThierry Reding 99*42cee19aSThierry Reding static void wdt_writel(struct tegra186_wdt *wdt, u32 value, unsigned int offset) 100*42cee19aSThierry Reding { 101*42cee19aSThierry Reding writel_relaxed(value, wdt->regs + offset); 102*42cee19aSThierry Reding } 103*42cee19aSThierry Reding 104*42cee19aSThierry Reding static u32 wdt_readl(struct tegra186_wdt *wdt, unsigned int offset) 105*42cee19aSThierry Reding { 106*42cee19aSThierry Reding return readl_relaxed(wdt->regs + offset); 107*42cee19aSThierry Reding } 108*42cee19aSThierry Reding 109*42cee19aSThierry Reding static struct tegra186_tmr *tegra186_tmr_create(struct tegra186_timer *tegra, 110*42cee19aSThierry Reding unsigned int index) 111*42cee19aSThierry Reding { 112*42cee19aSThierry Reding unsigned int offset = 0x10000 + index * 0x10000; 113*42cee19aSThierry Reding struct tegra186_tmr *tmr; 114*42cee19aSThierry Reding 115*42cee19aSThierry Reding tmr = devm_kzalloc(tegra->dev, sizeof(*tmr), GFP_KERNEL); 116*42cee19aSThierry Reding if (!tmr) 117*42cee19aSThierry Reding return ERR_PTR(-ENOMEM); 118*42cee19aSThierry Reding 119*42cee19aSThierry Reding tmr->parent = tegra; 120*42cee19aSThierry Reding tmr->regs = tegra->regs + offset; 121*42cee19aSThierry Reding tmr->index = index; 122*42cee19aSThierry Reding tmr->hwirq = 0; 123*42cee19aSThierry Reding 124*42cee19aSThierry Reding return tmr; 125*42cee19aSThierry Reding } 126*42cee19aSThierry Reding 127*42cee19aSThierry Reding static const struct watchdog_info tegra186_wdt_info = { 128*42cee19aSThierry Reding .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 129*42cee19aSThierry Reding .identity = "NVIDIA Tegra186 WDT", 130*42cee19aSThierry Reding }; 131*42cee19aSThierry Reding 132*42cee19aSThierry Reding static void tegra186_wdt_disable(struct tegra186_wdt *wdt) 133*42cee19aSThierry Reding { 134*42cee19aSThierry Reding /* unlock and disable the watchdog */ 135*42cee19aSThierry Reding wdt_writel(wdt, WDTUR_UNLOCK_PATTERN, WDTUR); 136*42cee19aSThierry Reding wdt_writel(wdt, WDTCMDR_DISABLE_COUNTER, WDTCMDR); 137*42cee19aSThierry Reding 138*42cee19aSThierry Reding /* disable timer */ 139*42cee19aSThierry Reding tmr_writel(wdt->tmr, 0, TMRCR); 140*42cee19aSThierry Reding } 141*42cee19aSThierry Reding 142*42cee19aSThierry Reding static void tegra186_wdt_enable(struct tegra186_wdt *wdt) 143*42cee19aSThierry Reding { 144*42cee19aSThierry Reding struct tegra186_timer *tegra = wdt->tmr->parent; 145*42cee19aSThierry Reding u32 value; 146*42cee19aSThierry Reding 147*42cee19aSThierry Reding /* unmask hardware IRQ, this may have been lost across powergate */ 148*42cee19aSThierry Reding value = TKEIE_WDT_MASK(wdt->index, 1); 149*42cee19aSThierry Reding writel(value, tegra->regs + TKEIE(wdt->tmr->hwirq)); 150*42cee19aSThierry Reding 151*42cee19aSThierry Reding /* clear interrupt */ 152*42cee19aSThierry Reding tmr_writel(wdt->tmr, TMRSR_INTR_CLR, TMRSR); 153*42cee19aSThierry Reding 154*42cee19aSThierry Reding /* select microsecond source */ 155*42cee19aSThierry Reding tmr_writel(wdt->tmr, TMRCSSR_SRC_USEC, TMRCSSR); 156*42cee19aSThierry Reding 157*42cee19aSThierry Reding /* configure timer (system reset happens on the fifth expiration) */ 158*42cee19aSThierry Reding value = TMRCR_PTV(wdt->base.timeout * USEC_PER_SEC / 5) | 159*42cee19aSThierry Reding TMRCR_PERIODIC | TMRCR_ENABLE; 160*42cee19aSThierry Reding tmr_writel(wdt->tmr, value, TMRCR); 161*42cee19aSThierry Reding 162*42cee19aSThierry Reding if (!wdt->locked) { 163*42cee19aSThierry Reding value = wdt_readl(wdt, WDTCR); 164*42cee19aSThierry Reding 165*42cee19aSThierry Reding /* select the proper timer source */ 166*42cee19aSThierry Reding value &= ~WDTCR_TIMER_SOURCE_MASK; 167*42cee19aSThierry Reding value |= WDTCR_TIMER_SOURCE(wdt->tmr->index); 168*42cee19aSThierry Reding 169*42cee19aSThierry Reding /* single timer period since that's already configured */ 170*42cee19aSThierry Reding value &= ~WDTCR_PERIOD_MASK; 171*42cee19aSThierry Reding value |= WDTCR_PERIOD(1); 172*42cee19aSThierry Reding 173*42cee19aSThierry Reding /* enable local interrupt for WDT petting */ 174*42cee19aSThierry Reding value |= WDTCR_LOCAL_INT_ENABLE; 175*42cee19aSThierry Reding 176*42cee19aSThierry Reding /* enable local FIQ and remote interrupt for debug dump */ 177*42cee19aSThierry Reding if (0) 178*42cee19aSThierry Reding value |= WDTCR_REMOTE_INT_ENABLE | 179*42cee19aSThierry Reding WDTCR_LOCAL_FIQ_ENABLE; 180*42cee19aSThierry Reding 181*42cee19aSThierry Reding /* enable system debug reset (doesn't properly reboot) */ 182*42cee19aSThierry Reding if (0) 183*42cee19aSThierry Reding value |= WDTCR_SYSTEM_DEBUG_RESET_ENABLE; 184*42cee19aSThierry Reding 185*42cee19aSThierry Reding /* enable system POR reset */ 186*42cee19aSThierry Reding value |= WDTCR_SYSTEM_POR_RESET_ENABLE; 187*42cee19aSThierry Reding 188*42cee19aSThierry Reding wdt_writel(wdt, value, WDTCR); 189*42cee19aSThierry Reding } 190*42cee19aSThierry Reding 191*42cee19aSThierry Reding wdt_writel(wdt, WDTCMDR_START_COUNTER, WDTCMDR); 192*42cee19aSThierry Reding } 193*42cee19aSThierry Reding 194*42cee19aSThierry Reding static int tegra186_wdt_start(struct watchdog_device *wdd) 195*42cee19aSThierry Reding { 196*42cee19aSThierry Reding struct tegra186_wdt *wdt = to_tegra186_wdt(wdd); 197*42cee19aSThierry Reding 198*42cee19aSThierry Reding tegra186_wdt_enable(wdt); 199*42cee19aSThierry Reding 200*42cee19aSThierry Reding return 0; 201*42cee19aSThierry Reding } 202*42cee19aSThierry Reding 203*42cee19aSThierry Reding static int tegra186_wdt_stop(struct watchdog_device *wdd) 204*42cee19aSThierry Reding { 205*42cee19aSThierry Reding struct tegra186_wdt *wdt = to_tegra186_wdt(wdd); 206*42cee19aSThierry Reding 207*42cee19aSThierry Reding tegra186_wdt_disable(wdt); 208*42cee19aSThierry Reding 209*42cee19aSThierry Reding return 0; 210*42cee19aSThierry Reding } 211*42cee19aSThierry Reding 212*42cee19aSThierry Reding static int tegra186_wdt_ping(struct watchdog_device *wdd) 213*42cee19aSThierry Reding { 214*42cee19aSThierry Reding struct tegra186_wdt *wdt = to_tegra186_wdt(wdd); 215*42cee19aSThierry Reding 216*42cee19aSThierry Reding tegra186_wdt_disable(wdt); 217*42cee19aSThierry Reding tegra186_wdt_enable(wdt); 218*42cee19aSThierry Reding 219*42cee19aSThierry Reding return 0; 220*42cee19aSThierry Reding } 221*42cee19aSThierry Reding 222*42cee19aSThierry Reding static int tegra186_wdt_set_timeout(struct watchdog_device *wdd, 223*42cee19aSThierry Reding unsigned int timeout) 224*42cee19aSThierry Reding { 225*42cee19aSThierry Reding struct tegra186_wdt *wdt = to_tegra186_wdt(wdd); 226*42cee19aSThierry Reding 227*42cee19aSThierry Reding if (watchdog_active(&wdt->base)) 228*42cee19aSThierry Reding tegra186_wdt_disable(wdt); 229*42cee19aSThierry Reding 230*42cee19aSThierry Reding wdt->base.timeout = timeout; 231*42cee19aSThierry Reding 232*42cee19aSThierry Reding if (watchdog_active(&wdt->base)) 233*42cee19aSThierry Reding tegra186_wdt_enable(wdt); 234*42cee19aSThierry Reding 235*42cee19aSThierry Reding return 0; 236*42cee19aSThierry Reding } 237*42cee19aSThierry Reding 238*42cee19aSThierry Reding static const struct watchdog_ops tegra186_wdt_ops = { 239*42cee19aSThierry Reding .owner = THIS_MODULE, 240*42cee19aSThierry Reding .start = tegra186_wdt_start, 241*42cee19aSThierry Reding .stop = tegra186_wdt_stop, 242*42cee19aSThierry Reding .ping = tegra186_wdt_ping, 243*42cee19aSThierry Reding .set_timeout = tegra186_wdt_set_timeout, 244*42cee19aSThierry Reding }; 245*42cee19aSThierry Reding 246*42cee19aSThierry Reding static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra, 247*42cee19aSThierry Reding unsigned int index) 248*42cee19aSThierry Reding { 249*42cee19aSThierry Reding unsigned int offset = 0x10000, source; 250*42cee19aSThierry Reding struct tegra186_wdt *wdt; 251*42cee19aSThierry Reding u32 value; 252*42cee19aSThierry Reding int err; 253*42cee19aSThierry Reding 254*42cee19aSThierry Reding offset += tegra->soc->num_timers * 0x10000 + index * 0x10000; 255*42cee19aSThierry Reding 256*42cee19aSThierry Reding wdt = devm_kzalloc(tegra->dev, sizeof(*wdt), GFP_KERNEL); 257*42cee19aSThierry Reding if (!wdt) 258*42cee19aSThierry Reding return ERR_PTR(-ENOMEM); 259*42cee19aSThierry Reding 260*42cee19aSThierry Reding wdt->regs = tegra->regs + offset; 261*42cee19aSThierry Reding wdt->index = index; 262*42cee19aSThierry Reding 263*42cee19aSThierry Reding /* read the watchdog configuration since it might be locked down */ 264*42cee19aSThierry Reding value = wdt_readl(wdt, WDTCR); 265*42cee19aSThierry Reding 266*42cee19aSThierry Reding if (value & WDTCR_LOCAL_INT_ENABLE) 267*42cee19aSThierry Reding wdt->locked = true; 268*42cee19aSThierry Reding 269*42cee19aSThierry Reding source = value & WDTCR_TIMER_SOURCE_MASK; 270*42cee19aSThierry Reding 271*42cee19aSThierry Reding wdt->tmr = tegra186_tmr_create(tegra, source); 272*42cee19aSThierry Reding if (IS_ERR(wdt->tmr)) 273*42cee19aSThierry Reding return ERR_CAST(wdt->tmr); 274*42cee19aSThierry Reding 275*42cee19aSThierry Reding wdt->base.info = &tegra186_wdt_info; 276*42cee19aSThierry Reding wdt->base.ops = &tegra186_wdt_ops; 277*42cee19aSThierry Reding wdt->base.min_timeout = 1; 278*42cee19aSThierry Reding wdt->base.max_timeout = 255; 279*42cee19aSThierry Reding wdt->base.parent = tegra->dev; 280*42cee19aSThierry Reding 281*42cee19aSThierry Reding err = watchdog_init_timeout(&wdt->base, 5, tegra->dev); 282*42cee19aSThierry Reding if (err < 0) { 283*42cee19aSThierry Reding dev_err(tegra->dev, "failed to initialize timeout: %d\n", err); 284*42cee19aSThierry Reding return ERR_PTR(err); 285*42cee19aSThierry Reding } 286*42cee19aSThierry Reding 287*42cee19aSThierry Reding err = devm_watchdog_register_device(tegra->dev, &wdt->base); 288*42cee19aSThierry Reding if (err < 0) { 289*42cee19aSThierry Reding dev_err(tegra->dev, "failed to register WDT: %d\n", err); 290*42cee19aSThierry Reding return ERR_PTR(err); 291*42cee19aSThierry Reding } 292*42cee19aSThierry Reding 293*42cee19aSThierry Reding return wdt; 294*42cee19aSThierry Reding } 295*42cee19aSThierry Reding 296*42cee19aSThierry Reding static u64 tegra186_timer_tsc_read(struct clocksource *cs) 297*42cee19aSThierry Reding { 298*42cee19aSThierry Reding struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer, 299*42cee19aSThierry Reding tsc); 300*42cee19aSThierry Reding u32 hi, lo, ss; 301*42cee19aSThierry Reding 302*42cee19aSThierry Reding hi = readl_relaxed(tegra->regs + TKETSC1); 303*42cee19aSThierry Reding 304*42cee19aSThierry Reding /* 305*42cee19aSThierry Reding * The 56-bit value of the TSC is spread across two registers that are 306*42cee19aSThierry Reding * not synchronized. In order to read them atomically, ensure that the 307*42cee19aSThierry Reding * high 24 bits match before and after reading the low 32 bits. 308*42cee19aSThierry Reding */ 309*42cee19aSThierry Reding do { 310*42cee19aSThierry Reding /* snapshot the high 24 bits */ 311*42cee19aSThierry Reding ss = hi; 312*42cee19aSThierry Reding 313*42cee19aSThierry Reding lo = readl_relaxed(tegra->regs + TKETSC0); 314*42cee19aSThierry Reding hi = readl_relaxed(tegra->regs + TKETSC1); 315*42cee19aSThierry Reding } while (hi != ss); 316*42cee19aSThierry Reding 317*42cee19aSThierry Reding return (u64)hi << 32 | lo; 318*42cee19aSThierry Reding } 319*42cee19aSThierry Reding 320*42cee19aSThierry Reding static int tegra186_timer_tsc_init(struct tegra186_timer *tegra) 321*42cee19aSThierry Reding { 322*42cee19aSThierry Reding tegra->tsc.name = "tsc"; 323*42cee19aSThierry Reding tegra->tsc.rating = 300; 324*42cee19aSThierry Reding tegra->tsc.read = tegra186_timer_tsc_read; 325*42cee19aSThierry Reding tegra->tsc.mask = CLOCKSOURCE_MASK(56); 326*42cee19aSThierry Reding tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS; 327*42cee19aSThierry Reding 328*42cee19aSThierry Reding return clocksource_register_hz(&tegra->tsc, 31250000); 329*42cee19aSThierry Reding } 330*42cee19aSThierry Reding 331*42cee19aSThierry Reding static u64 tegra186_timer_osc_read(struct clocksource *cs) 332*42cee19aSThierry Reding { 333*42cee19aSThierry Reding struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer, 334*42cee19aSThierry Reding osc); 335*42cee19aSThierry Reding 336*42cee19aSThierry Reding return readl_relaxed(tegra->regs + TKEOSC); 337*42cee19aSThierry Reding } 338*42cee19aSThierry Reding 339*42cee19aSThierry Reding static int tegra186_timer_osc_init(struct tegra186_timer *tegra) 340*42cee19aSThierry Reding { 341*42cee19aSThierry Reding tegra->osc.name = "osc"; 342*42cee19aSThierry Reding tegra->osc.rating = 300; 343*42cee19aSThierry Reding tegra->osc.read = tegra186_timer_osc_read; 344*42cee19aSThierry Reding tegra->osc.mask = CLOCKSOURCE_MASK(32); 345*42cee19aSThierry Reding tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS; 346*42cee19aSThierry Reding 347*42cee19aSThierry Reding return clocksource_register_hz(&tegra->osc, 38400000); 348*42cee19aSThierry Reding } 349*42cee19aSThierry Reding 350*42cee19aSThierry Reding static u64 tegra186_timer_usec_read(struct clocksource *cs) 351*42cee19aSThierry Reding { 352*42cee19aSThierry Reding struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer, 353*42cee19aSThierry Reding usec); 354*42cee19aSThierry Reding 355*42cee19aSThierry Reding return readl_relaxed(tegra->regs + TKEUSEC); 356*42cee19aSThierry Reding } 357*42cee19aSThierry Reding 358*42cee19aSThierry Reding static int tegra186_timer_usec_init(struct tegra186_timer *tegra) 359*42cee19aSThierry Reding { 360*42cee19aSThierry Reding tegra->usec.name = "usec"; 361*42cee19aSThierry Reding tegra->usec.rating = 300; 362*42cee19aSThierry Reding tegra->usec.read = tegra186_timer_usec_read; 363*42cee19aSThierry Reding tegra->usec.mask = CLOCKSOURCE_MASK(32); 364*42cee19aSThierry Reding tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS; 365*42cee19aSThierry Reding 366*42cee19aSThierry Reding return clocksource_register_hz(&tegra->usec, USEC_PER_SEC); 367*42cee19aSThierry Reding } 368*42cee19aSThierry Reding 369*42cee19aSThierry Reding static irqreturn_t tegra186_timer_irq(int irq, void *data) 370*42cee19aSThierry Reding { 371*42cee19aSThierry Reding struct tegra186_timer *tegra = data; 372*42cee19aSThierry Reding 373*42cee19aSThierry Reding if (watchdog_active(&tegra->wdt->base)) { 374*42cee19aSThierry Reding tegra186_wdt_disable(tegra->wdt); 375*42cee19aSThierry Reding tegra186_wdt_enable(tegra->wdt); 376*42cee19aSThierry Reding } 377*42cee19aSThierry Reding 378*42cee19aSThierry Reding return IRQ_HANDLED; 379*42cee19aSThierry Reding } 380*42cee19aSThierry Reding 381*42cee19aSThierry Reding static int tegra186_timer_probe(struct platform_device *pdev) 382*42cee19aSThierry Reding { 383*42cee19aSThierry Reding struct device *dev = &pdev->dev; 384*42cee19aSThierry Reding struct tegra186_timer *tegra; 385*42cee19aSThierry Reding unsigned int irq; 386*42cee19aSThierry Reding int err; 387*42cee19aSThierry Reding 388*42cee19aSThierry Reding tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL); 389*42cee19aSThierry Reding if (!tegra) 390*42cee19aSThierry Reding return -ENOMEM; 391*42cee19aSThierry Reding 392*42cee19aSThierry Reding tegra->soc = of_device_get_match_data(dev); 393*42cee19aSThierry Reding dev_set_drvdata(dev, tegra); 394*42cee19aSThierry Reding tegra->dev = dev; 395*42cee19aSThierry Reding 396*42cee19aSThierry Reding tegra->regs = devm_platform_ioremap_resource(pdev, 0); 397*42cee19aSThierry Reding if (IS_ERR(tegra->regs)) 398*42cee19aSThierry Reding return PTR_ERR(tegra->regs); 399*42cee19aSThierry Reding 400*42cee19aSThierry Reding err = platform_get_irq(pdev, 0); 401*42cee19aSThierry Reding if (err < 0) 402*42cee19aSThierry Reding return err; 403*42cee19aSThierry Reding 404*42cee19aSThierry Reding irq = err; 405*42cee19aSThierry Reding 406*42cee19aSThierry Reding /* create a watchdog using a preconfigured timer */ 407*42cee19aSThierry Reding tegra->wdt = tegra186_wdt_create(tegra, 0); 408*42cee19aSThierry Reding if (IS_ERR(tegra->wdt)) { 409*42cee19aSThierry Reding err = PTR_ERR(tegra->wdt); 410*42cee19aSThierry Reding dev_err(dev, "failed to create WDT: %d\n", err); 411*42cee19aSThierry Reding return err; 412*42cee19aSThierry Reding } 413*42cee19aSThierry Reding 414*42cee19aSThierry Reding err = tegra186_timer_tsc_init(tegra); 415*42cee19aSThierry Reding if (err < 0) { 416*42cee19aSThierry Reding dev_err(dev, "failed to register TSC counter: %d\n", err); 417*42cee19aSThierry Reding return err; 418*42cee19aSThierry Reding } 419*42cee19aSThierry Reding 420*42cee19aSThierry Reding err = tegra186_timer_osc_init(tegra); 421*42cee19aSThierry Reding if (err < 0) { 422*42cee19aSThierry Reding dev_err(dev, "failed to register OSC counter: %d\n", err); 423*42cee19aSThierry Reding goto unregister_tsc; 424*42cee19aSThierry Reding } 425*42cee19aSThierry Reding 426*42cee19aSThierry Reding err = tegra186_timer_usec_init(tegra); 427*42cee19aSThierry Reding if (err < 0) { 428*42cee19aSThierry Reding dev_err(dev, "failed to register USEC counter: %d\n", err); 429*42cee19aSThierry Reding goto unregister_osc; 430*42cee19aSThierry Reding } 431*42cee19aSThierry Reding 432*42cee19aSThierry Reding err = devm_request_irq(dev, irq, tegra186_timer_irq, 0, 433*42cee19aSThierry Reding "tegra186-timer", tegra); 434*42cee19aSThierry Reding if (err < 0) { 435*42cee19aSThierry Reding dev_err(dev, "failed to request IRQ#%u: %d\n", irq, err); 436*42cee19aSThierry Reding goto unregister_usec; 437*42cee19aSThierry Reding } 438*42cee19aSThierry Reding 439*42cee19aSThierry Reding return 0; 440*42cee19aSThierry Reding 441*42cee19aSThierry Reding unregister_usec: 442*42cee19aSThierry Reding clocksource_unregister(&tegra->usec); 443*42cee19aSThierry Reding unregister_osc: 444*42cee19aSThierry Reding clocksource_unregister(&tegra->osc); 445*42cee19aSThierry Reding unregister_tsc: 446*42cee19aSThierry Reding clocksource_unregister(&tegra->tsc); 447*42cee19aSThierry Reding return err; 448*42cee19aSThierry Reding } 449*42cee19aSThierry Reding 450*42cee19aSThierry Reding static int tegra186_timer_remove(struct platform_device *pdev) 451*42cee19aSThierry Reding { 452*42cee19aSThierry Reding struct tegra186_timer *tegra = platform_get_drvdata(pdev); 453*42cee19aSThierry Reding 454*42cee19aSThierry Reding clocksource_unregister(&tegra->usec); 455*42cee19aSThierry Reding clocksource_unregister(&tegra->osc); 456*42cee19aSThierry Reding clocksource_unregister(&tegra->tsc); 457*42cee19aSThierry Reding 458*42cee19aSThierry Reding return 0; 459*42cee19aSThierry Reding } 460*42cee19aSThierry Reding 461*42cee19aSThierry Reding static int __maybe_unused tegra186_timer_suspend(struct device *dev) 462*42cee19aSThierry Reding { 463*42cee19aSThierry Reding struct tegra186_timer *tegra = dev_get_drvdata(dev); 464*42cee19aSThierry Reding 465*42cee19aSThierry Reding if (watchdog_active(&tegra->wdt->base)) 466*42cee19aSThierry Reding tegra186_wdt_disable(tegra->wdt); 467*42cee19aSThierry Reding 468*42cee19aSThierry Reding return 0; 469*42cee19aSThierry Reding } 470*42cee19aSThierry Reding 471*42cee19aSThierry Reding static int __maybe_unused tegra186_timer_resume(struct device *dev) 472*42cee19aSThierry Reding { 473*42cee19aSThierry Reding struct tegra186_timer *tegra = dev_get_drvdata(dev); 474*42cee19aSThierry Reding 475*42cee19aSThierry Reding if (watchdog_active(&tegra->wdt->base)) 476*42cee19aSThierry Reding tegra186_wdt_enable(tegra->wdt); 477*42cee19aSThierry Reding 478*42cee19aSThierry Reding return 0; 479*42cee19aSThierry Reding } 480*42cee19aSThierry Reding 481*42cee19aSThierry Reding static SIMPLE_DEV_PM_OPS(tegra186_timer_pm_ops, tegra186_timer_suspend, 482*42cee19aSThierry Reding tegra186_timer_resume); 483*42cee19aSThierry Reding 484*42cee19aSThierry Reding static const struct tegra186_timer_soc tegra186_timer = { 485*42cee19aSThierry Reding .num_timers = 10, 486*42cee19aSThierry Reding .num_wdts = 3, 487*42cee19aSThierry Reding }; 488*42cee19aSThierry Reding 489*42cee19aSThierry Reding static const struct of_device_id tegra186_timer_of_match[] = { 490*42cee19aSThierry Reding { .compatible = "nvidia,tegra186-timer", .data = &tegra186_timer }, 491*42cee19aSThierry Reding { } 492*42cee19aSThierry Reding }; 493*42cee19aSThierry Reding MODULE_DEVICE_TABLE(of, tegra186_timer_of_match); 494*42cee19aSThierry Reding 495*42cee19aSThierry Reding static struct platform_driver tegra186_wdt_driver = { 496*42cee19aSThierry Reding .driver = { 497*42cee19aSThierry Reding .name = "tegra186-timer", 498*42cee19aSThierry Reding .pm = &tegra186_timer_pm_ops, 499*42cee19aSThierry Reding .of_match_table = tegra186_timer_of_match, 500*42cee19aSThierry Reding }, 501*42cee19aSThierry Reding .probe = tegra186_timer_probe, 502*42cee19aSThierry Reding .remove = tegra186_timer_remove, 503*42cee19aSThierry Reding }; 504*42cee19aSThierry Reding module_platform_driver(tegra186_wdt_driver); 505*42cee19aSThierry Reding 506*42cee19aSThierry Reding MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 507*42cee19aSThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra186 timers driver"); 508*42cee19aSThierry Reding MODULE_LICENSE("GPL v2"); 509