tadpmu.c revision 1.2 1 1.2 macallan /*/* $NetBSD: tadpmu.c,v 1.2 2018/10/13 19:53:43 macallan Exp $ */
2 1.1 macallan
3 1.1 macallan /*-
4 1.1 macallan * Copyright (c) 2018 Michael Lorenz <macallan (at) netbsd.org>
5 1.1 macallan * All rights reserved.
6 1.1 macallan *
7 1.1 macallan * Redistribution and use in source and binary forms, with or without
8 1.1 macallan * modification, are permitted provided that the following conditions
9 1.1 macallan * are met:
10 1.1 macallan * 1. Redistributions of source code must retain the above copyright
11 1.1 macallan * notice, this list of conditions and the following disclaimer.
12 1.1 macallan * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 macallan * notice, this list of conditions and the following disclaimer in the
14 1.1 macallan * documentation and/or other materials provided with the distribution.
15 1.1 macallan *
16 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 macallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 macallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 macallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 macallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 macallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 macallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 macallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 macallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 macallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 macallan * POSSIBILITY OF SUCH DAMAGE.
27 1.1 macallan */
28 1.1 macallan
29 1.1 macallan /* a driver for the PMU found in Tadpole Wiper and possibly SPARCle laptops */
30 1.1 macallan
31 1.1 macallan #include <sys/param.h>
32 1.1 macallan #include <sys/systm.h>
33 1.1 macallan #include <sys/kernel.h>
34 1.1 macallan #include <sys/device.h>
35 1.1 macallan #include <sys/malloc.h>
36 1.2 macallan #include <sys/proc.h>
37 1.1 macallan #include <sys/bus.h>
38 1.1 macallan #include <sys/intr.h>
39 1.1 macallan
40 1.1 macallan #include <dev/sysmon/sysmonvar.h>
41 1.2 macallan #include <dev/sysmon/sysmon_taskq.h>
42 1.1 macallan
43 1.1 macallan #include <sparc64/dev/tadpmureg.h>
44 1.1 macallan #include <sparc64/dev/tadpmuvar.h>
45 1.1 macallan
46 1.2 macallan #ifdef TADPMU_DEBUG
47 1.2 macallan #define DPRINTF printf
48 1.2 macallan #else
49 1.2 macallan #define DPRINTF while (0) printf
50 1.2 macallan #endif
51 1.2 macallan
52 1.1 macallan static bus_space_tag_t tadpmu_iot;
53 1.1 macallan static bus_space_handle_t tadpmu_hcmd;
54 1.1 macallan static bus_space_handle_t tadpmu_hdata;
55 1.1 macallan static struct sysmon_envsys *tadpmu_sme;
56 1.1 macallan static envsys_data_t tadpmu_sensors[5];
57 1.2 macallan static uint8_t idata = 0xff;
58 1.2 macallan static uint8_t ivalid = 0;
59 1.2 macallan static wchan_t tadpmu;
60 1.2 macallan static struct sysmon_pswitch tadpmu_pbutton;
61 1.1 macallan
62 1.1 macallan static inline void
63 1.1 macallan tadpmu_cmd(uint8_t d)
64 1.1 macallan {
65 1.1 macallan bus_space_write_1(tadpmu_iot, tadpmu_hcmd, 0, d);
66 1.1 macallan }
67 1.1 macallan
68 1.1 macallan static inline void
69 1.1 macallan tadpmu_wdata(uint8_t d)
70 1.1 macallan {
71 1.1 macallan bus_space_write_1(tadpmu_iot, tadpmu_hdata, 0, d);
72 1.1 macallan }
73 1.1 macallan
74 1.1 macallan static inline uint8_t
75 1.1 macallan tadpmu_status(void)
76 1.1 macallan {
77 1.1 macallan return bus_space_read_1(tadpmu_iot, tadpmu_hcmd, 0);
78 1.1 macallan }
79 1.1 macallan
80 1.1 macallan static inline uint8_t
81 1.1 macallan tadpmu_data(void)
82 1.1 macallan {
83 1.1 macallan return bus_space_read_1(tadpmu_iot, tadpmu_hdata, 0);
84 1.1 macallan }
85 1.1 macallan
86 1.1 macallan static void
87 1.1 macallan tadpmu_flush(void)
88 1.1 macallan {
89 1.1 macallan volatile uint8_t junk, d;
90 1.1 macallan int bail = 0;
91 1.1 macallan
92 1.1 macallan d = tadpmu_status();
93 1.1 macallan while (d & STATUS_HAVE_DATA) {
94 1.1 macallan junk = tadpmu_data();
95 1.1 macallan __USE(junk);
96 1.1 macallan delay(10);
97 1.1 macallan bail++;
98 1.1 macallan if (bail > 100) {
99 1.1 macallan printf("%s: timeout waiting for data out to clear %2x\n",
100 1.1 macallan __func__, d);
101 1.1 macallan break;
102 1.1 macallan }
103 1.1 macallan d = tadpmu_status();
104 1.1 macallan }
105 1.1 macallan bail = 0;
106 1.1 macallan d = tadpmu_status();
107 1.1 macallan while (d & STATUS_SEND_DATA) {
108 1.1 macallan bus_space_write_1(tadpmu_iot, tadpmu_hdata, 0, 0);
109 1.1 macallan delay(10);
110 1.1 macallan bail++;
111 1.1 macallan if (bail > 100) {
112 1.1 macallan printf("%s: timeout waiting for data in to clear %02x\n",
113 1.1 macallan __func__, d);
114 1.1 macallan break;
115 1.1 macallan }
116 1.1 macallan d = tadpmu_status();
117 1.1 macallan }
118 1.1 macallan }
119 1.1 macallan
120 1.1 macallan static void
121 1.1 macallan tadpmu_send_cmd(uint8_t cmd)
122 1.1 macallan {
123 1.1 macallan int bail = 0;
124 1.1 macallan uint8_t d;
125 1.1 macallan
126 1.2 macallan ivalid = 0;
127 1.1 macallan tadpmu_cmd(cmd);
128 1.1 macallan
129 1.1 macallan d = tadpmu_status();
130 1.1 macallan while ((d & STATUS_CMD_IN_PROGRESS) == 0) {
131 1.1 macallan delay(10);
132 1.1 macallan bail++;
133 1.1 macallan if (bail > 100) {
134 1.1 macallan printf("%s: timeout waiting for command to start\n",
135 1.1 macallan __func__);
136 1.1 macallan break;
137 1.1 macallan }
138 1.1 macallan d = tadpmu_status();
139 1.1 macallan }
140 1.1 macallan }
141 1.1 macallan
142 1.1 macallan static uint8_t
143 1.1 macallan tadpmu_recv(void)
144 1.1 macallan {
145 1.1 macallan int bail = 0;
146 1.1 macallan uint8_t d;
147 1.1 macallan
148 1.2 macallan if (cold) {
149 1.2 macallan d = tadpmu_status();
150 1.2 macallan while ((d & STATUS_HAVE_DATA) == 0) {
151 1.2 macallan delay(10);
152 1.2 macallan bail++;
153 1.2 macallan if (bail > 1000) {
154 1.2 macallan printf("%s: timeout waiting for data %02x\n",
155 1.2 macallan __func__, d);
156 1.2 macallan break;
157 1.2 macallan }
158 1.2 macallan d = tadpmu_status();
159 1.1 macallan }
160 1.2 macallan return bus_space_read_1(tadpmu_iot, tadpmu_hdata, 0);
161 1.2 macallan } else {
162 1.2 macallan while (ivalid == 0)
163 1.2 macallan tsleep(tadpmu, 0, "pmucmd", 1);
164 1.2 macallan return idata;
165 1.1 macallan }
166 1.1 macallan }
167 1.1 macallan
168 1.1 macallan static void
169 1.1 macallan tadpmu_send(uint8_t v)
170 1.1 macallan {
171 1.1 macallan int bail = 0;
172 1.1 macallan uint8_t d;
173 1.1 macallan
174 1.1 macallan d = tadpmu_status();
175 1.1 macallan while ((d & STATUS_SEND_DATA) == 0) {
176 1.1 macallan delay(10);
177 1.1 macallan bail++;
178 1.1 macallan if (bail > 1000) {
179 1.1 macallan printf("%s: timeout waiting for PMU ready %02x\n", __func__, d);
180 1.1 macallan break;
181 1.1 macallan }
182 1.1 macallan d = tadpmu_status();
183 1.1 macallan }
184 1.1 macallan
185 1.1 macallan tadpmu_wdata(v);
186 1.1 macallan
187 1.1 macallan while ((d & STATUS_SEND_DATA) != 0) {
188 1.1 macallan delay(10);
189 1.1 macallan bail++;
190 1.1 macallan if (bail > 1000) {
191 1.1 macallan printf("%s: timeout waiting for accept data %02x\n", __func__, d);
192 1.1 macallan break;
193 1.1 macallan }
194 1.1 macallan d = tadpmu_status();
195 1.1 macallan }
196 1.1 macallan }
197 1.1 macallan
198 1.1 macallan static void
199 1.1 macallan tadpmu_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
200 1.1 macallan {
201 1.1 macallan int res;
202 1.1 macallan if (edata->private > 0) {
203 1.1 macallan tadpmu_flush();
204 1.1 macallan tadpmu_send_cmd(edata->private);
205 1.1 macallan res = tadpmu_recv();
206 1.1 macallan if (edata->units == ENVSYS_STEMP) {
207 1.1 macallan edata->value_cur = res * 1000000 + 273150000;
208 1.1 macallan } else {
209 1.1 macallan edata->value_cur = res;
210 1.1 macallan }
211 1.1 macallan edata->state = ENVSYS_SVALID;
212 1.1 macallan } else {
213 1.1 macallan edata->state = ENVSYS_SINVALID;
214 1.1 macallan }
215 1.1 macallan }
216 1.1 macallan
217 1.2 macallan int
218 1.2 macallan tadpmu_intr(void *cookie)
219 1.2 macallan {
220 1.2 macallan uint8_t s = tadpmu_status(), d;
221 1.2 macallan if (s & STATUS_INTR) {
222 1.2 macallan /* interrupt message */
223 1.2 macallan d = tadpmu_data();
224 1.2 macallan DPRINTF("status change %02x\n", d);
225 1.2 macallan switch (d) {
226 1.2 macallan case TADPMU_POWERBUTTON:
227 1.2 macallan sysmon_pswitch_event(&tadpmu_pbutton,
228 1.2 macallan PSWITCH_EVENT_PRESSED);
229 1.2 macallan break;
230 1.2 macallan case TADPMU_LID:
231 1.2 macallan /* read genstat and report lid */
232 1.2 macallan break;
233 1.2 macallan }
234 1.2 macallan }
235 1.2 macallan s = tadpmu_status();
236 1.2 macallan if (s & STATUS_HAVE_DATA) {
237 1.2 macallan idata = tadpmu_data();
238 1.2 macallan ivalid = 1;
239 1.2 macallan wakeup(tadpmu);
240 1.2 macallan DPRINTF("%s data %02x\n", __func__, idata);
241 1.2 macallan }
242 1.2 macallan
243 1.2 macallan return 1;
244 1.2 macallan }
245 1.2 macallan
246 1.1 macallan int
247 1.1 macallan tadpmu_init(bus_space_tag_t t, bus_space_handle_t hcmd, bus_space_handle_t hdata)
248 1.1 macallan {
249 1.1 macallan int ver;
250 1.1 macallan
251 1.1 macallan tadpmu_iot = t;
252 1.1 macallan tadpmu_hcmd = hcmd;
253 1.1 macallan tadpmu_hdata = hdata;
254 1.1 macallan
255 1.1 macallan tadpmu_flush();
256 1.1 macallan delay(1000);
257 1.1 macallan
258 1.1 macallan tadpmu_send_cmd(CMD_READ_VERSION);
259 1.1 macallan ver = tadpmu_recv();
260 1.1 macallan printf("Tadpole PMU Version 1.%d\n", ver);
261 1.1 macallan
262 1.1 macallan tadpmu_send_cmd(CMD_SET_OPMODE);
263 1.1 macallan tadpmu_send(0x75);
264 1.1 macallan
265 1.1 macallan tadpmu_send_cmd(CMD_READ_SYSTEMP);
266 1.1 macallan ver = tadpmu_recv();
267 1.1 macallan printf("Temperature %d\n", ver);
268 1.1 macallan
269 1.1 macallan tadpmu_send_cmd(CMD_READ_VBATT);
270 1.1 macallan ver = tadpmu_recv();
271 1.1 macallan printf("Battery voltage %d\n", ver);
272 1.1 macallan
273 1.1 macallan tadpmu_send_cmd(CMD_READ_GENSTAT);
274 1.1 macallan ver = tadpmu_recv();
275 1.1 macallan printf("status %02x\n", ver);
276 1.1 macallan
277 1.1 macallan tadpmu_sme = sysmon_envsys_create();
278 1.1 macallan tadpmu_sme->sme_name = "tadpmu";
279 1.1 macallan tadpmu_sme->sme_cookie = NULL;
280 1.1 macallan tadpmu_sme->sme_refresh = tadpmu_sensors_refresh;
281 1.1 macallan
282 1.1 macallan tadpmu_sensors[0].units = ENVSYS_STEMP;
283 1.1 macallan tadpmu_sensors[0].private = CMD_READ_SYSTEMP;
284 1.1 macallan strcpy(tadpmu_sensors[0].desc, "systemp");
285 1.1 macallan sysmon_envsys_sensor_attach(tadpmu_sme, &tadpmu_sensors[0]);
286 1.1 macallan #ifdef TADPMU_DEBUG
287 1.1 macallan tadpmu_sensors[1].units = ENVSYS_INTEGER;
288 1.1 macallan tadpmu_sensors[1].private = 0x17;
289 1.1 macallan strcpy(tadpmu_sensors[1].desc, "reg 17");
290 1.1 macallan sysmon_envsys_sensor_attach(tadpmu_sme, &tadpmu_sensors[1]);
291 1.1 macallan tadpmu_sensors[2].units = ENVSYS_INTEGER;
292 1.1 macallan tadpmu_sensors[2].private = 0x18;
293 1.1 macallan strcpy(tadpmu_sensors[2].desc, "reg 18");
294 1.1 macallan sysmon_envsys_sensor_attach(tadpmu_sme, &tadpmu_sensors[2]);
295 1.1 macallan tadpmu_sensors[3].units = ENVSYS_INTEGER;
296 1.1 macallan tadpmu_sensors[3].private = CMD_READ_GENSTAT;
297 1.1 macallan strcpy(tadpmu_sensors[3].desc, "genstat");
298 1.1 macallan sysmon_envsys_sensor_attach(tadpmu_sme, &tadpmu_sensors[3]);
299 1.1 macallan #if 0
300 1.1 macallan tadpmu_sensors[4].units = ENVSYS_INTEGER;
301 1.1 macallan tadpmu_sensors[4].private = CMD_READ_VBATT;
302 1.1 macallan strcpy(tadpmu_sensors[4].desc, "Vbatt");
303 1.1 macallan sysmon_envsys_sensor_attach(tadpmu_sme, &tadpmu_sensors[4]);
304 1.1 macallan #endif
305 1.1 macallan #endif
306 1.1 macallan sysmon_envsys_register(tadpmu_sme);
307 1.1 macallan
308 1.2 macallan sysmon_task_queue_init();
309 1.2 macallan memset(&tadpmu_pbutton, 0, sizeof(struct sysmon_pswitch));
310 1.2 macallan tadpmu_pbutton.smpsw_name = "tadpmu";
311 1.2 macallan tadpmu_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
312 1.2 macallan if (sysmon_pswitch_register(&tadpmu_pbutton) != 0)
313 1.2 macallan aprint_error(
314 1.2 macallan "unable to register power button with sysmon\n");
315 1.2 macallan
316 1.1 macallan return 0;
317 1.1 macallan }
318 1.1 macallan
319