1 /*
2  * (C) Copyright 2007-2008
3  * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
4  * based on lm75.c by Bill Hunter
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24 
25 /*
26  * National LM63 Temperature Sensor
27  */
28 
29 #include <common.h>
30 #include <i2c.h>
31 #include <dtt.h>
32 
33 #define DTT_I2C_DEV_CODE 0x4C	/* National LM63 device */
34 
35 #define DTT_READ_TEMP_RMT_MSB	0x01
36 #define DTT_CONFIG		0x03
37 #define DTT_READ_TEMP_RMT_LSB	0x10
38 #define DTT_TACHLIM_LSB		0x48
39 #define DTT_TACHLIM_MSB		0x49
40 #define DTT_FAN_CONFIG		0x4A
41 #define DTT_PWM_FREQ		0x4D
42 #define DTT_PWM_LOOKUP_BASE	0x50
43 
44 struct pwm_lookup_entry {
45 	u8 temp;
46 	u8 pwm;
47 };
48 
49 /*
50  * Device code
51  */
52 
dtt_read(int sensor,int reg)53 int dtt_read(int sensor, int reg)
54 {
55 	int dlen;
56 	uchar data[2];
57 
58 	/*
59 	 * Calculate sensor address and register.
60 	 */
61 	sensor = DTT_I2C_DEV_CODE;	/* address of lm63 is not adjustable */
62 
63 	dlen = 1;
64 
65 	/*
66 	 * Now try to read the register.
67 	 */
68 	if (i2c_read(sensor, reg, 1, data, dlen) != 0)
69 		return -1;
70 
71 	return (int)data[0];
72 }				/* dtt_read() */
73 
dtt_write(int sensor,int reg,int val)74 int dtt_write(int sensor, int reg, int val)
75 {
76 	int dlen;
77 	uchar data[2];
78 
79 	/*
80 	 * Calculate sensor address and register.
81 	 */
82 	sensor = DTT_I2C_DEV_CODE;	/* address of lm63 is not adjustable */
83 
84 	dlen = 1;
85 	data[0] = (char)(val & 0xff);
86 
87 	/*
88 	 * Write value to register.
89 	 */
90 	if (i2c_write(sensor, reg, 1, data, dlen) != 0)
91 		return 1;
92 
93 	return 0;
94 }				/* dtt_write() */
95 
_dtt_init(int sensor)96 static int _dtt_init(int sensor)
97 {
98 	int i;
99 	int val;
100 
101 	struct pwm_lookup_entry pwm_lookup[] = CONFIG_DTT_PWM_LOOKUPTABLE;
102 
103 	/*
104 	 * Set PWM Frequency to 2.5% resolution
105 	 */
106 	val = 20;
107 	if (dtt_write(sensor, DTT_PWM_FREQ, val) != 0)
108 		return 1;
109 
110 	/*
111 	 * Set Tachometer Limit
112 	 */
113 	val = CONFIG_DTT_TACH_LIMIT;
114 	if (dtt_write(sensor, DTT_TACHLIM_LSB, val & 0xff) != 0)
115 		return 1;
116 	if (dtt_write(sensor, DTT_TACHLIM_MSB, (val >> 8) & 0xff) != 0)
117 		return 1;
118 
119 	/*
120 	 * Setup PWM Lookup-Table
121 	 */
122 	for (i = 0; i < sizeof(pwm_lookup) / sizeof(struct pwm_lookup_entry);
123 	     i++) {
124 		int address = DTT_PWM_LOOKUP_BASE + 2 * i;
125 		val = pwm_lookup[i].temp;
126 		if (dtt_write(sensor, address, val) != 0)
127 			return 1;
128 		val = pwm_lookup[i].pwm;
129 		if (dtt_write(sensor, address + 1, val) != 0)
130 			return 1;
131 	}
132 
133 	/*
134 	 * Enable PWM Lookup-Table, PWM Clock 360 kHz, Tachometer Mode 2
135 	 */
136 	val = 0x02;
137 	if (dtt_write(sensor, DTT_FAN_CONFIG, val) != 0)
138 		return 1;
139 
140 	/*
141 	 * Enable Tach input
142 	 */
143 	val = dtt_read(sensor, DTT_CONFIG) | 0x04;
144 	if (dtt_write(sensor, DTT_CONFIG, val) != 0)
145 		return 1;
146 
147 	return 0;
148 }
149 
dtt_get_temp(int sensor)150 int dtt_get_temp(int sensor)
151 {
152 	s16 temp = (dtt_read(sensor, DTT_READ_TEMP_RMT_MSB) << 8)
153 	    | (dtt_read(sensor, DTT_READ_TEMP_RMT_LSB));
154 
155 	/* Ignore LSB for now, U-Boot only prints natural numbers */
156 	return temp >> 8;
157 }
158 
dtt_init(void)159 int dtt_init(void)
160 {
161 	int i;
162 	unsigned char sensors[] = CONFIG_DTT_SENSORS;
163 	const char *const header = "DTT:   ";
164 
165 	for (i = 0; i < sizeof(sensors); i++) {
166 		if (_dtt_init(sensors[i]) != 0)
167 			printf("%s%d FAILED INIT\n", header, i + 1);
168 		else
169 			printf("%s%d is %i C\n", header, i + 1,
170 			       dtt_get_temp(sensors[i]));
171 	}
172 
173 	return 0;
174 }
175