1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/clock.h>
38#include <sys/kernel.h>
39#include <sys/lock.h>
40#include <sys/module.h>
41
42#include <contrib/octeon-sdk/cvmx.h>
43#include <contrib/octeon-sdk/cvmx-rtc.h>
44
45#include "clock_if.h"
46
47static int	octeon_rtc_attach(device_t dev);
48static int	octeon_rtc_probe(device_t dev);
49
50static int	octeon_rtc_settime(device_t dev, struct timespec *ts);
51static int	octeon_rtc_gettime(device_t dev, struct timespec *ts);
52
53static device_method_t octeon_rtc_methods[] = {
54	/* Device interface */
55	DEVMETHOD(device_probe,		octeon_rtc_probe),
56	DEVMETHOD(device_attach,	octeon_rtc_attach),
57
58	/* clock interface */
59	DEVMETHOD(clock_gettime,	octeon_rtc_gettime),
60	DEVMETHOD(clock_settime,	octeon_rtc_settime),
61	{ 0, 0 }
62};
63
64static driver_t octeon_rtc_driver = {
65	"rtc",
66	octeon_rtc_methods,
67	0
68};
69static devclass_t octeon_rtc_devclass;
70DRIVER_MODULE(rtc, nexus, octeon_rtc_driver, octeon_rtc_devclass, 0, 0);
71
72static int
73octeon_rtc_probe(device_t dev)
74{
75	cvmx_rtc_options_t supported;
76
77	if (device_get_unit(dev) != 0)
78		return (ENXIO);
79
80	supported = cvmx_rtc_supported();
81	if (supported == 0)
82		return (ENXIO);
83
84	device_set_desc(dev, "Cavium Octeon Realtime Clock");
85	return (BUS_PROBE_NOWILDCARD);
86}
87
88static int
89octeon_rtc_attach(device_t dev)
90{
91	cvmx_rtc_options_t supported;
92
93	supported = cvmx_rtc_supported();
94	if ((supported & CVMX_RTC_READ) == 0)
95		return (ENXIO);
96
97	clock_register(dev, 1000000);
98	return (0);
99}
100
101static int
102octeon_rtc_settime(device_t dev, struct timespec *ts)
103{
104	cvmx_rtc_options_t supported;
105	uint32_t status;
106
107	supported = cvmx_rtc_supported();
108	if ((supported & CVMX_RTC_WRITE) == 0)
109		return (ENOTSUP);
110
111	status = cvmx_rtc_write(ts->tv_sec);
112	if (status != 0)
113		return (EINVAL);
114
115	return (0);
116}
117
118static int
119octeon_rtc_gettime(device_t dev, struct timespec *ts)
120{
121	uint32_t secs;
122
123	secs = cvmx_rtc_read();
124	if (secs == 0)
125		return (ENOTSUP);
126
127	ts->tv_sec = secs;
128	ts->tv_nsec = 0;
129
130	return (0);
131}
132