Skip to content

Commit 790439e

Browse files
authored
Merge pull request #2 from Cinerar/khadas-vim-4.9.y
watchdog: kvims: update watchdog driver
2 parents e860c5a + fa92924 commit 790439e

File tree

6 files changed

+286
-15
lines changed

6 files changed

+286
-15
lines changed

arch/arm64/boot/dts/amlogic/kvim_linux.dts

+4
Original file line numberDiff line numberDiff line change
@@ -1142,3 +1142,7 @@
11421142
&audio_data{
11431143
status = "okay";
11441144
};
1145+
1146+
&amlwatchdog {
1147+
status = "okay";
1148+
};

arch/arm64/boot/dts/amlogic/mesongxl.dtsi

+2-9
Original file line numberDiff line numberDiff line change
@@ -211,17 +211,10 @@
211211
status = "okay";
212212
};
213213

214-
watchdog {
215-
compatible = "amlogic, meson-wdt";
214+
amlwatchdog: amlogic-watchdog {
215+
compatible = "amlogic,meson-gxbb-wdt";
216216
status = "disabled";
217-
default_timeout=<10>;
218-
reset_watchdog_method=<1>; /* 0:sysfs,1:kernel */
219-
reset_watchdog_time=<2>;
220-
shutdown_timeout=<10>;
221-
firmware_timeout=<6>;
222-
suspend_timeout=<6>;
223217
reg = <0x0 0xc11098d0 0x0 0x10>;
224-
clock-names = "xtal";
225218
clocks = <&xtal>;
226219
};
227220

arch/arm64/configs/kvim_defconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ CONFIG_AML_LED_TRIGGER_BREATHE=y
278278
CONFIG_AMLOGIC_JTAG=y
279279
CONFIG_AMLOGIC_JTAG_MESON=y
280280
CONFIG_AMLOGIC_WDT=y
281-
CONFIG_AMLOGIC_WDT_MESON=y
281+
CONFIG_GX_WDT=y
282282
CONFIG_AMLOGIC_WIFI=y
283283
CONFIG_AMLOGIC_BT_DEVICE=y
284284
CONFIG_AMLOGIC_DVB_COMPAT=y

drivers/amlogic/watchdog/Kconfig

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ menuconfig AMLOGIC_WDT
1313

1414

1515
if AMLOGIC_WDT
16-
config AMLOGIC_WDT_MESON
17-
bool "Amlogic Meson Watchdog"
16+
config GX_WDT
17+
tristate "Amlogic Meson GXBB SoCs watchdog support"
1818
default n
1919
help
20-
say y to enable Amlogic meson watchdog driver.
20+
Say Y here to include support for the watchdog timer
21+
in Amlogic Meson GXBB SoCs.
22+
To compile this driver as a module, choose M here: the
23+
module will be called gxbb_wdt.
2124
endif

drivers/amlogic/watchdog/Makefile

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22
# Makefile for MHL
33
#
44

5-
obj-$(CONFIG_AMLOGIC_WDT_MESON) += meson_wdt.o
6-
5+
obj-$(CONFIG_AMLOGIC_WDT_MESON) += gxbb_wdt.o

drivers/amlogic/watchdog/gxbb_wdt.c

+272
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
/*
2+
* This file is provided under a dual BSD/GPLv2 license. When using or
3+
* redistributing this file, you may do so under either license.
4+
*
5+
* GPL LICENSE SUMMARY
6+
*
7+
* Copyright (c) 2016 BayLibre, SAS.
8+
* Author: Neil Armstrong <[email protected]>
9+
*
10+
* This program is free software; you can redistribute it and/or modify
11+
* it under the terms of version 2 of the GNU General Public License as
12+
* published by the Free Software Foundation.
13+
*
14+
* This program is distributed in the hope that it will be useful, but
15+
* WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program; if not, see <http://www.gnu.org/licenses/>.
21+
* The full GNU General Public License is included in this distribution
22+
* in the file called COPYING.
23+
*
24+
* BSD LICENSE
25+
*
26+
* Copyright (c) 2016 BayLibre, SAS.
27+
* Author: Neil Armstrong <[email protected]>
28+
*
29+
* Redistribution and use in source and binary forms, with or without
30+
* modification, are permitted provided that the following conditions
31+
* are met:
32+
*
33+
* * Redistributions of source code must retain the above copyright
34+
* notice, this list of conditions and the following disclaimer.
35+
* * Redistributions in binary form must reproduce the above copyright
36+
* notice, this list of conditions and the following disclaimer in
37+
* the documentation and/or other materials provided with the
38+
* distribution.
39+
* * Neither the name of Intel Corporation nor the names of its
40+
* contributors may be used to endorse or promote products derived
41+
* from this software without specific prior written permission.
42+
*
43+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54+
*/
55+
#include <linux/clk.h>
56+
#include <linux/err.h>
57+
#include <linux/io.h>
58+
#include <linux/module.h>
59+
#include <linux/of.h>
60+
#include <linux/platform_device.h>
61+
#include <linux/slab.h>
62+
#include <linux/types.h>
63+
#include <linux/watchdog.h>
64+
65+
#define DEFAULT_TIMEOUT 30 /* seconds */
66+
67+
#define GXBB_WDT_CTRL_REG 0x0
68+
#define GXBB_WDT_TCNT_REG 0x8
69+
#define GXBB_WDT_RSET_REG 0xc
70+
71+
#define GXBB_WDT_CTRL_CLKDIV_EN BIT(25)
72+
#define GXBB_WDT_CTRL_CLK_EN BIT(24)
73+
#define GXBB_WDT_CTRL_EE_RESET BIT(21)
74+
#define GXBB_WDT_CTRL_EN BIT(18)
75+
#define GXBB_WDT_CTRL_DIV_MASK (BIT(18) - 1)
76+
77+
#define GXBB_WDT_TCNT_SETUP_MASK (BIT(16) - 1)
78+
#define GXBB_WDT_TCNT_CNT_SHIFT 16
79+
80+
struct meson_gxbb_wdt {
81+
void __iomem *reg_base;
82+
struct watchdog_device wdt_dev;
83+
struct clk *clk;
84+
};
85+
86+
static int meson_gxbb_wdt_start(struct watchdog_device *wdt_dev)
87+
{
88+
struct meson_gxbb_wdt *data = watchdog_get_drvdata(wdt_dev);
89+
90+
writel(readl(data->reg_base + GXBB_WDT_CTRL_REG) | GXBB_WDT_CTRL_EN,
91+
data->reg_base + GXBB_WDT_CTRL_REG);
92+
93+
return 0;
94+
}
95+
96+
static int meson_gxbb_wdt_stop(struct watchdog_device *wdt_dev)
97+
{
98+
struct meson_gxbb_wdt *data = watchdog_get_drvdata(wdt_dev);
99+
100+
writel(readl(data->reg_base + GXBB_WDT_CTRL_REG) & ~GXBB_WDT_CTRL_EN,
101+
data->reg_base + GXBB_WDT_CTRL_REG);
102+
103+
return 0;
104+
}
105+
106+
static int meson_gxbb_wdt_ping(struct watchdog_device *wdt_dev)
107+
{
108+
struct meson_gxbb_wdt *data = watchdog_get_drvdata(wdt_dev);
109+
110+
writel(0, data->reg_base + GXBB_WDT_RSET_REG);
111+
112+
return 0;
113+
}
114+
115+
static int meson_gxbb_wdt_set_timeout(struct watchdog_device *wdt_dev,
116+
unsigned int timeout)
117+
{
118+
struct meson_gxbb_wdt *data = watchdog_get_drvdata(wdt_dev);
119+
unsigned long tcnt = timeout * 1000;
120+
121+
if (tcnt > GXBB_WDT_TCNT_SETUP_MASK)
122+
tcnt = GXBB_WDT_TCNT_SETUP_MASK;
123+
124+
wdt_dev->timeout = timeout;
125+
126+
meson_gxbb_wdt_ping(wdt_dev);
127+
128+
writel(tcnt, data->reg_base + GXBB_WDT_TCNT_REG);
129+
130+
return 0;
131+
}
132+
133+
static unsigned int meson_gxbb_wdt_get_timeleft(struct watchdog_device *wdt_dev)
134+
{
135+
struct meson_gxbb_wdt *data = watchdog_get_drvdata(wdt_dev);
136+
unsigned long reg;
137+
138+
reg = readl(data->reg_base + GXBB_WDT_TCNT_REG);
139+
140+
return ((reg >> GXBB_WDT_TCNT_CNT_SHIFT) -
141+
(reg & GXBB_WDT_TCNT_SETUP_MASK)) / 1000;
142+
}
143+
144+
static const struct watchdog_ops meson_gxbb_wdt_ops = {
145+
.start = meson_gxbb_wdt_start,
146+
.stop = meson_gxbb_wdt_stop,
147+
.ping = meson_gxbb_wdt_ping,
148+
.set_timeout = meson_gxbb_wdt_set_timeout,
149+
.get_timeleft = meson_gxbb_wdt_get_timeleft,
150+
};
151+
152+
static const struct watchdog_info meson_gxbb_wdt_info = {
153+
.identity = "Meson GXBB Watchdog",
154+
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
155+
};
156+
157+
static int __maybe_unused meson_gxbb_wdt_resume(struct device *dev)
158+
{
159+
struct meson_gxbb_wdt *data = dev_get_drvdata(dev);
160+
161+
if (watchdog_active(&data->wdt_dev))
162+
meson_gxbb_wdt_start(&data->wdt_dev);
163+
164+
return 0;
165+
}
166+
167+
static int __maybe_unused meson_gxbb_wdt_suspend(struct device *dev)
168+
{
169+
struct meson_gxbb_wdt *data = dev_get_drvdata(dev);
170+
171+
if (watchdog_active(&data->wdt_dev))
172+
meson_gxbb_wdt_stop(&data->wdt_dev);
173+
174+
return 0;
175+
}
176+
177+
static const struct dev_pm_ops meson_gxbb_wdt_pm_ops = {
178+
SET_SYSTEM_SLEEP_PM_OPS(meson_gxbb_wdt_suspend, meson_gxbb_wdt_resume)
179+
};
180+
181+
static const struct of_device_id meson_gxbb_wdt_dt_ids[] = {
182+
{ .compatible = "amlogic,meson-gxbb-wdt", },
183+
{ /* sentinel */ },
184+
};
185+
MODULE_DEVICE_TABLE(of, meson_gxbb_wdt_dt_ids);
186+
187+
static int meson_gxbb_wdt_probe(struct platform_device *pdev)
188+
{
189+
struct meson_gxbb_wdt *data;
190+
struct resource *res;
191+
int ret;
192+
193+
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
194+
if (!data)
195+
return -ENOMEM;
196+
197+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
198+
data->reg_base = devm_ioremap_resource(&pdev->dev, res);
199+
if (IS_ERR(data->reg_base))
200+
return PTR_ERR(data->reg_base);
201+
202+
data->clk = devm_clk_get(&pdev->dev, NULL);
203+
if (IS_ERR(data->clk))
204+
return PTR_ERR(data->clk);
205+
206+
clk_prepare_enable(data->clk);
207+
208+
platform_set_drvdata(pdev, data);
209+
210+
data->wdt_dev.parent = &pdev->dev;
211+
data->wdt_dev.info = &meson_gxbb_wdt_info;
212+
data->wdt_dev.ops = &meson_gxbb_wdt_ops;
213+
/*
214+
data->wdt_dev.max_hw_heartbeat_ms = GXBB_WDT_TCNT_SETUP_MASK;
215+
data->wdt_dev.min_timeout = 1;
216+
*/
217+
data->wdt_dev.timeout = DEFAULT_TIMEOUT;
218+
watchdog_set_drvdata(&data->wdt_dev, data);
219+
220+
/* Setup with 1ms timebase */
221+
writel(((clk_get_rate(data->clk) / 1000) & GXBB_WDT_CTRL_DIV_MASK) |
222+
GXBB_WDT_CTRL_EE_RESET |
223+
GXBB_WDT_CTRL_CLK_EN |
224+
GXBB_WDT_CTRL_CLKDIV_EN,
225+
data->reg_base + GXBB_WDT_CTRL_REG);
226+
227+
meson_gxbb_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);
228+
229+
ret = watchdog_register_device(&data->wdt_dev);
230+
if (ret) {
231+
clk_disable_unprepare(data->clk);
232+
return ret;
233+
}
234+
235+
return 0;
236+
}
237+
238+
static int meson_gxbb_wdt_remove(struct platform_device *pdev)
239+
{
240+
struct meson_gxbb_wdt *data = platform_get_drvdata(pdev);
241+
242+
watchdog_unregister_device(&data->wdt_dev);
243+
244+
clk_disable_unprepare(data->clk);
245+
246+
return 0;
247+
}
248+
249+
static void meson_gxbb_wdt_shutdown(struct platform_device *pdev)
250+
{
251+
struct meson_gxbb_wdt *data = platform_get_drvdata(pdev);
252+
253+
meson_gxbb_wdt_stop(&data->wdt_dev);
254+
}
255+
256+
static struct platform_driver meson_gxbb_wdt_driver = {
257+
.probe = meson_gxbb_wdt_probe,
258+
.remove = meson_gxbb_wdt_remove,
259+
.shutdown = meson_gxbb_wdt_shutdown,
260+
.driver = {
261+
.name = "meson-gxbb-wdt",
262+
.pm = &meson_gxbb_wdt_pm_ops,
263+
.of_match_table = meson_gxbb_wdt_dt_ids,
264+
},
265+
};
266+
267+
module_platform_driver(meson_gxbb_wdt_driver);
268+
269+
MODULE_ALIAS("platform:meson-gxbb-wdt");
270+
MODULE_AUTHOR("Neil Armstrong <[email protected]>");
271+
MODULE_DESCRIPTION("Amlogic Meson GXBB Watchdog timer driver");
272+
MODULE_LICENSE("Dual BSD/GPL");

0 commit comments

Comments
 (0)