1222457Sattilio/*-
2222457Sattilio * Copyright (c) 2010 Andreas Tobler
3222457Sattilio * All rights reserved.
4222457Sattilio *
5222457Sattilio * Redistribution and use in source and binary forms, with or without
6222457Sattilio * modification, are permitted provided that the following conditions
7222457Sattilio * are met:
8222457Sattilio * 1. Redistributions of source code must retain the above copyright
9222457Sattilio *    notice, this list of conditions and the following disclaimer.
10222457Sattilio * 2. Redistributions in binary form must reproduce the above copyright
11222457Sattilio *    notice, this list of conditions and the following disclaimer in the
12222457Sattilio *    documentation and/or other materials provided with the distribution.
13222457Sattilio *
14222457Sattilio * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15222457Sattilio * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16222457Sattilio * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17222457Sattilio * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18222457Sattilio * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19222457Sattilio * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20222457Sattilio * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21222457Sattilio * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22222457Sattilio * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23222457Sattilio * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24222457Sattilio * SUCH DAMAGE.
25222457Sattilio */
26222457Sattilio
27222457Sattilio#include <sys/cdefs.h>
28222457Sattilio__FBSDID("$FreeBSD: releng/10.3/sys/dev/iicbus/ad7417.c 239397 2012-08-19 19:31:36Z andreast $");
29222457Sattilio
30222457Sattilio#include <sys/param.h>
31222457Sattilio#include <sys/bus.h>
32222457Sattilio#include <sys/systm.h>
33222457Sattilio#include <sys/module.h>
34222457Sattilio#include <sys/callout.h>
35222457Sattilio#include <sys/conf.h>
36222457Sattilio#include <sys/cpu.h>
37222457Sattilio#include <sys/ctype.h>
38222457Sattilio#include <sys/kernel.h>
39222457Sattilio#include <sys/reboot.h>
40222457Sattilio#include <sys/rman.h>
41222457Sattilio#include <sys/sysctl.h>
42222457Sattilio#include <sys/limits.h>
43222457Sattilio
44222457Sattilio#include <machine/bus.h>
45222457Sattilio#include <machine/md_var.h>
46222457Sattilio
47222457Sattilio#include <dev/iicbus/iicbus.h>
48222457Sattilio#include <dev/iicbus/iiconf.h>
49222457Sattilio
50222457Sattilio#include <dev/ofw/openfirm.h>
51222457Sattilio#include <dev/ofw/ofw_bus.h>
52222526Sattilio#include <powerpc/powermac/powermac_thermal.h>
53222457Sattilio
54222457Sattilio/* CPU A/B sensors, temp and adc: AD7417. */
55222457Sattilio
56222457Sattilio#define AD7417_TEMP         0x00
57222457Sattilio#define AD7417_CONFIG       0x01
58222457Sattilio#define AD7417_ADC          0x04
59222457Sattilio#define AD7417_CONFIG2      0x05
60222457Sattilio#define AD7417_CONFMASK     0xe0
61222457Sattilio
62222457Sattiliouint8_t adc741x_config;
63222457Sattilio
64222457Sattiliostruct ad7417_sensor {
65222526Sattilio	struct	pmac_therm therm;
66222526Sattilio	device_t dev;
67222457Sattilio	int     id;
68222457Sattilio	enum {
69222457Sattilio		ADC7417_TEMP_SENSOR,
70222457Sattilio		ADC7417_ADC_SENSOR
71222457Sattilio	} type;
72222457Sattilio};
73222457Sattilio
74222860Sandreaststruct write_data {
75222860Sandreast	uint8_t reg;
76222860Sandreast	uint8_t val;
77222860Sandreast};
78222860Sandreast
79222860Sandreaststruct read_data {
80222860Sandreast	uint8_t reg;
81222860Sandreast	uint16_t val;
82222860Sandreast};
83222860Sandreast
84222457Sattilio/* Regular bus attachment functions */
85222457Sattiliostatic int ad7417_probe(device_t);
86222457Sattiliostatic int ad7417_attach(device_t);
87222457Sattilio
88222457Sattilio/* Utility functions */
89222457Sattiliostatic int ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS);
90222457Sattiliostatic int ad7417_write(device_t dev, uint32_t addr, uint8_t reg,
91222457Sattilio			uint8_t *buf, int len);
92222457Sattiliostatic int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg,
93222457Sattilio			 uint8_t *data);
94222457Sattiliostatic int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg,
95222457Sattilio			 uint16_t *data);
96222860Sandreaststatic int ad7417_write_read(device_t dev, uint32_t addr,
97222860Sandreast			     struct write_data out, struct read_data *in);
98222526Sattiliostatic int ad7417_diode_read(struct ad7417_sensor *sens);
99222526Sattiliostatic int ad7417_adc_read(struct ad7417_sensor *sens);
100222526Sattiliostatic int ad7417_sensor_read(struct ad7417_sensor *sens);
101222457Sattilio
102222457Sattiliostruct ad7417_softc {
103222457Sattilio	device_t		sc_dev;
104222457Sattilio	uint32_t                sc_addr;
105222457Sattilio	struct ad7417_sensor    *sc_sensors;
106222457Sattilio	int                     sc_nsensors;
107239397Sandreast	int                     init_done;
108222457Sattilio};
109222457Sattiliostatic device_method_t  ad7417_methods[] = {
110222457Sattilio	/* Device interface */
111222457Sattilio	DEVMETHOD(device_probe,		ad7417_probe),
112222457Sattilio	DEVMETHOD(device_attach,	ad7417_attach),
113222457Sattilio	{ 0, 0 },
114222457Sattilio};
115222457Sattilio
116222457Sattiliostatic driver_t ad7417_driver = {
117222457Sattilio	"ad7417",
118222457Sattilio	ad7417_methods,
119222457Sattilio	sizeof(struct ad7417_softc)
120222457Sattilio};
121222457Sattilio
122222457Sattiliostatic devclass_t ad7417_devclass;
123222457Sattilio
124222457SattilioDRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0);
125227293Sedstatic MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417");
126222457Sattilio
127222457Sattilio
128222457Sattiliostatic int
129222457Sattilioad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len)
130222457Sattilio{
131222457Sattilio	unsigned char buf[4];
132222860Sandreast	int try = 0;
133222860Sandreast
134222457Sattilio	struct iic_msg msg[] = {
135222457Sattilio		{ addr, IIC_M_WR, 0, buf }
136222457Sattilio	};
137222457Sattilio
138222457Sattilio	msg[0].len = len + 1;
139222457Sattilio	buf[0] = reg;
140222457Sattilio	memcpy(buf + 1, buff, len);
141222457Sattilio
142222860Sandreast	for (;;)
143222860Sandreast	{
144222860Sandreast		if (iicbus_transfer(dev, msg, 1) == 0)
145222860Sandreast			return (0);
146222860Sandreast
147222860Sandreast		if (++try > 5) {
148222860Sandreast			device_printf(dev, "iicbus write failed\n");
149222860Sandreast			return (-1);
150222860Sandreast		}
151222860Sandreast		pause("ad7417_write", hz);
152222457Sattilio	}
153222457Sattilio}
154222457Sattilio
155222457Sattiliostatic int
156222457Sattilioad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data)
157222457Sattilio{
158222457Sattilio	uint8_t buf[4];
159222860Sandreast	int err, try = 0;
160222457Sattilio
161222457Sattilio	struct iic_msg msg[2] = {
162222457Sattilio	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
163222457Sattilio	    { addr, IIC_M_RD, 1, buf },
164222457Sattilio	};
165222457Sattilio
166222860Sandreast	for (;;)
167222860Sandreast	{
168222860Sandreast		err = iicbus_transfer(dev, msg, 2);
169222860Sandreast		if (err != 0)
170222860Sandreast			goto retry;
171222860Sandreast
172222860Sandreast		*data = *((uint8_t*)buf);
173222860Sandreast		return (0);
174222860Sandreast	retry:
175222860Sandreast		if (++try > 5) {
176222860Sandreast			device_printf(dev, "iicbus read failed\n");
177222860Sandreast			return (-1);
178222860Sandreast		}
179222860Sandreast		pause("ad7417_read_1", hz);
180222457Sattilio	}
181222457Sattilio}
182222457Sattilio
183222457Sattiliostatic int
184222457Sattilioad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
185222457Sattilio{
186222457Sattilio	uint8_t buf[4];
187222860Sandreast	int err, try = 0;
188222457Sattilio
189222457Sattilio	struct iic_msg msg[2] = {
190222457Sattilio	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
191222457Sattilio	    { addr, IIC_M_RD, 2, buf },
192222457Sattilio	};
193222457Sattilio
194222860Sandreast	for (;;)
195222860Sandreast	{
196222860Sandreast		err = iicbus_transfer(dev, msg, 2);
197222860Sandreast		if (err != 0)
198222860Sandreast			goto retry;
199222860Sandreast
200222860Sandreast		*data = *((uint16_t*)buf);
201222860Sandreast		return (0);
202222860Sandreast	retry:
203222860Sandreast		if (++try > 5) {
204222860Sandreast			device_printf(dev, "iicbus read failed\n");
205222860Sandreast			return (-1);
206222860Sandreast		}
207222860Sandreast		pause("ad7417_read_2", hz);
208222457Sattilio	}
209222860Sandreast}
210222457Sattilio
211222860Sandreaststatic int
212222860Sandreastad7417_write_read(device_t dev, uint32_t addr, struct write_data out,
213222860Sandreast		  struct read_data *in)
214222860Sandreast{
215222860Sandreast	uint8_t buf[4];
216222860Sandreast	int err, try = 0;
217222457Sattilio
218222860Sandreast	/* Do a combined write/read. */
219222860Sandreast	struct iic_msg msg[3] = {
220222860Sandreast	    { addr, IIC_M_WR, 2, buf },
221222860Sandreast	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg },
222222860Sandreast	    { addr, IIC_M_RD, 2, buf },
223222860Sandreast	};
224222860Sandreast
225222860Sandreast	/* Prepare the write msg. */
226222860Sandreast	buf[0] = out.reg;
227222860Sandreast	buf[1] = out.val & 0xff;
228222860Sandreast
229222860Sandreast	for (;;)
230222860Sandreast	{
231222860Sandreast		err = iicbus_transfer(dev, msg, 3);
232222860Sandreast		if (err != 0)
233222860Sandreast			goto retry;
234222860Sandreast
235222860Sandreast		in->val = *((uint16_t*)buf);
236222860Sandreast		return (0);
237222860Sandreast	retry:
238222860Sandreast		if (++try > 5) {
239222860Sandreast			device_printf(dev, "iicbus write/read failed\n");
240222860Sandreast			return (-1);
241222860Sandreast		}
242222860Sandreast		pause("ad7417_write_read", hz);
243222860Sandreast	}
244222457Sattilio}
245222457Sattilio
246222457Sattiliostatic int
247222457Sattilioad7417_init_adc(device_t dev, uint32_t addr)
248222457Sattilio{
249222457Sattilio	uint8_t buf;
250222860Sandreast	int err;
251239397Sandreast	struct ad7417_softc *sc;
252222457Sattilio
253239397Sandreast	sc = device_get_softc(dev);
254239397Sandreast
255222457Sattilio	adc741x_config = 0;
256222457Sattilio	/* Clear Config2 */
257222457Sattilio	buf = 0;
258222457Sattilio
259222860Sandreast	err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1);
260222860Sandreast
261222457Sattilio	 /* Read & cache Config1 */
262222457Sattilio	buf = 0;
263222860Sandreast	err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1);
264222860Sandreast	err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf);
265222457Sattilio	adc741x_config = (uint8_t)buf;
266222457Sattilio
267222457Sattilio	/* Disable shutdown mode */
268222457Sattilio	adc741x_config &= 0xfe;
269222457Sattilio	buf = adc741x_config;
270222860Sandreast	err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1);
271222860Sandreast	if (err < 0)
272222860Sandreast		return (-1);
273222457Sattilio
274239397Sandreast	sc->init_done = 1;
275239397Sandreast
276222457Sattilio	return (0);
277222457Sattilio
278222457Sattilio}
279222457Sattiliostatic int
280222457Sattilioad7417_probe(device_t dev)
281222457Sattilio{
282222457Sattilio	const char  *name, *compatible;
283222457Sattilio	struct ad7417_softc *sc;
284222457Sattilio
285222457Sattilio	name = ofw_bus_get_name(dev);
286222457Sattilio	compatible = ofw_bus_get_compat(dev);
287222457Sattilio
288222457Sattilio	if (!name)
289222457Sattilio		return (ENXIO);
290222457Sattilio
291222457Sattilio	if (strcmp(name, "supply-monitor") != 0 ||
292222457Sattilio	    strcmp(compatible, "ad7417") != 0)
293222457Sattilio		return (ENXIO);
294222457Sattilio
295222457Sattilio	sc = device_get_softc(dev);
296222457Sattilio	sc->sc_dev = dev;
297222457Sattilio	sc->sc_addr = iicbus_get_addr(dev);
298222457Sattilio
299222457Sattilio	device_set_desc(dev, "Supply-Monitor AD7417");
300222457Sattilio
301222457Sattilio	return (0);
302222457Sattilio}
303222457Sattilio
304222457Sattilio/*
305222457Sattilio * This function returns the number of sensors. If we call it the second time
306222457Sattilio * and we have allocated memory for sc->sc_sensors, we fill in the properties.
307222457Sattilio */
308222457Sattiliostatic int
309222457Sattilioad7417_fill_sensor_prop(device_t dev)
310222457Sattilio{
311222457Sattilio	phandle_t child;
312222457Sattilio	struct ad7417_softc *sc;
313222457Sattilio	u_int id[10];
314222457Sattilio	char location[96];
315222457Sattilio	char type[32];
316222457Sattilio	int i = 0, j, len = 0, prop_len, prev_len = 0;
317222457Sattilio
318222457Sattilio	sc = device_get_softc(dev);
319222457Sattilio
320222457Sattilio	child = ofw_bus_get_node(dev);
321222457Sattilio
322222457Sattilio	/* Fill the sensor location property. */
323222457Sattilio	prop_len = OF_getprop(child, "hwsensor-location", location,
324222457Sattilio			      sizeof(location));
325222457Sattilio	while (len < prop_len) {
326222457Sattilio		if (sc->sc_sensors != NULL)
327222526Sattilio			strcpy(sc->sc_sensors[i].therm.name, location + len);
328222457Sattilio		prev_len = strlen(location + len) + 1;
329222457Sattilio		len += prev_len;
330222457Sattilio		i++;
331222457Sattilio	}
332222457Sattilio	if (sc->sc_sensors == NULL)
333222457Sattilio		return (i);
334222457Sattilio
335222526Sattilio	/* Fill the sensor type property. */
336222457Sattilio	len = 0;
337222457Sattilio	i = 0;
338222457Sattilio	prev_len = 0;
339222457Sattilio	prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type));
340222457Sattilio	while (len < prop_len) {
341222457Sattilio		if (strcmp(type + len, "temperature") == 0)
342222457Sattilio			sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR;
343222457Sattilio		else
344222457Sattilio			sc->sc_sensors[i].type = ADC7417_ADC_SENSOR;
345222457Sattilio		prev_len = strlen(type + len) + 1;
346222457Sattilio		len += prev_len;
347222457Sattilio		i++;
348222457Sattilio	}
349222457Sattilio
350222457Sattilio	/* Fill the sensor id property. Taken from OF. */
351222457Sattilio	prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id));
352222457Sattilio	for (j = 0; j < i; j++)
353222457Sattilio		sc->sc_sensors[j].id = id[j];
354222457Sattilio
355222526Sattilio	/* Fill the sensor zone property. Taken from OF. */
356222526Sattilio	prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
357222526Sattilio	for (j = 0; j < i; j++)
358222526Sattilio		sc->sc_sensors[j].therm.zone = id[j];
359222526Sattilio
360222526Sattilio	/* Finish setting up sensor properties */
361222526Sattilio	for (j = 0; j < i; j++) {
362222526Sattilio		sc->sc_sensors[j].dev = dev;
363222526Sattilio
364222526Sattilio		/* HACK: Apple wired a random diode to the ADC line */
365222526Sattilio		if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP")
366222526Sattilio		    != NULL) {
367222526Sattilio			sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR;
368222526Sattilio			sc->sc_sensors[j].therm.read =
369222526Sattilio			    (int (*)(struct pmac_therm *))(ad7417_diode_read);
370222526Sattilio		} else {
371222526Sattilio			sc->sc_sensors[j].therm.read =
372222526Sattilio			    (int (*)(struct pmac_therm *))(ad7417_sensor_read);
373222526Sattilio		}
374222526Sattilio
375222526Sattilio		if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR)
376222526Sattilio			continue;
377222526Sattilio
378222526Sattilio		/* Make up some ranges */
379222860Sandreast		sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K;
380222860Sandreast		sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K;
381222526Sattilio
382222526Sattilio		pmac_thermal_sensor_register(&sc->sc_sensors[j].therm);
383222526Sattilio	}
384222526Sattilio
385222457Sattilio	return (i);
386222457Sattilio}
387222457Sattilio
388222457Sattiliostatic int
389222457Sattilioad7417_attach(device_t dev)
390222457Sattilio{
391222457Sattilio	struct ad7417_softc *sc;
392222457Sattilio	struct sysctl_oid *oid, *sensroot_oid;
393222457Sattilio	struct sysctl_ctx_list *ctx;
394222457Sattilio	char sysctl_name[32];
395222457Sattilio	int i, j;
396222457Sattilio	const char *unit;
397222457Sattilio	const char *desc;
398222457Sattilio
399222457Sattilio	sc = device_get_softc(dev);
400222457Sattilio
401222457Sattilio	sc->sc_nsensors = 0;
402222457Sattilio
403222457Sattilio	/* Count the actual number of sensors. */
404222457Sattilio	sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
405222457Sattilio
406222457Sattilio	device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors);
407222457Sattilio
408222457Sattilio	if (sc->sc_nsensors == 0)
409222457Sattilio		device_printf(dev, "WARNING: No AD7417 sensors detected!\n");
410222457Sattilio
411222457Sattilio	sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor),
412222457Sattilio				 M_AD7417, M_WAITOK | M_ZERO);
413222457Sattilio
414222457Sattilio	ctx = device_get_sysctl_ctx(dev);
415222457Sattilio	sensroot_oid = SYSCTL_ADD_NODE(ctx,
416222457Sattilio	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor",
417222457Sattilio	    CTLFLAG_RD, 0, "AD7417 Sensor Information");
418222457Sattilio
419222457Sattilio	/* Now we can fill the properties into the allocated struct. */
420222457Sattilio	sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
421222457Sattilio
422222457Sattilio	/* Add sysctls for the sensors. */
423222457Sattilio	for (i = 0; i < sc->sc_nsensors; i++) {
424222526Sattilio		for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
425222526Sattilio			sysctl_name[j] =
426222526Sattilio			    tolower(sc->sc_sensors[i].therm.name[j]);
427222457Sattilio			if (isspace(sysctl_name[j]))
428222457Sattilio				sysctl_name[j] = '_';
429222457Sattilio		}
430222457Sattilio		sysctl_name[j] = 0;
431222457Sattilio
432222457Sattilio		oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid),
433222457Sattilio				      OID_AUTO,
434222457Sattilio				      sysctl_name, CTLFLAG_RD, 0,
435222457Sattilio				      "Sensor Information");
436222457Sattilio
437222457Sattilio		if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) {
438222457Sattilio			unit = "temp";
439239397Sandreast			desc = "sensor unit (C)";
440222457Sattilio		} else {
441222457Sattilio			unit = "volt";
442239397Sandreast			desc = "sensor unit (mV)";
443222457Sattilio		}
444222457Sattilio		/* I use i to pass the sensor id. */
445222457Sattilio		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
446222457Sattilio				unit, CTLTYPE_INT | CTLFLAG_RD, dev,
447222457Sattilio				i, ad7417_sensor_sysctl,
448222457Sattilio				sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ?
449222457Sattilio				"IK" : "I", desc);
450222457Sattilio	}
451222457Sattilio	/* Dump sensor location, ID & type. */
452222457Sattilio	if (bootverbose) {
453222457Sattilio		device_printf(dev, "Sensors\n");
454222457Sattilio		for (i = 0; i < sc->sc_nsensors; i++) {
455222457Sattilio			device_printf(dev, "Location: %s ID: %d type: %d\n",
456222526Sattilio				      sc->sc_sensors[i].therm.name,
457222457Sattilio				      sc->sc_sensors[i].id,
458222457Sattilio				      sc->sc_sensors[i].type);
459222457Sattilio		}
460222457Sattilio	}
461222457Sattilio
462222457Sattilio	return (0);
463222457Sattilio}
464222457Sattilio
465222457Sattiliostatic int
466222457Sattilioad7417_get_temp(device_t dev, uint32_t addr, int *temp)
467222457Sattilio{
468222457Sattilio	uint16_t buf[2];
469222457Sattilio	uint16_t read;
470222860Sandreast	int err;
471222457Sattilio
472222860Sandreast	err = ad7417_read_2(dev, addr, AD7417_TEMP, buf);
473222860Sandreast
474222860Sandreast	if (err < 0)
475222860Sandreast		return (-1);
476222860Sandreast
477222457Sattilio	read = *((int16_t*)buf);
478222457Sattilio
479222457Sattilio	/* The ADC is 10 bit, the resolution is 0.25 C.
480222457Sattilio	   The temperature is in tenth kelvin.
481222457Sattilio	*/
482222457Sattilio	*temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10;
483222457Sattilio	return (0);
484222457Sattilio}
485222457Sattilio
486222457Sattiliostatic int
487222457Sattilioad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value,
488222457Sattilio	       uint8_t chan)
489222457Sattilio{
490222860Sandreast	uint8_t tmp;
491222860Sandreast	int err;
492222860Sandreast	struct write_data config;
493222860Sandreast	struct read_data data;
494222457Sattilio
495222457Sattilio	tmp = chan << 5;
496222860Sandreast	config.reg = AD7417_CONFIG;
497222860Sandreast	data.reg = AD7417_ADC;
498222860Sandreast	data.val = 0;
499222457Sattilio
500222860Sandreast	err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val);
501222457Sattilio
502222860Sandreast	config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK);
503222457Sattilio
504222860Sandreast	err = ad7417_write_read(dev, addr, config, &data);
505222860Sandreast	if (err < 0)
506222860Sandreast		return (-1);
507222457Sattilio
508222860Sandreast	*value = ((uint32_t)data.val) >> 6;
509222457Sattilio
510222457Sattilio	return (0);
511222457Sattilio}
512222457Sattilio
513222457Sattiliostatic int
514222526Sattilioad7417_diode_read(struct ad7417_sensor *sens)
515222457Sattilio{
516222526Sattilio	static int eeprom_read = 0;
517222526Sattilio	static cell_t eeprom[2][40];
518222526Sattilio	phandle_t eeprom_node;
519222526Sattilio	int rawval, diode_slope, diode_offset;
520222526Sattilio	int temp;
521222526Sattilio
522222526Sattilio	if (!eeprom_read) {
523222526Sattilio		eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0");
524222526Sattilio		OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0]));
525222526Sattilio		eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2");
526222526Sattilio		OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1]));
527222526Sattilio		eeprom_read = 1;
528222526Sattilio	}
529222526Sattilio
530222526Sattilio	rawval = ad7417_adc_read(sens);
531222860Sandreast	if (rawval < 0)
532222860Sandreast		return (-1);
533222860Sandreast
534222526Sattilio	if (strstr(sens->therm.name, "CPU B") != NULL) {
535222526Sattilio		diode_slope = eeprom[1][0x11] >> 16;
536222526Sattilio		diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12;
537222526Sattilio	} else {
538222526Sattilio		diode_slope = eeprom[0][0x11] >> 16;
539222526Sattilio		diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12;
540222526Sattilio	}
541222526Sattilio
542222526Sattilio	temp = (rawval*diode_slope + diode_offset) >> 2;
543222526Sattilio	temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16);
544222526Sattilio
545222860Sandreast	return (temp + ZERO_C_TO_K);
546222526Sattilio}
547222526Sattilio
548222526Sattiliostatic int
549222526Sattilioad7417_adc_read(struct ad7417_sensor *sens)
550222526Sattilio{
551222457Sattilio	struct ad7417_softc *sc;
552222526Sattilio	uint8_t chan;
553222526Sattilio	int temp;
554222457Sattilio
555222526Sattilio	sc = device_get_softc(sens->dev);
556222457Sattilio
557222526Sattilio	switch (sens->id) {
558222526Sattilio	case 11:
559222526Sattilio	case 16:
560222526Sattilio		chan = 1;
561222526Sattilio		break;
562222526Sattilio	case 12:
563222526Sattilio	case 17:
564222526Sattilio		chan = 2;
565222526Sattilio		break;
566222526Sattilio	case 13:
567222526Sattilio	case 18:
568222526Sattilio		chan = 3;
569222526Sattilio		break;
570222526Sattilio	case 14:
571222526Sattilio	case 19:
572222526Sattilio		chan = 4;
573222526Sattilio		break;
574222526Sattilio	default:
575222526Sattilio		chan = 1;
576222526Sattilio	}
577222526Sattilio
578222860Sandreast	if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0)
579222860Sandreast		return (-1);
580222526Sattilio
581222526Sattilio	return (temp);
582222526Sattilio}
583222526Sattilio
584222526Sattilio
585222526Sattiliostatic int
586222526Sattilioad7417_sensor_read(struct ad7417_sensor *sens)
587222526Sattilio{
588222526Sattilio	struct ad7417_softc *sc;
589222526Sattilio	int temp;
590222526Sattilio
591222526Sattilio	sc = device_get_softc(sens->dev);
592222526Sattilio
593239397Sandreast	/* Init the ADC if not already done.*/
594239397Sandreast	if (!sc->init_done)
595239397Sandreast		if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0)
596239397Sandreast			return (-1);
597222457Sattilio
598222457Sattilio	if (sens->type == ADC7417_TEMP_SENSOR) {
599222860Sandreast		if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0)
600222860Sandreast			return (-1);
601222860Sandreast		temp += ZERO_C_TO_K;
602222457Sattilio	} else {
603222526Sattilio		temp = ad7417_adc_read(sens);
604222457Sattilio	}
605222526Sattilio	return (temp);
606222457Sattilio}
607222457Sattilio
608222457Sattiliostatic int
609222457Sattilioad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS)
610222457Sattilio{
611222457Sattilio	device_t dev;
612222457Sattilio	struct ad7417_softc *sc;
613222457Sattilio	struct ad7417_sensor *sens;
614222457Sattilio	int value = 0;
615222457Sattilio	int error;
616222457Sattilio
617222457Sattilio	dev = arg1;
618222457Sattilio	sc = device_get_softc(dev);
619222457Sattilio	sens = &sc->sc_sensors[arg2];
620222457Sattilio
621222526Sattilio	value = sens->therm.read(&sens->therm);
622222526Sattilio	if (value < 0)
623222526Sattilio		return (ENXIO);
624222457Sattilio
625222526Sattilio	error = sysctl_handle_int(oidp, &value, 0, req);
626222457Sattilio
627222457Sattilio	return (error);
628222457Sattilio}
629