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$");
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;
107222457Sattilio};
108222457Sattiliostatic device_method_t  ad7417_methods[] = {
109222457Sattilio	/* Device interface */
110222457Sattilio	DEVMETHOD(device_probe,		ad7417_probe),
111222457Sattilio	DEVMETHOD(device_attach,	ad7417_attach),
112222457Sattilio	{ 0, 0 },
113222457Sattilio};
114222457Sattilio
115222457Sattiliostatic driver_t ad7417_driver = {
116222457Sattilio	"ad7417",
117222457Sattilio	ad7417_methods,
118222457Sattilio	sizeof(struct ad7417_softc)
119222457Sattilio};
120222457Sattilio
121222457Sattiliostatic devclass_t ad7417_devclass;
122222457Sattilio
123222457SattilioDRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0);
124249132Smavstatic MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417");
125222457Sattilio
126222457Sattilio
127222457Sattiliostatic int
128222457Sattilioad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len)
129222457Sattilio{
130222457Sattilio	unsigned char buf[4];
131222860Sandreast	int try = 0;
132222860Sandreast
133222457Sattilio	struct iic_msg msg[] = {
134222457Sattilio		{ addr, IIC_M_WR, 0, buf }
135222457Sattilio	};
136222457Sattilio
137222457Sattilio	msg[0].len = len + 1;
138222457Sattilio	buf[0] = reg;
139222457Sattilio	memcpy(buf + 1, buff, len);
140222457Sattilio
141222860Sandreast	for (;;)
142222860Sandreast	{
143222860Sandreast		if (iicbus_transfer(dev, msg, 1) == 0)
144222860Sandreast			return (0);
145222860Sandreast
146222860Sandreast		if (++try > 5) {
147222860Sandreast			device_printf(dev, "iicbus write failed\n");
148222860Sandreast			return (-1);
149222860Sandreast		}
150222860Sandreast		pause("ad7417_write", hz);
151222457Sattilio	}
152222457Sattilio}
153222457Sattilio
154222457Sattiliostatic int
155222457Sattilioad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data)
156222457Sattilio{
157222457Sattilio	uint8_t buf[4];
158222860Sandreast	int err, try = 0;
159222457Sattilio
160222457Sattilio	struct iic_msg msg[2] = {
161222457Sattilio	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
162222457Sattilio	    { addr, IIC_M_RD, 1, buf },
163222457Sattilio	};
164222457Sattilio
165222860Sandreast	for (;;)
166222860Sandreast	{
167222860Sandreast		err = iicbus_transfer(dev, msg, 2);
168222860Sandreast		if (err != 0)
169222860Sandreast			goto retry;
170222860Sandreast
171222860Sandreast		*data = *((uint8_t*)buf);
172222860Sandreast		return (0);
173222860Sandreast	retry:
174222860Sandreast		if (++try > 5) {
175222860Sandreast			device_printf(dev, "iicbus read failed\n");
176222860Sandreast			return (-1);
177222860Sandreast		}
178222860Sandreast		pause("ad7417_read_1", hz);
179222457Sattilio	}
180222457Sattilio}
181222457Sattilio
182222457Sattiliostatic int
183222457Sattilioad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
184222457Sattilio{
185222457Sattilio	uint8_t buf[4];
186222860Sandreast	int err, try = 0;
187222457Sattilio
188222457Sattilio	struct iic_msg msg[2] = {
189222457Sattilio	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
190222457Sattilio	    { addr, IIC_M_RD, 2, buf },
191222457Sattilio	};
192222457Sattilio
193222860Sandreast	for (;;)
194222860Sandreast	{
195222860Sandreast		err = iicbus_transfer(dev, msg, 2);
196222860Sandreast		if (err != 0)
197222860Sandreast			goto retry;
198222860Sandreast
199222860Sandreast		*data = *((uint16_t*)buf);
200222860Sandreast		return (0);
201222860Sandreast	retry:
202222860Sandreast		if (++try > 5) {
203222860Sandreast			device_printf(dev, "iicbus read failed\n");
204222860Sandreast			return (-1);
205222860Sandreast		}
206222860Sandreast		pause("ad7417_read_2", hz);
207222457Sattilio	}
208222860Sandreast}
209222457Sattilio
210222860Sandreaststatic int
211222860Sandreastad7417_write_read(device_t dev, uint32_t addr, struct write_data out,
212222860Sandreast		  struct read_data *in)
213222860Sandreast{
214222860Sandreast	uint8_t buf[4];
215222860Sandreast	int err, try = 0;
216222457Sattilio
217222860Sandreast	/* Do a combined write/read. */
218222860Sandreast	struct iic_msg msg[3] = {
219222860Sandreast	    { addr, IIC_M_WR, 2, buf },
220222860Sandreast	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg },
221222860Sandreast	    { addr, IIC_M_RD, 2, buf },
222222860Sandreast	};
223222860Sandreast
224222860Sandreast	/* Prepare the write msg. */
225222860Sandreast	buf[0] = out.reg;
226222860Sandreast	buf[1] = out.val & 0xff;
227222860Sandreast
228222860Sandreast	for (;;)
229222860Sandreast	{
230222860Sandreast		err = iicbus_transfer(dev, msg, 3);
231222860Sandreast		if (err != 0)
232222860Sandreast			goto retry;
233222860Sandreast
234222860Sandreast		in->val = *((uint16_t*)buf);
235222860Sandreast		return (0);
236222860Sandreast	retry:
237222860Sandreast		if (++try > 5) {
238222860Sandreast			device_printf(dev, "iicbus write/read failed\n");
239222860Sandreast			return (-1);
240222860Sandreast		}
241222860Sandreast		pause("ad7417_write_read", hz);
242222860Sandreast	}
243222457Sattilio}
244222457Sattilio
245222457Sattiliostatic int
246222457Sattilioad7417_init_adc(device_t dev, uint32_t addr)
247222457Sattilio{
248222457Sattilio	uint8_t buf;
249222860Sandreast	int err;
250222457Sattilio
251222457Sattilio	adc741x_config = 0;
252222457Sattilio	/* Clear Config2 */
253222457Sattilio	buf = 0;
254222457Sattilio
255222860Sandreast	err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1);
256222860Sandreast
257222457Sattilio	 /* Read & cache Config1 */
258222457Sattilio	buf = 0;
259222860Sandreast	err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1);
260222860Sandreast	err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf);
261222457Sattilio	adc741x_config = (uint8_t)buf;
262222457Sattilio
263222457Sattilio	/* Disable shutdown mode */
264222457Sattilio	adc741x_config &= 0xfe;
265222457Sattilio	buf = adc741x_config;
266222860Sandreast	err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1);
267222860Sandreast	if (err < 0)
268222860Sandreast		return (-1);
269222457Sattilio
270222457Sattilio	return (0);
271222457Sattilio
272222457Sattilio}
273222457Sattiliostatic int
274222457Sattilioad7417_probe(device_t dev)
275222457Sattilio{
276222457Sattilio	const char  *name, *compatible;
277222457Sattilio	struct ad7417_softc *sc;
278222457Sattilio
279222457Sattilio	name = ofw_bus_get_name(dev);
280222457Sattilio	compatible = ofw_bus_get_compat(dev);
281222457Sattilio
282222457Sattilio	if (!name)
283222457Sattilio		return (ENXIO);
284222457Sattilio
285222457Sattilio	if (strcmp(name, "supply-monitor") != 0 ||
286222457Sattilio	    strcmp(compatible, "ad7417") != 0)
287222457Sattilio		return (ENXIO);
288222457Sattilio
289222457Sattilio	sc = device_get_softc(dev);
290222457Sattilio	sc->sc_dev = dev;
291222457Sattilio	sc->sc_addr = iicbus_get_addr(dev);
292222457Sattilio
293222457Sattilio	device_set_desc(dev, "Supply-Monitor AD7417");
294222457Sattilio
295222457Sattilio	return (0);
296222457Sattilio}
297222457Sattilio
298222457Sattilio/*
299222457Sattilio * This function returns the number of sensors. If we call it the second time
300222457Sattilio * and we have allocated memory for sc->sc_sensors, we fill in the properties.
301222457Sattilio */
302222457Sattiliostatic int
303222457Sattilioad7417_fill_sensor_prop(device_t dev)
304222457Sattilio{
305222457Sattilio	phandle_t child;
306222457Sattilio	struct ad7417_softc *sc;
307222457Sattilio	u_int id[10];
308222457Sattilio	char location[96];
309222457Sattilio	char type[32];
310222457Sattilio	int i = 0, j, len = 0, prop_len, prev_len = 0;
311222457Sattilio
312222457Sattilio	sc = device_get_softc(dev);
313222457Sattilio
314222457Sattilio	child = ofw_bus_get_node(dev);
315222457Sattilio
316222457Sattilio	/* Fill the sensor location property. */
317222457Sattilio	prop_len = OF_getprop(child, "hwsensor-location", location,
318222457Sattilio			      sizeof(location));
319222457Sattilio	while (len < prop_len) {
320222457Sattilio		if (sc->sc_sensors != NULL)
321222526Sattilio			strcpy(sc->sc_sensors[i].therm.name, location + len);
322222457Sattilio		prev_len = strlen(location + len) + 1;
323222457Sattilio		len += prev_len;
324222457Sattilio		i++;
325222457Sattilio	}
326222457Sattilio	if (sc->sc_sensors == NULL)
327222457Sattilio		return (i);
328222457Sattilio
329222526Sattilio	/* Fill the sensor type property. */
330222457Sattilio	len = 0;
331222457Sattilio	i = 0;
332222457Sattilio	prev_len = 0;
333222457Sattilio	prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type));
334222457Sattilio	while (len < prop_len) {
335222457Sattilio		if (strcmp(type + len, "temperature") == 0)
336222457Sattilio			sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR;
337222457Sattilio		else
338222457Sattilio			sc->sc_sensors[i].type = ADC7417_ADC_SENSOR;
339222457Sattilio		prev_len = strlen(type + len) + 1;
340222457Sattilio		len += prev_len;
341222457Sattilio		i++;
342222457Sattilio	}
343222457Sattilio
344222457Sattilio	/* Fill the sensor id property. Taken from OF. */
345222457Sattilio	prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id));
346222457Sattilio	for (j = 0; j < i; j++)
347222457Sattilio		sc->sc_sensors[j].id = id[j];
348222457Sattilio
349222526Sattilio	/* Fill the sensor zone property. Taken from OF. */
350222526Sattilio	prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
351222526Sattilio	for (j = 0; j < i; j++)
352222526Sattilio		sc->sc_sensors[j].therm.zone = id[j];
353222526Sattilio
354222526Sattilio	/* Finish setting up sensor properties */
355222526Sattilio	for (j = 0; j < i; j++) {
356222526Sattilio		sc->sc_sensors[j].dev = dev;
357222526Sattilio
358222526Sattilio		/* HACK: Apple wired a random diode to the ADC line */
359222526Sattilio		if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP")
360222526Sattilio		    != NULL) {
361222526Sattilio			sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR;
362222526Sattilio			sc->sc_sensors[j].therm.read =
363222526Sattilio			    (int (*)(struct pmac_therm *))(ad7417_diode_read);
364222526Sattilio		} else {
365222526Sattilio			sc->sc_sensors[j].therm.read =
366222526Sattilio			    (int (*)(struct pmac_therm *))(ad7417_sensor_read);
367222526Sattilio		}
368222526Sattilio
369222526Sattilio		if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR)
370222526Sattilio			continue;
371222526Sattilio
372222526Sattilio		/* Make up some ranges */
373222860Sandreast		sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K;
374222860Sandreast		sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K;
375222526Sattilio
376222526Sattilio		pmac_thermal_sensor_register(&sc->sc_sensors[j].therm);
377222526Sattilio	}
378222526Sattilio
379222457Sattilio	return (i);
380222457Sattilio}
381222457Sattilio
382222457Sattiliostatic int
383222457Sattilioad7417_attach(device_t dev)
384222457Sattilio{
385222457Sattilio	struct ad7417_softc *sc;
386222457Sattilio	struct sysctl_oid *oid, *sensroot_oid;
387222457Sattilio	struct sysctl_ctx_list *ctx;
388222457Sattilio	char sysctl_name[32];
389222457Sattilio	int i, j;
390222457Sattilio	const char *unit;
391222457Sattilio	const char *desc;
392222457Sattilio
393222457Sattilio	sc = device_get_softc(dev);
394222457Sattilio
395222457Sattilio	sc->sc_nsensors = 0;
396222457Sattilio
397222457Sattilio	/* Count the actual number of sensors. */
398222457Sattilio	sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
399222457Sattilio
400222457Sattilio	device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors);
401222457Sattilio
402222457Sattilio	if (sc->sc_nsensors == 0)
403222457Sattilio		device_printf(dev, "WARNING: No AD7417 sensors detected!\n");
404222457Sattilio
405222457Sattilio	sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor),
406222457Sattilio				 M_AD7417, M_WAITOK | M_ZERO);
407222457Sattilio
408222457Sattilio	ctx = device_get_sysctl_ctx(dev);
409222457Sattilio	sensroot_oid = SYSCTL_ADD_NODE(ctx,
410222457Sattilio	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor",
411222457Sattilio	    CTLFLAG_RD, 0, "AD7417 Sensor Information");
412222457Sattilio
413222457Sattilio	/* Now we can fill the properties into the allocated struct. */
414222457Sattilio	sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
415222457Sattilio
416222457Sattilio	/* Add sysctls for the sensors. */
417222457Sattilio	for (i = 0; i < sc->sc_nsensors; i++) {
418222526Sattilio		for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
419222526Sattilio			sysctl_name[j] =
420222526Sattilio			    tolower(sc->sc_sensors[i].therm.name[j]);
421222457Sattilio			if (isspace(sysctl_name[j]))
422222457Sattilio				sysctl_name[j] = '_';
423222457Sattilio		}
424222457Sattilio		sysctl_name[j] = 0;
425222457Sattilio
426222457Sattilio		oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid),
427222457Sattilio				      OID_AUTO,
428222457Sattilio				      sysctl_name, CTLFLAG_RD, 0,
429222457Sattilio				      "Sensor Information");
430222457Sattilio
431222457Sattilio		if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) {
432222457Sattilio			unit = "temp";
433222457Sattilio			desc = "Sensor temp in C";
434222457Sattilio		} else {
435222457Sattilio			unit = "volt";
436222457Sattilio			desc = "Sensor Volt in V";
437222457Sattilio		}
438222457Sattilio		/* I use i to pass the sensor id. */
439222457Sattilio		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
440222457Sattilio				unit, CTLTYPE_INT | CTLFLAG_RD, dev,
441222457Sattilio				i, ad7417_sensor_sysctl,
442222457Sattilio				sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ?
443222457Sattilio				"IK" : "I", desc);
444222457Sattilio	}
445222457Sattilio	/* Dump sensor location, ID & type. */
446222457Sattilio	if (bootverbose) {
447222457Sattilio		device_printf(dev, "Sensors\n");
448222457Sattilio		for (i = 0; i < sc->sc_nsensors; i++) {
449222457Sattilio			device_printf(dev, "Location: %s ID: %d type: %d\n",
450222526Sattilio				      sc->sc_sensors[i].therm.name,
451222457Sattilio				      sc->sc_sensors[i].id,
452222457Sattilio				      sc->sc_sensors[i].type);
453222457Sattilio		}
454222457Sattilio	}
455222457Sattilio
456222457Sattilio	return (0);
457222457Sattilio}
458222457Sattilio
459222457Sattiliostatic int
460222457Sattilioad7417_get_temp(device_t dev, uint32_t addr, int *temp)
461222457Sattilio{
462222457Sattilio	uint16_t buf[2];
463222457Sattilio	uint16_t read;
464222860Sandreast	int err;
465222457Sattilio
466222860Sandreast	err = ad7417_read_2(dev, addr, AD7417_TEMP, buf);
467222860Sandreast
468222860Sandreast	if (err < 0)
469222860Sandreast		return (-1);
470222860Sandreast
471222457Sattilio	read = *((int16_t*)buf);
472222457Sattilio
473222457Sattilio	/* The ADC is 10 bit, the resolution is 0.25 C.
474222457Sattilio	   The temperature is in tenth kelvin.
475222457Sattilio	*/
476222457Sattilio	*temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10;
477222457Sattilio	return (0);
478222457Sattilio}
479222457Sattilio
480222457Sattiliostatic int
481222457Sattilioad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value,
482222457Sattilio	       uint8_t chan)
483222457Sattilio{
484222860Sandreast	uint8_t tmp;
485222860Sandreast	int err;
486222860Sandreast	struct write_data config;
487222860Sandreast	struct read_data data;
488222457Sattilio
489222457Sattilio	tmp = chan << 5;
490222860Sandreast	config.reg = AD7417_CONFIG;
491222860Sandreast	data.reg = AD7417_ADC;
492222860Sandreast	data.val = 0;
493222457Sattilio
494222860Sandreast	err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val);
495222457Sattilio
496222860Sandreast	config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK);
497222457Sattilio
498222860Sandreast	err = ad7417_write_read(dev, addr, config, &data);
499222860Sandreast	if (err < 0)
500222860Sandreast		return (-1);
501222457Sattilio
502222860Sandreast	*value = ((uint32_t)data.val) >> 6;
503222457Sattilio
504222457Sattilio	return (0);
505222457Sattilio}
506222457Sattilio
507222457Sattiliostatic int
508222526Sattilioad7417_diode_read(struct ad7417_sensor *sens)
509222457Sattilio{
510222526Sattilio	static int eeprom_read = 0;
511222526Sattilio	static cell_t eeprom[2][40];
512222526Sattilio	phandle_t eeprom_node;
513222526Sattilio	int rawval, diode_slope, diode_offset;
514222526Sattilio	int temp;
515222526Sattilio
516222526Sattilio	if (!eeprom_read) {
517222526Sattilio		eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0");
518222526Sattilio		OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0]));
519222526Sattilio		eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2");
520222526Sattilio		OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1]));
521222526Sattilio		eeprom_read = 1;
522222526Sattilio	}
523222526Sattilio
524222526Sattilio	rawval = ad7417_adc_read(sens);
525222860Sandreast	if (rawval < 0)
526222860Sandreast		return (-1);
527222860Sandreast
528222526Sattilio	if (strstr(sens->therm.name, "CPU B") != NULL) {
529222526Sattilio		diode_slope = eeprom[1][0x11] >> 16;
530222526Sattilio		diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12;
531222526Sattilio	} else {
532222526Sattilio		diode_slope = eeprom[0][0x11] >> 16;
533222526Sattilio		diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12;
534222526Sattilio	}
535222526Sattilio
536222526Sattilio	temp = (rawval*diode_slope + diode_offset) >> 2;
537222526Sattilio	temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16);
538222526Sattilio
539222860Sandreast	return (temp + ZERO_C_TO_K);
540222526Sattilio}
541222526Sattilio
542222526Sattiliostatic int
543222526Sattilioad7417_adc_read(struct ad7417_sensor *sens)
544222526Sattilio{
545222457Sattilio	struct ad7417_softc *sc;
546222526Sattilio	uint8_t chan;
547222526Sattilio	int temp;
548222457Sattilio
549222526Sattilio	sc = device_get_softc(sens->dev);
550222457Sattilio
551222526Sattilio	switch (sens->id) {
552222526Sattilio	case 11:
553222526Sattilio	case 16:
554222526Sattilio		chan = 1;
555222526Sattilio		break;
556222526Sattilio	case 12:
557222526Sattilio	case 17:
558222526Sattilio		chan = 2;
559222526Sattilio		break;
560222526Sattilio	case 13:
561222526Sattilio	case 18:
562222526Sattilio		chan = 3;
563222526Sattilio		break;
564222526Sattilio	case 14:
565222526Sattilio	case 19:
566222526Sattilio		chan = 4;
567222526Sattilio		break;
568222526Sattilio	default:
569222526Sattilio		chan = 1;
570222526Sattilio	}
571222526Sattilio
572222860Sandreast	if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0)
573222860Sandreast		return (-1);
574222526Sattilio
575222526Sattilio	return (temp);
576222526Sattilio}
577222526Sattilio
578222526Sattilio
579222526Sattiliostatic int
580222526Sattilioad7417_sensor_read(struct ad7417_sensor *sens)
581222526Sattilio{
582222526Sattilio	struct ad7417_softc *sc;
583222526Sattilio	int temp;
584222526Sattilio
585222526Sattilio	sc = device_get_softc(sens->dev);
586222526Sattilio
587222457Sattilio	/* Init the ADC. */
588222860Sandreast	if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0)
589222860Sandreast		return (-1);
590222457Sattilio
591222457Sattilio	if (sens->type == ADC7417_TEMP_SENSOR) {
592222860Sandreast		if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0)
593222860Sandreast			return (-1);
594222860Sandreast		temp += ZERO_C_TO_K;
595222457Sattilio	} else {
596222526Sattilio		temp = ad7417_adc_read(sens);
597222457Sattilio	}
598222526Sattilio	return (temp);
599222457Sattilio}
600222457Sattilio
601222457Sattiliostatic int
602222457Sattilioad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS)
603222457Sattilio{
604222457Sattilio	device_t dev;
605222457Sattilio	struct ad7417_softc *sc;
606222457Sattilio	struct ad7417_sensor *sens;
607222457Sattilio	int value = 0;
608222457Sattilio	int error;
609222457Sattilio
610222457Sattilio	dev = arg1;
611222457Sattilio	sc = device_get_softc(dev);
612222457Sattilio	sens = &sc->sc_sensors[arg2];
613222457Sattilio
614222526Sattilio	value = sens->therm.read(&sens->therm);
615222526Sattilio	if (value < 0)
616222526Sattilio		return (ENXIO);
617222457Sattilio
618222526Sattilio	error = sysctl_handle_int(oidp, &value, 0, req);
619222457Sattilio
620222457Sattilio	return (error);
621222457Sattilio}
622