aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/sh/clk/cpg.c77
-rw-r--r--drivers/sh/intc/dynamic.c8
-rw-r--r--drivers/tty/serial/sh-sci.c49
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/shwdt.c306
5 files changed, 186 insertions, 255 deletions
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 91b6d52f74eb..f0d015dd0fef 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -2,6 +2,7 @@
2 * Helper routines for SuperH Clock Pulse Generator blocks (CPG). 2 * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
3 * 3 *
4 * Copyright (C) 2010 Magnus Damm 4 * Copyright (C) 2010 Magnus Damm
5 * Copyright (C) 2010 - 2012 Paul Mundt
5 * 6 *
6 * This file is subject to the terms and conditions of the GNU General Public 7 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive 8 * License. See the file "COPYING" in the main directory of this archive
@@ -13,26 +14,44 @@
13#include <linux/io.h> 14#include <linux/io.h>
14#include <linux/sh_clk.h> 15#include <linux/sh_clk.h>
15 16
16static int sh_clk_mstp32_enable(struct clk *clk) 17static unsigned int sh_clk_read(struct clk *clk)
17{ 18{
18 iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit), 19 if (clk->flags & CLK_ENABLE_REG_8BIT)
19 clk->mapped_reg); 20 return ioread8(clk->mapped_reg);
21 else if (clk->flags & CLK_ENABLE_REG_16BIT)
22 return ioread16(clk->mapped_reg);
23
24 return ioread32(clk->mapped_reg);
25}
26
27static void sh_clk_write(int value, struct clk *clk)
28{
29 if (clk->flags & CLK_ENABLE_REG_8BIT)
30 iowrite8(value, clk->mapped_reg);
31 else if (clk->flags & CLK_ENABLE_REG_16BIT)
32 iowrite16(value, clk->mapped_reg);
33 else
34 iowrite32(value, clk->mapped_reg);
35}
36
37static int sh_clk_mstp_enable(struct clk *clk)
38{
39 sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
20 return 0; 40 return 0;
21} 41}
22 42
23static void sh_clk_mstp32_disable(struct clk *clk) 43static void sh_clk_mstp_disable(struct clk *clk)
24{ 44{
25 iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit), 45 sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
26 clk->mapped_reg);
27} 46}
28 47
29static struct sh_clk_ops sh_clk_mstp32_clk_ops = { 48static struct sh_clk_ops sh_clk_mstp_clk_ops = {
30 .enable = sh_clk_mstp32_enable, 49 .enable = sh_clk_mstp_enable,
31 .disable = sh_clk_mstp32_disable, 50 .disable = sh_clk_mstp_disable,
32 .recalc = followparent_recalc, 51 .recalc = followparent_recalc,
33}; 52};
34 53
35int __init sh_clk_mstp32_register(struct clk *clks, int nr) 54int __init sh_clk_mstp_register(struct clk *clks, int nr)
36{ 55{
37 struct clk *clkp; 56 struct clk *clkp;
38 int ret = 0; 57 int ret = 0;
@@ -40,7 +59,7 @@ int __init sh_clk_mstp32_register(struct clk *clks, int nr)
40 59
41 for (k = 0; !ret && (k < nr); k++) { 60 for (k = 0; !ret && (k < nr); k++) {
42 clkp = clks + k; 61 clkp = clks + k;
43 clkp->ops = &sh_clk_mstp32_clk_ops; 62 clkp->ops = &sh_clk_mstp_clk_ops;
44 ret |= clk_register(clkp); 63 ret |= clk_register(clkp);
45 } 64 }
46 65
@@ -72,7 +91,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
72 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 91 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
73 table, NULL); 92 table, NULL);
74 93
75 idx = ioread32(clk->mapped_reg) & 0x003f; 94 idx = sh_clk_read(clk) & 0x003f;
76 95
77 return clk->freq_table[idx].frequency; 96 return clk->freq_table[idx].frequency;
78} 97}
@@ -98,10 +117,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
98 if (ret < 0) 117 if (ret < 0)
99 return ret; 118 return ret;
100 119
101 value = ioread32(clk->mapped_reg) & 120 value = sh_clk_read(clk) &
102 ~(((1 << clk->src_width) - 1) << clk->src_shift); 121 ~(((1 << clk->src_width) - 1) << clk->src_shift);
103 122
104 iowrite32(value | (i << clk->src_shift), clk->mapped_reg); 123 sh_clk_write(value | (i << clk->src_shift), clk);
105 124
106 /* Rebuild the frequency table */ 125 /* Rebuild the frequency table */
107 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 126 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +138,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
119 if (idx < 0) 138 if (idx < 0)
120 return idx; 139 return idx;
121 140
122 value = ioread32(clk->mapped_reg); 141 value = sh_clk_read(clk);
123 value &= ~0x3f; 142 value &= ~0x3f;
124 value |= idx; 143 value |= idx;
125 iowrite32(value, clk->mapped_reg); 144 sh_clk_write(value, clk);
126 return 0; 145 return 0;
127} 146}
128 147
@@ -133,9 +152,9 @@ static int sh_clk_div6_enable(struct clk *clk)
133 152
134 ret = sh_clk_div6_set_rate(clk, clk->rate); 153 ret = sh_clk_div6_set_rate(clk, clk->rate);
135 if (ret == 0) { 154 if (ret == 0) {
136 value = ioread32(clk->mapped_reg); 155 value = sh_clk_read(clk);
137 value &= ~0x100; /* clear stop bit to enable clock */ 156 value &= ~0x100; /* clear stop bit to enable clock */
138 iowrite32(value, clk->mapped_reg); 157 sh_clk_write(value, clk);
139 } 158 }
140 return ret; 159 return ret;
141} 160}
@@ -144,10 +163,10 @@ static void sh_clk_div6_disable(struct clk *clk)
144{ 163{
145 unsigned long value; 164 unsigned long value;
146 165
147 value = ioread32(clk->mapped_reg); 166 value = sh_clk_read(clk);
148 value |= 0x100; /* stop clock */ 167 value |= 0x100; /* stop clock */
149 value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */ 168 value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
150 iowrite32(value, clk->mapped_reg); 169 sh_clk_write(value, clk);
151} 170}
152 171
153static struct sh_clk_ops sh_clk_div6_clk_ops = { 172static struct sh_clk_ops sh_clk_div6_clk_ops = {
@@ -182,7 +201,7 @@ static int __init sh_clk_init_parent(struct clk *clk)
182 return -EINVAL; 201 return -EINVAL;
183 } 202 }
184 203
185 val = (ioread32(clk->mapped_reg) >> clk->src_shift); 204 val = (sh_clk_read(clk) >> clk->src_shift);
186 val &= (1 << clk->src_width) - 1; 205 val &= (1 << clk->src_width) - 1;
187 206
188 if (val >= clk->parent_num) { 207 if (val >= clk->parent_num) {
@@ -252,7 +271,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
252 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 271 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
253 table, &clk->arch_flags); 272 table, &clk->arch_flags);
254 273
255 idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f; 274 idx = (sh_clk_read(clk) >> clk->enable_bit) & 0x000f;
256 275
257 return clk->freq_table[idx].frequency; 276 return clk->freq_table[idx].frequency;
258} 277}
@@ -270,15 +289,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
270 */ 289 */
271 290
272 if (parent->flags & CLK_ENABLE_ON_INIT) 291 if (parent->flags & CLK_ENABLE_ON_INIT)
273 value = ioread32(clk->mapped_reg) & ~(1 << 7); 292 value = sh_clk_read(clk) & ~(1 << 7);
274 else 293 else
275 value = ioread32(clk->mapped_reg) | (1 << 7); 294 value = sh_clk_read(clk) | (1 << 7);
276 295
277 ret = clk_reparent(clk, parent); 296 ret = clk_reparent(clk, parent);
278 if (ret < 0) 297 if (ret < 0)
279 return ret; 298 return ret;
280 299
281 iowrite32(value, clk->mapped_reg); 300 sh_clk_write(value, clk);
282 301
283 /* Rebiuld the frequency table */ 302 /* Rebiuld the frequency table */
284 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 303 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -295,10 +314,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
295 if (idx < 0) 314 if (idx < 0)
296 return idx; 315 return idx;
297 316
298 value = ioread32(clk->mapped_reg); 317 value = sh_clk_read(clk);
299 value &= ~(0xf << clk->enable_bit); 318 value &= ~(0xf << clk->enable_bit);
300 value |= (idx << clk->enable_bit); 319 value |= (idx << clk->enable_bit);
301 iowrite32(value, clk->mapped_reg); 320 sh_clk_write(value, clk);
302 321
303 if (d4t->kick) 322 if (d4t->kick)
304 d4t->kick(clk); 323 d4t->kick(clk);
@@ -308,13 +327,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
308 327
309static int sh_clk_div4_enable(struct clk *clk) 328static int sh_clk_div4_enable(struct clk *clk)
310{ 329{
311 iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg); 330 sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk);
312 return 0; 331 return 0;
313} 332}
314 333
315static void sh_clk_div4_disable(struct clk *clk) 334static void sh_clk_div4_disable(struct clk *clk)
316{ 335{
317 iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg); 336 sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
318} 337}
319 338
320static struct sh_clk_ops sh_clk_div4_clk_ops = { 339static struct sh_clk_ops sh_clk_div4_clk_ops = {
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
index 5fea1ee8799a..14eb01ef5d72 100644
--- a/drivers/sh/intc/dynamic.c
+++ b/drivers/sh/intc/dynamic.c
@@ -55,11 +55,3 @@ void destroy_irq(unsigned int irq)
55{ 55{
56 irq_free_desc(irq); 56 irq_free_desc(irq);
57} 57}
58
59void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
60{
61 int i;
62
63 for (i = 0; i < nr_vecs; i++)
64 irq_reserve_irq(evt2irq(vectors[i].vect));
65}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3158e17b665c..4604153b7954 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1052,9 +1052,17 @@ static int sci_request_irq(struct sci_port *port)
1052 if (SCIx_IRQ_IS_MUXED(port)) { 1052 if (SCIx_IRQ_IS_MUXED(port)) {
1053 i = SCIx_MUX_IRQ; 1053 i = SCIx_MUX_IRQ;
1054 irq = up->irq; 1054 irq = up->irq;
1055 } else 1055 } else {
1056 irq = port->cfg->irqs[i]; 1056 irq = port->cfg->irqs[i];
1057 1057
1058 /*
1059 * Certain port types won't support all of the
1060 * available interrupt sources.
1061 */
1062 if (unlikely(!irq))
1063 continue;
1064 }
1065
1058 desc = sci_irq_desc + i; 1066 desc = sci_irq_desc + i;
1059 port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s", 1067 port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
1060 dev_name(up->dev), desc->desc); 1068 dev_name(up->dev), desc->desc);
@@ -1094,6 +1102,15 @@ static void sci_free_irq(struct sci_port *port)
1094 * IRQ first. 1102 * IRQ first.
1095 */ 1103 */
1096 for (i = 0; i < SCIx_NR_IRQS; i++) { 1104 for (i = 0; i < SCIx_NR_IRQS; i++) {
1105 unsigned int irq = port->cfg->irqs[i];
1106
1107 /*
1108 * Certain port types won't support all of the available
1109 * interrupt sources.
1110 */
1111 if (unlikely(!irq))
1112 continue;
1113
1097 free_irq(port->cfg->irqs[i], port); 1114 free_irq(port->cfg->irqs[i], port);
1098 kfree(port->irqstr[i]); 1115 kfree(port->irqstr[i]);
1099 1116
@@ -1564,10 +1581,32 @@ static void sci_enable_ms(struct uart_port *port)
1564 1581
1565static void sci_break_ctl(struct uart_port *port, int break_state) 1582static void sci_break_ctl(struct uart_port *port, int break_state)
1566{ 1583{
1567 /* 1584 struct sci_port *s = to_sci_port(port);
1568 * Not supported by hardware. Most parts couple break and rx 1585 struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
1569 * interrupts together, with break detection always enabled. 1586 unsigned short scscr, scsptr;
1570 */ 1587
1588 /* check wheter the port has SCSPTR */
1589 if (!reg->size) {
1590 /*
1591 * Not supported by hardware. Most parts couple break and rx
1592 * interrupts together, with break detection always enabled.
1593 */
1594 return;
1595 }
1596
1597 scsptr = serial_port_in(port, SCSPTR);
1598 scscr = serial_port_in(port, SCSCR);
1599
1600 if (break_state == -1) {
1601 scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
1602 scscr &= ~SCSCR_TE;
1603 } else {
1604 scsptr = (scsptr | SCSPTR_SPB2DT) & ~SCSPTR_SPB2IO;
1605 scscr |= SCSCR_TE;
1606 }
1607
1608 serial_port_out(port, SCSPTR, scsptr);
1609 serial_port_out(port, SCSCR, scscr);
1571} 1610}
1572 1611
1573#ifdef CONFIG_SERIAL_SH_SCI_DMA 1612#ifdef CONFIG_SERIAL_SH_SCI_DMA
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index eeea76f4dccb..edebaf771f50 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1138,6 +1138,7 @@ config ZVM_WATCHDOG
1138config SH_WDT 1138config SH_WDT
1139 tristate "SuperH Watchdog" 1139 tristate "SuperH Watchdog"
1140 depends on SUPERH && (CPU_SH3 || CPU_SH4) 1140 depends on SUPERH && (CPU_SH3 || CPU_SH4)
1141 select WATCHDOG_CORE
1141 help 1142 help
1142 This driver adds watchdog support for the integrated watchdog in the 1143 This driver adds watchdog support for the integrated watchdog in the
1143 SuperH processors. If you have one of these processors and wish 1144 SuperH processors. If you have one of these processors and wish
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index 93958a7763e6..e5b59bebcdb1 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Watchdog driver for integrated watchdog in the SuperH processors. 4 * Watchdog driver for integrated watchdog in the SuperH processors.
5 * 5 *
6 * Copyright (C) 2001 - 2010 Paul Mundt <lethal@linux-sh.org> 6 * Copyright (C) 2001 - 2012 Paul Mundt <lethal@linux-sh.org>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the 9 * under the terms of the GNU General Public License as published by the
@@ -25,16 +25,15 @@
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/init.h> 26#include <linux/init.h>
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/spinlock.h>
28#include <linux/miscdevice.h> 29#include <linux/miscdevice.h>
29#include <linux/watchdog.h> 30#include <linux/watchdog.h>
30#include <linux/reboot.h> 31#include <linux/pm_runtime.h>
31#include <linux/notifier.h>
32#include <linux/ioport.h>
33#include <linux/fs.h> 32#include <linux/fs.h>
34#include <linux/mm.h> 33#include <linux/mm.h>
35#include <linux/slab.h> 34#include <linux/slab.h>
36#include <linux/io.h> 35#include <linux/io.h>
37#include <linux/uaccess.h> 36#include <linux/clk.h>
38#include <asm/watchdog.h> 37#include <asm/watchdog.h>
39 38
40#define DRV_NAME "sh-wdt" 39#define DRV_NAME "sh-wdt"
@@ -69,10 +68,6 @@
69static int clock_division_ratio = WTCSR_CKS_4096; 68static int clock_division_ratio = WTCSR_CKS_4096;
70#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) 69#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4))
71 70
72static const struct watchdog_info sh_wdt_info;
73static struct platform_device *sh_wdt_dev;
74static DEFINE_SPINLOCK(shwdt_lock);
75
76#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ 71#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
77static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ 72static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
78static bool nowayout = WATCHDOG_NOWAYOUT; 73static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -81,19 +76,22 @@ static unsigned long next_heartbeat;
81struct sh_wdt { 76struct sh_wdt {
82 void __iomem *base; 77 void __iomem *base;
83 struct device *dev; 78 struct device *dev;
79 struct clk *clk;
80 spinlock_t lock;
84 81
85 struct timer_list timer; 82 struct timer_list timer;
86
87 unsigned long enabled;
88 char expect_close;
89}; 83};
90 84
91static void sh_wdt_start(struct sh_wdt *wdt) 85static int sh_wdt_start(struct watchdog_device *wdt_dev)
92{ 86{
87 struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
93 unsigned long flags; 88 unsigned long flags;
94 u8 csr; 89 u8 csr;
95 90
96 spin_lock_irqsave(&shwdt_lock, flags); 91 pm_runtime_get_sync(wdt->dev);
92 clk_enable(wdt->clk);
93
94 spin_lock_irqsave(&wdt->lock, flags);
97 95
98 next_heartbeat = jiffies + (heartbeat * HZ); 96 next_heartbeat = jiffies + (heartbeat * HZ);
99 mod_timer(&wdt->timer, next_ping_period(clock_division_ratio)); 97 mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
@@ -122,15 +120,18 @@ static void sh_wdt_start(struct sh_wdt *wdt)
122 csr &= ~RSTCSR_RSTS; 120 csr &= ~RSTCSR_RSTS;
123 sh_wdt_write_rstcsr(csr); 121 sh_wdt_write_rstcsr(csr);
124#endif 122#endif
125 spin_unlock_irqrestore(&shwdt_lock, flags); 123 spin_unlock_irqrestore(&wdt->lock, flags);
124
125 return 0;
126} 126}
127 127
128static void sh_wdt_stop(struct sh_wdt *wdt) 128static int sh_wdt_stop(struct watchdog_device *wdt_dev)
129{ 129{
130 struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
130 unsigned long flags; 131 unsigned long flags;
131 u8 csr; 132 u8 csr;
132 133
133 spin_lock_irqsave(&shwdt_lock, flags); 134 spin_lock_irqsave(&wdt->lock, flags);
134 135
135 del_timer(&wdt->timer); 136 del_timer(&wdt->timer);
136 137
@@ -138,28 +139,39 @@ static void sh_wdt_stop(struct sh_wdt *wdt)
138 csr &= ~WTCSR_TME; 139 csr &= ~WTCSR_TME;
139 sh_wdt_write_csr(csr); 140 sh_wdt_write_csr(csr);
140 141
141 spin_unlock_irqrestore(&shwdt_lock, flags); 142 spin_unlock_irqrestore(&wdt->lock, flags);
143
144 clk_disable(wdt->clk);
145 pm_runtime_put_sync(wdt->dev);
146
147 return 0;
142} 148}
143 149
144static inline void sh_wdt_keepalive(struct sh_wdt *wdt) 150static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
145{ 151{
152 struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
146 unsigned long flags; 153 unsigned long flags;
147 154
148 spin_lock_irqsave(&shwdt_lock, flags); 155 spin_lock_irqsave(&wdt->lock, flags);
149 next_heartbeat = jiffies + (heartbeat * HZ); 156 next_heartbeat = jiffies + (heartbeat * HZ);
150 spin_unlock_irqrestore(&shwdt_lock, flags); 157 spin_unlock_irqrestore(&wdt->lock, flags);
158
159 return 0;
151} 160}
152 161
153static int sh_wdt_set_heartbeat(int t) 162static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
154{ 163{
164 struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
155 unsigned long flags; 165 unsigned long flags;
156 166
157 if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */ 167 if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
158 return -EINVAL; 168 return -EINVAL;
159 169
160 spin_lock_irqsave(&shwdt_lock, flags); 170 spin_lock_irqsave(&wdt->lock, flags);
161 heartbeat = t; 171 heartbeat = t;
162 spin_unlock_irqrestore(&shwdt_lock, flags); 172 wdt_dev->timeout = t;
173 spin_unlock_irqrestore(&wdt->lock, flags);
174
163 return 0; 175 return 0;
164} 176}
165 177
@@ -168,7 +180,7 @@ static void sh_wdt_ping(unsigned long data)
168 struct sh_wdt *wdt = (struct sh_wdt *)data; 180 struct sh_wdt *wdt = (struct sh_wdt *)data;
169 unsigned long flags; 181 unsigned long flags;
170 182
171 spin_lock_irqsave(&shwdt_lock, flags); 183 spin_lock_irqsave(&wdt->lock, flags);
172 if (time_before(jiffies, next_heartbeat)) { 184 if (time_before(jiffies, next_heartbeat)) {
173 u8 csr; 185 u8 csr;
174 186
@@ -182,137 +194,9 @@ static void sh_wdt_ping(unsigned long data)
182 } else 194 } else
183 dev_warn(wdt->dev, "Heartbeat lost! Will not ping " 195 dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
184 "the watchdog\n"); 196 "the watchdog\n");
185 spin_unlock_irqrestore(&shwdt_lock, flags); 197 spin_unlock_irqrestore(&wdt->lock, flags);
186}
187
188static int sh_wdt_open(struct inode *inode, struct file *file)
189{
190 struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
191
192 if (test_and_set_bit(0, &wdt->enabled))
193 return -EBUSY;
194 if (nowayout)
195 __module_get(THIS_MODULE);
196
197 file->private_data = wdt;
198
199 sh_wdt_start(wdt);
200
201 return nonseekable_open(inode, file);
202}
203
204static int sh_wdt_close(struct inode *inode, struct file *file)
205{
206 struct sh_wdt *wdt = file->private_data;
207
208 if (wdt->expect_close == 42) {
209 sh_wdt_stop(wdt);
210 } else {
211 dev_crit(wdt->dev, "Unexpected close, not "
212 "stopping watchdog!\n");
213 sh_wdt_keepalive(wdt);
214 }
215
216 clear_bit(0, &wdt->enabled);
217 wdt->expect_close = 0;
218
219 return 0;
220}
221
222static ssize_t sh_wdt_write(struct file *file, const char *buf,
223 size_t count, loff_t *ppos)
224{
225 struct sh_wdt *wdt = file->private_data;
226
227 if (count) {
228 if (!nowayout) {
229 size_t i;
230
231 wdt->expect_close = 0;
232
233 for (i = 0; i != count; i++) {
234 char c;
235 if (get_user(c, buf + i))
236 return -EFAULT;
237 if (c == 'V')
238 wdt->expect_close = 42;
239 }
240 }
241 sh_wdt_keepalive(wdt);
242 }
243
244 return count;
245} 198}
246 199
247static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
248 unsigned long arg)
249{
250 struct sh_wdt *wdt = file->private_data;
251 int new_heartbeat;
252 int options, retval = -EINVAL;
253
254 switch (cmd) {
255 case WDIOC_GETSUPPORT:
256 return copy_to_user((struct watchdog_info *)arg,
257 &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
258 case WDIOC_GETSTATUS:
259 case WDIOC_GETBOOTSTATUS:
260 return put_user(0, (int *)arg);
261 case WDIOC_SETOPTIONS:
262 if (get_user(options, (int *)arg))
263 return -EFAULT;
264
265 if (options & WDIOS_DISABLECARD) {
266 sh_wdt_stop(wdt);
267 retval = 0;
268 }
269
270 if (options & WDIOS_ENABLECARD) {
271 sh_wdt_start(wdt);
272 retval = 0;
273 }
274
275 return retval;
276 case WDIOC_KEEPALIVE:
277 sh_wdt_keepalive(wdt);
278 return 0;
279 case WDIOC_SETTIMEOUT:
280 if (get_user(new_heartbeat, (int *)arg))
281 return -EFAULT;
282
283 if (sh_wdt_set_heartbeat(new_heartbeat))
284 return -EINVAL;
285
286 sh_wdt_keepalive(wdt);
287 /* Fall */
288 case WDIOC_GETTIMEOUT:
289 return put_user(heartbeat, (int *)arg);
290 default:
291 return -ENOTTY;
292 }
293 return 0;
294}
295
296static int sh_wdt_notify_sys(struct notifier_block *this,
297 unsigned long code, void *unused)
298{
299 struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
300
301 if (code == SYS_DOWN || code == SYS_HALT)
302 sh_wdt_stop(wdt);
303
304 return NOTIFY_DONE;
305}
306
307static const struct file_operations sh_wdt_fops = {
308 .owner = THIS_MODULE,
309 .llseek = no_llseek,
310 .write = sh_wdt_write,
311 .unlocked_ioctl = sh_wdt_ioctl,
312 .open = sh_wdt_open,
313 .release = sh_wdt_close,
314};
315
316static const struct watchdog_info sh_wdt_info = { 200static const struct watchdog_info sh_wdt_info = {
317 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | 201 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
318 WDIOF_MAGICCLOSE, 202 WDIOF_MAGICCLOSE,
@@ -320,14 +204,17 @@ static const struct watchdog_info sh_wdt_info = {
320 .identity = "SH WDT", 204 .identity = "SH WDT",
321}; 205};
322 206
323static struct notifier_block sh_wdt_notifier = { 207static const struct watchdog_ops sh_wdt_ops = {
324 .notifier_call = sh_wdt_notify_sys, 208 .owner = THIS_MODULE,
209 .start = sh_wdt_start,
210 .stop = sh_wdt_stop,
211 .ping = sh_wdt_keepalive,
212 .set_timeout = sh_wdt_set_heartbeat,
325}; 213};
326 214
327static struct miscdevice sh_wdt_miscdev = { 215static struct watchdog_device sh_wdt_dev = {
328 .minor = WATCHDOG_MINOR, 216 .info = &sh_wdt_info,
329 .name = "watchdog", 217 .ops = &sh_wdt_ops,
330 .fops = &sh_wdt_fops,
331}; 218};
332 219
333static int __devinit sh_wdt_probe(struct platform_device *pdev) 220static int __devinit sh_wdt_probe(struct platform_device *pdev)
@@ -347,39 +234,49 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
347 if (unlikely(!res)) 234 if (unlikely(!res))
348 return -EINVAL; 235 return -EINVAL;
349 236
350 if (!devm_request_mem_region(&pdev->dev, res->start,
351 resource_size(res), DRV_NAME))
352 return -EBUSY;
353
354 wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL); 237 wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
355 if (unlikely(!wdt)) { 238 if (unlikely(!wdt))
356 rc = -ENOMEM; 239 return -ENOMEM;
357 goto out_release;
358 }
359 240
360 wdt->dev = &pdev->dev; 241 wdt->dev = &pdev->dev;
361 242
362 wdt->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 243 wdt->clk = clk_get(&pdev->dev, NULL);
244 if (IS_ERR(wdt->clk)) {
245 /*
246 * Clock framework support is optional, continue on
247 * anyways if we don't find a matching clock.
248 */
249 wdt->clk = NULL;
250 }
251
252 wdt->base = devm_request_and_ioremap(wdt->dev, res);
363 if (unlikely(!wdt->base)) { 253 if (unlikely(!wdt->base)) {
364 rc = -ENXIO; 254 rc = -EADDRNOTAVAIL;
365 goto out_err; 255 goto err;
366 } 256 }
367 257
368 rc = register_reboot_notifier(&sh_wdt_notifier); 258 watchdog_set_nowayout(&sh_wdt_dev, nowayout);
259 watchdog_set_drvdata(&sh_wdt_dev, wdt);
260
261 spin_lock_init(&wdt->lock);
262
263 rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
369 if (unlikely(rc)) { 264 if (unlikely(rc)) {
370 dev_err(&pdev->dev, 265 /* Default timeout if invalid */
371 "Can't register reboot notifier (err=%d)\n", rc); 266 sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
372 goto out_unmap; 267
268 dev_warn(&pdev->dev,
269 "heartbeat value must be 1<=x<=3600, using %d\n",
270 sh_wdt_dev.timeout);
373 } 271 }
374 272
375 sh_wdt_miscdev.parent = wdt->dev; 273 dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
274 sh_wdt_dev.timeout, nowayout);
376 275
377 rc = misc_register(&sh_wdt_miscdev); 276 rc = watchdog_register_device(&sh_wdt_dev);
378 if (unlikely(rc)) { 277 if (unlikely(rc)) {
379 dev_err(&pdev->dev, 278 dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
380 "Can't register miscdev on minor=%d (err=%d)\n", 279 goto err;
381 sh_wdt_miscdev.minor, rc);
382 goto out_unreg;
383 } 280 }
384 281
385 init_timer(&wdt->timer); 282 init_timer(&wdt->timer);
@@ -388,20 +285,15 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
388 wdt->timer.expires = next_ping_period(clock_division_ratio); 285 wdt->timer.expires = next_ping_period(clock_division_ratio);
389 286
390 platform_set_drvdata(pdev, wdt); 287 platform_set_drvdata(pdev, wdt);
391 sh_wdt_dev = pdev;
392 288
393 dev_info(&pdev->dev, "initialized.\n"); 289 dev_info(&pdev->dev, "initialized.\n");
394 290
291 pm_runtime_enable(&pdev->dev);
292
395 return 0; 293 return 0;
396 294
397out_unreg: 295err:
398 unregister_reboot_notifier(&sh_wdt_notifier); 296 clk_put(wdt->clk);
399out_unmap:
400 devm_iounmap(&pdev->dev, wdt->base);
401out_err:
402 devm_kfree(&pdev->dev, wdt);
403out_release:
404 devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
405 297
406 return rc; 298 return rc;
407} 299}
@@ -409,36 +301,35 @@ out_release:
409static int __devexit sh_wdt_remove(struct platform_device *pdev) 301static int __devexit sh_wdt_remove(struct platform_device *pdev)
410{ 302{
411 struct sh_wdt *wdt = platform_get_drvdata(pdev); 303 struct sh_wdt *wdt = platform_get_drvdata(pdev);
412 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
413 304
414 platform_set_drvdata(pdev, NULL); 305 platform_set_drvdata(pdev, NULL);
415 306
416 misc_deregister(&sh_wdt_miscdev); 307 watchdog_unregister_device(&sh_wdt_dev);
417 308
418 sh_wdt_dev = NULL; 309 pm_runtime_disable(&pdev->dev);
419 310 clk_put(wdt->clk);
420 unregister_reboot_notifier(&sh_wdt_notifier);
421 devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
422 devm_iounmap(&pdev->dev, wdt->base);
423 devm_kfree(&pdev->dev, wdt);
424 311
425 return 0; 312 return 0;
426} 313}
427 314
315static void sh_wdt_shutdown(struct platform_device *pdev)
316{
317 sh_wdt_stop(&sh_wdt_dev);
318}
319
428static struct platform_driver sh_wdt_driver = { 320static struct platform_driver sh_wdt_driver = {
429 .driver = { 321 .driver = {
430 .name = DRV_NAME, 322 .name = DRV_NAME,
431 .owner = THIS_MODULE, 323 .owner = THIS_MODULE,
432 }, 324 },
433 325
434 .probe = sh_wdt_probe, 326 .probe = sh_wdt_probe,
435 .remove = __devexit_p(sh_wdt_remove), 327 .remove = __devexit_p(sh_wdt_remove),
328 .shutdown = sh_wdt_shutdown,
436}; 329};
437 330
438static int __init sh_wdt_init(void) 331static int __init sh_wdt_init(void)
439{ 332{
440 int rc;
441
442 if (unlikely(clock_division_ratio < 0x5 || 333 if (unlikely(clock_division_ratio < 0x5 ||
443 clock_division_ratio > 0x7)) { 334 clock_division_ratio > 0x7)) {
444 clock_division_ratio = WTCSR_CKS_4096; 335 clock_division_ratio = WTCSR_CKS_4096;
@@ -447,17 +338,6 @@ static int __init sh_wdt_init(void)
447 clock_division_ratio); 338 clock_division_ratio);
448 } 339 }
449 340
450 rc = sh_wdt_set_heartbeat(heartbeat);
451 if (unlikely(rc)) {
452 heartbeat = WATCHDOG_HEARTBEAT;
453
454 pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
455 heartbeat);
456 }
457
458 pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
459 heartbeat, nowayout);
460
461 return platform_driver_register(&sh_wdt_driver); 341 return platform_driver_register(&sh_wdt_driver);
462} 342}
463 343