xref: /openbsd/sys/dev/usb/usps.c (revision 898184e3)
1 /*	$OpenBSD: usps.c,v 1.1 2011/09/16 15:48:19 yuo Exp $   */
2 
3 /*
4  * Copyright (c) 2011 Yojiro UO <yuo@nui.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Driver for usb smart power strip FX-5204PS */
20 
21 #include <sys/param.h>
22 #include <sys/proc.h>
23 #include <sys/systm.h>
24 #include <sys/kernel.h>
25 #include <sys/malloc.h>
26 #include <sys/device.h>
27 #include <sys/conf.h>
28 #include <sys/sensors.h>
29 
30 #include <dev/usb/usb.h>
31 #include <dev/usb/usbdi.h>
32 #include <dev/usb/usbdi_util.h>
33 #include <dev/usb/usbdevs.h>
34 
35 #ifdef USB_DEBUG
36 #define USPS_DEBUG
37 #endif
38 
39 #ifdef USPS_DEBUG
40 int	uspsdebug = 0;
41 #define DPRINTFN(n, x)	do { if (uspsdebug > (n)) printf x; } while (0)
42 #else
43 #define DPRINTFN(n, x)
44 #endif
45 
46 #define DPRINTF(x) DPRINTFN(0, x)
47 
48 #define USPS_UPDATE_TICK	1 /* sec */
49 #define USPS_TIMEOUT		1000 /* ms */
50 #define USPS_INTR_TICKS		50 /* ms */
51 
52 /* protocol */
53 #define USPS_CMD_START		0x01
54 #define USPS_CMD_VALUE		0x20
55 #define USPS_CMD_GET_FIRMWARE	0xc0
56 #define USPS_CMD_GET_SERIAL	0xc1
57 #define USPS_CMD_GET_VOLTAGE	0xb0
58 #define USPS_CMD_GET_TEMP	0xb4
59 #define USPS_CMD_GET_FREQ	0xa1
60 #define USPS_CMD_GET_UNK0	0xa2
61 
62 #define USPS_MODE_WATTAGE	0x10
63 #define USPS_MODE_CURRENT	0x30
64 
65 #define FX5204_NUM_PORTS	4
66 
67 struct usps_port_sensor {
68 	struct ksensor ave;
69 	struct ksensor min;
70 	struct ksensor max;
71 	int vave, vmin, vmax;
72 };
73 
74 struct usps_softc {
75 	struct device		 sc_dev;
76 	usbd_device_handle	 sc_udev;
77 	usbd_interface_handle	 sc_iface;
78 	usbd_pipe_handle	 sc_ipipe;
79 	int			 sc_isize;
80 	usbd_xfer_handle	 sc_xfer;
81 	uint8_t			 sc_buf[16];
82 	uint8_t			 *sc_intrbuf;
83 
84 	u_char			 sc_dying;
85 	uint16_t		 sc_flag;
86 
87 	/* device info */
88 	uint8_t		 	 sc_firmware_version[2];
89 	uint32_t		 sc_device_serial;
90 
91 	/* sensor framework */
92 	struct usps_port_sensor	 sc_port_sensor[FX5204_NUM_PORTS];
93 	struct usps_port_sensor	 sc_total_sensor;
94 	struct ksensor 		 sc_voltage_sensor;
95 	struct ksensor		 sc_frequency_sensor;
96 	struct ksensor		 sc_temp_sensor;
97 	struct ksensor		 sc_serial_sensor;
98 	struct ksensordev	 sc_sensordev;
99 	struct sensor_task	*sc_sensortask;
100 
101 	int			 sc_count;
102 };
103 
104 struct usps_port_pkt {
105 	uint8_t		header; /* should be 0x80 */
106 	uint16_t	seq;
107 	uint8_t		padding[5];
108 	uint16_t	port[4];
109 } __packed; /* 16 byte length struct */
110 
111 static const struct usb_devno usps_devs[] = {
112 	{ USB_VENDOR_FUJITSUCOMP, USB_PRODUCT_FUJITSUCOMP_FX5204PS},
113 };
114 #define usps_lookup(v, p) usb_lookup(usps_devs, v, p)
115 
116 int  usps_match(struct device *, void *, void *);
117 void usps_attach(struct device *, struct device *, void *);
118 int  usps_detach(struct device *, int);
119 int  usps_activate(struct device *, int);
120 void usps_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
121 
122 usbd_status usps_cmd(struct usps_softc *, uint8_t, uint16_t, uint16_t);
123 usbd_status usps_set_measurement_mode(struct usps_softc *, int);
124 
125 void usps_get_device_info(struct usps_softc *);
126 void usps_refresh(void *);
127 void usps_refresh_temp(struct usps_softc *);
128 void usps_refresh_power(struct usps_softc *);
129 void usps_refresh_ports(struct usps_softc *);
130 
131 struct cfdriver usps_cd = {
132 	NULL, "usps", DV_DULL
133 };
134 
135 const struct cfattach usps_ca = {
136 	sizeof(struct usps_softc),
137 	usps_match,
138 	usps_attach,
139 	usps_detach,
140 	usps_activate,
141 };
142 
143 int
144 usps_match(struct device *parent, void *match, void *aux)
145 {
146 	struct usb_attach_arg *uaa = aux;
147 
148 	if (uaa->iface != NULL)
149 		return UMATCH_NONE;
150 
151 	if (usps_lookup(uaa->vendor, uaa->product) == NULL)
152 		return UMATCH_NONE;
153 
154 	return (UMATCH_VENDOR_PRODUCT);
155 }
156 
157 void
158 usps_attach(struct device *parent, struct device *self, void *aux)
159 {
160 	struct usps_softc *sc = (struct usps_softc *)self;
161 	struct usb_attach_arg *uaa = aux;
162 	usb_interface_descriptor_t *id;
163 	usb_endpoint_descriptor_t *ed;
164 	int ep_ibulk, ep_obulk, ep_intr;
165 	usbd_status err;
166 	int i;
167 
168 	sc->sc_udev = uaa->device;
169 
170 #define USPS_USB_IFACE 0
171 #define USPS_USB_CONFIG 1
172 
173 	/* set configuration */
174 	if ((err = usbd_set_config_no(sc->sc_udev, USPS_USB_CONFIG, 0)) != 0){
175 		printf("%s: failed to set config %d: %s\n",
176 		    sc->sc_dev.dv_xname, USPS_USB_CONFIG, usbd_errstr(err));
177 		return;
178 	}
179 
180 	/* get interface handle */
181 	if ((err = usbd_device2interface_handle(sc->sc_udev, USPS_USB_IFACE,
182 		&sc->sc_iface)) != 0) {
183 		printf("%s: failed to get interface %d: %s\n",
184 		    sc->sc_dev.dv_xname, USPS_USB_IFACE, usbd_errstr(err));
185 		return;
186 	}
187 
188 	/* find endpoints */
189 	ep_ibulk = ep_obulk = ep_intr = -1;
190 	id = usbd_get_interface_descriptor(sc->sc_iface);
191 	for (i = 0; i < id->bNumEndpoints; i++) {
192 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
193 		if (ed == NULL) {
194 			printf("%s: failed to get endpoint %d descriptor\n",
195 			    sc->sc_dev.dv_xname, i);
196 			return;
197 		}
198 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
199 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
200 			ep_ibulk = ed->bEndpointAddress;
201 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
202 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
203 			ep_obulk = ed->bEndpointAddress;
204 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
205 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT){
206 			ep_intr = ed->bEndpointAddress;
207 			sc->sc_isize = UGETW(ed->wMaxPacketSize);
208 		}
209 	}
210 
211 	if (ep_intr == -1) {
212 		printf("%s: no data endpoint found\n", sc->sc_dev.dv_xname);
213 		return;
214 	}
215 
216 	usps_get_device_info(sc);
217 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
218 	    sizeof(sc->sc_sensordev.xname));
219 
220 	/* attach sensor */
221 	sc->sc_voltage_sensor.type = SENSOR_VOLTS_AC;
222 	sc->sc_frequency_sensor.type = SENSOR_FREQ;
223 	sc->sc_temp_sensor.type = SENSOR_TEMP;
224 	sc->sc_serial_sensor.type = SENSOR_INTEGER;
225 	sensor_attach(&sc->sc_sensordev, &sc->sc_voltage_sensor);
226 	sensor_attach(&sc->sc_sensordev, &sc->sc_frequency_sensor);
227 	sensor_attach(&sc->sc_sensordev, &sc->sc_temp_sensor);
228 	sensor_attach(&sc->sc_sensordev, &sc->sc_serial_sensor);
229 
230 	sc->sc_serial_sensor.value = sc->sc_device_serial;
231 	strlcpy(sc->sc_serial_sensor.desc, "unit serial#",
232 	    sizeof(sc->sc_serial_sensor.desc));
233 
234 	/*
235 	 * XXX: the device has mode of par port sensor, Watt of Ampair.
236 	 * currently only watt mode is selected.
237 	 */
238 	usps_set_measurement_mode(sc, USPS_MODE_WATTAGE);
239 	for (i = 0; i < FX5204_NUM_PORTS; i++) {
240 		sc->sc_port_sensor[i].ave.type = SENSOR_WATTS;
241 		sc->sc_port_sensor[i].min.type = SENSOR_WATTS;
242 		sc->sc_port_sensor[i].max.type = SENSOR_WATTS;
243 		sensor_attach(&sc->sc_sensordev, &sc->sc_port_sensor[i].ave);
244 		sensor_attach(&sc->sc_sensordev, &sc->sc_port_sensor[i].min);
245 		sensor_attach(&sc->sc_sensordev, &sc->sc_port_sensor[i].max);
246 		(void)snprintf(sc->sc_port_sensor[i].ave.desc,
247 		    sizeof(sc->sc_port_sensor[i].ave.desc),
248 		    "port#%d (average)", i);
249 		(void)snprintf(sc->sc_port_sensor[i].min.desc,
250 		    sizeof(sc->sc_port_sensor[i].min.desc),
251 		    "port#%d (min)", i);
252 		(void)snprintf(sc->sc_port_sensor[i].max.desc,
253 		    sizeof(sc->sc_port_sensor[i].max.desc),
254 		    "port#%d (max)", i);
255 	}
256 
257 	sc->sc_total_sensor.ave.type = SENSOR_WATTS;
258 	sc->sc_total_sensor.min.type = SENSOR_WATTS;
259 	sc->sc_total_sensor.max.type = SENSOR_WATTS;
260 	sensor_attach(&sc->sc_sensordev, &sc->sc_total_sensor.ave);
261 	sensor_attach(&sc->sc_sensordev, &sc->sc_total_sensor.min);
262 	sensor_attach(&sc->sc_sensordev, &sc->sc_total_sensor.max);
263 	(void)snprintf(sc->sc_total_sensor.ave.desc,
264 	    sizeof(sc->sc_total_sensor.ave.desc), "total (average)", i);
265 	(void)snprintf(sc->sc_total_sensor.min.desc,
266 	    sizeof(sc->sc_total_sensor.ave.desc), "total (min)", i);
267 	(void)snprintf(sc->sc_total_sensor.max.desc,
268 	    sizeof(sc->sc_total_sensor.ave.desc), "total (max)", i);
269 
270 	sc->sc_sensortask = sensor_task_register(sc, usps_refresh,
271 	    USPS_UPDATE_TICK);
272 	if (sc->sc_sensortask == NULL) {
273 		printf(", unable to register update task\n");
274 		goto fail;
275 	}
276 
277 	printf("%s: device#=%d, firmware version=V%02dL%02d\n",
278 	    sc->sc_dev.dv_xname, sc->sc_device_serial,
279 	    sc->sc_firmware_version[0],
280 	    sc->sc_firmware_version[1]);
281 
282 	sensordev_install(&sc->sc_sensordev);
283 
284 	/* open interrupt endpoint */
285 	sc->sc_intrbuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
286 	if (sc->sc_intrbuf == NULL)
287 		goto fail;
288 	err = usbd_open_pipe_intr(sc->sc_iface, ep_intr,
289 	    USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_intrbuf,
290 	    sc->sc_isize, usps_intr, USPS_INTR_TICKS);
291 	if (err) {
292 		printf("%s: could not open intr pipe %s\n",
293 		    sc->sc_dev.dv_xname, usbd_errstr(err));
294 		goto fail;
295 	}
296 
297 	DPRINTF(("usps_attach: complete\n"));
298 	return;
299 
300 fail:
301 	if (sc->sc_ipipe != NULL)
302 		usbd_close_pipe(sc->sc_ipipe);
303 	if (sc->sc_xfer != NULL)
304 		usbd_free_xfer(sc->sc_xfer);
305 	if (sc->sc_intrbuf != NULL)
306 		free(sc->sc_intrbuf, M_USBDEV);
307 }
308 
309 int
310 usps_detach(struct device *self, int flags)
311 {
312 	struct usps_softc *sc = (struct usps_softc *)self;
313 	int i, rv = 0, s;
314 
315 	sc->sc_dying = 1;
316 
317 	s = splusb();
318 	if (sc->sc_ipipe != NULL) {
319 		usbd_abort_pipe(sc->sc_ipipe);
320 		usbd_close_pipe(sc->sc_ipipe);
321 		if (sc->sc_intrbuf != NULL)
322 			free(sc->sc_intrbuf, M_USBDEV);
323 		sc->sc_ipipe = NULL;
324 	}
325 	if (sc->sc_xfer != NULL)
326 		usbd_free_xfer(sc->sc_xfer);
327 	splx(s);
328 
329 	wakeup(&sc->sc_sensortask);
330 	sensordev_deinstall(&sc->sc_sensordev);
331 	sensor_detach(&sc->sc_sensordev, &sc->sc_voltage_sensor);
332 	sensor_detach(&sc->sc_sensordev, &sc->sc_frequency_sensor);
333 	sensor_detach(&sc->sc_sensordev, &sc->sc_temp_sensor);
334 	sensor_detach(&sc->sc_sensordev, &sc->sc_serial_sensor);
335 	for (i = 0; i < FX5204_NUM_PORTS; i++) {
336 		sensor_detach(&sc->sc_sensordev, &sc->sc_port_sensor[i].ave);
337 		sensor_detach(&sc->sc_sensordev, &sc->sc_port_sensor[i].min);
338 		sensor_detach(&sc->sc_sensordev, &sc->sc_port_sensor[i].max);
339 	}
340 	sensor_detach(&sc->sc_sensordev, &sc->sc_total_sensor.ave);
341 	sensor_detach(&sc->sc_sensordev, &sc->sc_total_sensor.min);
342 	sensor_detach(&sc->sc_sensordev, &sc->sc_total_sensor.max);
343 
344 	if (sc->sc_sensortask != NULL)
345 		sensor_task_unregister(sc->sc_sensortask);
346 
347 	return (rv);
348 }
349 
350 int
351 usps_activate(struct device *self, int act)
352 {
353 	struct usps_softc *sc = (struct usps_softc *)self;
354 
355 	switch (act) {
356 	case DVACT_DEACTIVATE:
357 		sc->sc_dying = 1;
358 		break;
359 	}
360 	return (0);
361 }
362 
363 usbd_status
364 usps_cmd(struct usps_softc *sc, uint8_t cmd, uint16_t val, uint16_t len)
365 {
366 	usb_device_request_t req;
367 	usbd_status err;
368 
369 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
370 	req.bRequest = cmd;
371 	USETW(req.wValue, val);
372 	USETW(req.wIndex, 0);
373 	USETW(req.wLength, len);
374 
375 	err = usbd_do_request(sc->sc_udev, &req, &sc->sc_buf);
376 	if (err) {
377 		printf("%s: could not issue sensor cmd: %s\n",
378 		    sc->sc_dev.dv_xname, usbd_errstr(err));
379 		return (EIO);
380 	}
381 
382 	return (0);
383 }
384 
385 usbd_status
386 usps_set_measurement_mode(struct usps_softc *sc, int mode)
387 {
388 	usb_device_request_t req;
389 	usbd_status err;
390 
391 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
392 	req.bRequest = USPS_CMD_START;
393 	USETW(req.wValue, 0);
394 	USETW(req.wIndex, 0);
395 	USETW(req.wLength, 0);
396 
397 	err = usbd_do_request(sc->sc_udev, &req, &sc->sc_buf);
398 	if (err) {
399 		printf("%s: fail to set sensor mode: %s\n",
400 		    sc->sc_dev.dv_xname, usbd_errstr(err));
401 		return (EIO);
402 	}
403 
404 	req.bRequest = USPS_CMD_VALUE;
405 	USETW(req.wValue, mode);
406 
407 	err = usbd_do_request(sc->sc_udev, &req, &sc->sc_buf);
408 	if (err) {
409 		printf("%s: could not set sensor mode: %s\n",
410 		    sc->sc_dev.dv_xname, usbd_errstr(err));
411 		return (EIO);
412 	}
413 
414 	return (0);
415 }
416 
417 void
418 usps_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
419 {
420 	struct usps_softc *sc = priv;
421 	struct usps_port_pkt *pkt;
422 	struct usps_port_sensor *ps;
423 	int i, total;
424 
425 	if (sc->sc_dying)
426 		return;
427 
428 	if (status != USBD_NORMAL_COMPLETION) {
429 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
430 			return;
431 		if (status == USBD_STALLED)
432 			usbd_clear_endpoint_stall_async(sc->sc_ipipe);
433 		return;
434 	}
435 
436 	/* process intr packet */
437 	if (sc->sc_intrbuf == NULL)
438 		return;
439 
440 	pkt = (struct usps_port_pkt *)sc->sc_intrbuf;
441 
442 	total = 0;
443 	for (i = 0; i < FX5204_NUM_PORTS; i++) {
444 		ps = &sc->sc_port_sensor[i];
445 		if (sc->sc_count == 0)
446 			ps->vmax = ps->vmin = pkt->port[i];
447 		if (pkt->port[i] > ps->vmax)
448 			ps->vmax = pkt->port[i];
449 		if (pkt->port[i] < ps->vmin)
450 			ps->vmin = pkt->port[i];
451 		ps->vave =
452 		    (ps->vave * sc->sc_count + pkt->port[i])/(sc->sc_count +1);
453 		total += pkt->port[i];
454 	}
455 
456 	/* calculate ports total */
457 	ps = &sc->sc_total_sensor;
458 	if (sc->sc_count == 0)
459 		ps->vmax = ps->vmin = total;
460 	if (total > ps->vmax)
461 		ps->vmax = total;
462 	if (total < ps->vmin)
463 		ps->vmin = total;
464 	ps->vave = (ps->vave * sc->sc_count + total)/(sc->sc_count +1);
465 
466 	sc->sc_count++;
467 }
468 
469 void
470 usps_get_device_info(struct usps_softc *sc)
471 {
472 	int serial;
473 
474 	/* get Firmware version */
475 	usps_cmd(sc, USPS_CMD_GET_FIRMWARE, 0, 2);
476 	sc->sc_firmware_version[0] =
477 	    (sc->sc_buf[0]>>4) * 10 + (sc->sc_buf[0] & 0xf);
478 	sc->sc_firmware_version[1] =
479 	    (sc->sc_buf[1]>>4) * 10 + (sc->sc_buf[1] & 0xf);
480 
481 	/* get device serial number */
482 	usps_cmd(sc, USPS_CMD_GET_SERIAL, 0, 3);
483 
484 	serial = 0;
485 	serial += ((sc->sc_buf[0]>>4) * 10 + (sc->sc_buf[0] & 0xf)) * 10000;
486 	serial += ((sc->sc_buf[1]>>4) * 10 + (sc->sc_buf[1] & 0xf)) * 100;
487 	serial += ((sc->sc_buf[2]>>4) * 10 + (sc->sc_buf[2] & 0xf));
488 	sc->sc_device_serial = serial;
489 }
490 
491 void
492 usps_refresh(void *arg)
493 {
494 	struct usps_softc *sc = arg;
495 
496 	usps_refresh_temp(sc);
497 	usps_refresh_power(sc);
498 	usps_refresh_ports(sc);
499 }
500 
501 void
502 usps_refresh_ports(struct usps_softc *sc)
503 {
504 	int i;
505 	struct usps_port_sensor *ps;
506 
507 	/* update port values */
508 	for (i = 0; i < FX5204_NUM_PORTS; i++) {
509 		ps = &sc->sc_port_sensor[i];
510 		ps->ave.value = ps->vave * 1000000;
511 		ps->min.value = ps->vmin * 1000000;
512 		ps->max.value = ps->vmax * 1000000;
513 	}
514 
515 	/* update total value */
516 	ps = &sc->sc_total_sensor;
517 	ps->ave.value = ps->vave * 1000000;
518 	ps->min.value = ps->vmin * 1000000;
519 	ps->max.value = ps->vmax * 1000000;
520 
521 	sc->sc_count = 0;
522 }
523 
524 void
525 usps_refresh_temp(struct usps_softc *sc)
526 {
527 	int temp;
528 
529 	if (usps_cmd(sc, USPS_CMD_GET_TEMP, 0, 2) != 0) {
530 		DPRINTF(("%s: temperature data read error\n",
531 		    sc->sc_dev.dv_xname));
532 		sc->sc_temp_sensor.flags |= SENSOR_FINVALID;
533 		return;
534 	}
535 	temp = (sc->sc_buf[1] << 8) + sc->sc_buf[0];
536 	sc->sc_temp_sensor.value = (temp * 10000) + 273150000;
537 	sc->sc_temp_sensor.flags &= ~SENSOR_FINVALID;
538 }
539 
540 void
541 usps_refresh_power(struct usps_softc *sc)
542 {
543 	int v;
544 	uint val;
545 	uint64_t f;
546 
547 	/* update source voltage */
548 	if (usps_cmd(sc, USPS_CMD_GET_VOLTAGE, 0, 1) != 0) {
549 		DPRINTF(("%s: voltage data read error\n", sc->sc_dev.dv_xname));
550 		sc->sc_voltage_sensor.flags |= SENSOR_FINVALID;
551 		return;
552 	}
553 
554 	v = sc->sc_buf[0] * 1000000;
555 	sc->sc_voltage_sensor.value = v;
556 	sc->sc_voltage_sensor.flags &= ~SENSOR_FINVALID;
557 
558 	/* update source frequency */
559 	if (usps_cmd(sc, USPS_CMD_GET_FREQ, 0, 8) != 0) {
560 		DPRINTF(("%s: frequency data read error\n",
561 		    sc->sc_dev.dv_xname));
562 		sc->sc_frequency_sensor.flags |= SENSOR_FINVALID;
563 		return;
564 	}
565 
566 	if (sc->sc_buf[7] == 0 && sc->sc_buf[6] == 0) {
567 		/* special case */
568 		f = 0;
569 	} else {
570 		val = (sc->sc_buf[1] << 8) + sc->sc_buf[0];
571 		if (val == 0) {
572 			/* guard against "division by zero" */
573 			sc->sc_frequency_sensor.flags |= SENSOR_FINVALID;
574 			return;
575 		}
576 		f = 2000000L;
577 		f *=  1000000L;
578 		f /= val;
579 	}
580 
581 	sc->sc_frequency_sensor.value = f;
582 	sc->sc_frequency_sensor.flags &= ~SENSOR_FINVALID;
583 }
584