Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/ti/am335x/am335x_scm.c
39507 views
1
/*-
2
* Copyright (c) 2016 Rubicon Communications, LLC (Netgate)
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <sys/systm.h>
29
#include <sys/bus.h>
30
#include <sys/kernel.h>
31
#include <sys/module.h>
32
#include <sys/sysctl.h>
33
34
#include <machine/bus.h>
35
36
#include <arm/ti/am335x/am335x_scm.h>
37
#include <arm/ti/ti_cpuid.h>
38
#include <arm/ti/ti_scm.h>
39
40
#include <dev/syscon/syscon.h>
41
#include "syscon_if.h"
42
43
#define TZ_ZEROC 2731
44
45
struct am335x_scm_softc {
46
int sc_last_temp;
47
struct sysctl_oid *sc_temp_oid;
48
struct syscon *syscon;
49
};
50
51
static int
52
am335x_scm_temp_sysctl(SYSCTL_HANDLER_ARGS)
53
{
54
device_t dev;
55
int i, temp;
56
struct am335x_scm_softc *sc;
57
uint32_t reg;
58
59
dev = (device_t)arg1;
60
sc = device_get_softc(dev);
61
62
/* Read the temperature and convert to Kelvin. */
63
for(i = 50; i > 0; i--) {
64
reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL);
65
if ((reg & SCM_BGAP_EOCZ) == 0)
66
break;
67
DELAY(50);
68
}
69
if ((reg & SCM_BGAP_EOCZ) == 0) {
70
sc->sc_last_temp =
71
(reg >> SCM_BGAP_TEMP_SHIFT) & SCM_BGAP_TEMP_MASK;
72
sc->sc_last_temp *= 10;
73
}
74
temp = sc->sc_last_temp + TZ_ZEROC;
75
76
return (sysctl_handle_int(oidp, &temp, 0, req));
77
}
78
79
static void
80
am335x_scm_identify(driver_t *driver, device_t parent)
81
{
82
device_t child;
83
84
/* AM335x only. */
85
if (ti_chip() != CHIP_AM335X)
86
return;
87
88
/* Make sure we attach only once. */
89
if (device_find_child(parent, "am335x_scm", DEVICE_UNIT_ANY) != NULL)
90
return;
91
92
child = device_add_child(parent, "am335x_scm", DEVICE_UNIT_ANY);
93
if (child == NULL)
94
device_printf(parent, "cannot add ti_scm child\n");
95
}
96
97
static int
98
am335x_scm_probe(device_t dev)
99
{
100
/* Just allow the first one */
101
if (strcmp(device_get_nameunit(dev), "am335x_scm0") != 0)
102
return (ENXIO);
103
104
device_set_desc(dev, "AM335x Control Module Extension");
105
106
return (BUS_PROBE_DEFAULT);
107
}
108
109
static int
110
am335x_scm_attach(device_t dev)
111
{
112
struct am335x_scm_softc *sc;
113
struct sysctl_ctx_list *ctx;
114
struct sysctl_oid_list *tree;
115
uint32_t reg;
116
phandle_t opp_table;
117
int err;
118
119
sc = device_get_softc(dev);
120
121
/* FIXME: For now; Go and kidnap syscon from opp-table */
122
opp_table = OF_finddevice("/opp-table");
123
if (opp_table == -1) {
124
device_printf(dev, "Cant find /opp-table\n");
125
return (ENXIO);
126
}
127
if (!OF_hasprop(opp_table, "syscon")) {
128
device_printf(dev, "/opp-table missing syscon property\n");
129
return (ENXIO);
130
}
131
err = syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon);
132
if (err) {
133
device_printf(dev, "Failed to get syscon\n");
134
return (ENXIO);
135
}
136
137
/* Reset the digital outputs. */
138
SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, 0);
139
reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL);
140
DELAY(500);
141
/* Set continuous mode. */
142
SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, SCM_BGAP_CONTCONV);
143
reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL);
144
DELAY(500);
145
/* Start the ADC conversion. */
146
reg = SCM_BGAP_CLRZ | SCM_BGAP_CONTCONV | SCM_BGAP_SOC;
147
SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, reg);
148
149
/* Temperature sysctl. */
150
ctx = device_get_sysctl_ctx(dev);
151
tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
152
sc->sc_temp_oid = SYSCTL_ADD_PROC(ctx, tree, OID_AUTO,
153
"temperature", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
154
dev, 0, am335x_scm_temp_sysctl, "IK", "Current temperature");
155
156
return (0);
157
}
158
159
static int
160
am335x_scm_detach(device_t dev)
161
{
162
struct am335x_scm_softc *sc;
163
164
sc = device_get_softc(dev);
165
166
/* Remove temperature sysctl. */
167
if (sc->sc_temp_oid != NULL)
168
sysctl_remove_oid(sc->sc_temp_oid, 1, 0);
169
170
/* Stop the bandgap ADC. */
171
SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, SCM_BGAP_BGOFF);
172
173
return (0);
174
}
175
176
static device_method_t am335x_scm_methods[] = {
177
DEVMETHOD(device_identify, am335x_scm_identify),
178
DEVMETHOD(device_probe, am335x_scm_probe),
179
DEVMETHOD(device_attach, am335x_scm_attach),
180
DEVMETHOD(device_detach, am335x_scm_detach),
181
182
DEVMETHOD_END
183
};
184
185
static driver_t am335x_scm_driver = {
186
"am335x_scm",
187
am335x_scm_methods,
188
sizeof(struct am335x_scm_softc),
189
};
190
191
DRIVER_MODULE(am335x_scm, ti_scm, am335x_scm_driver, 0, 0);
192
MODULE_VERSION(am335x_scm, 1);
193
MODULE_DEPEND(am335x_scm, ti_scm_syscon, 1, 1, 1);
194
195