hwmon: Extend lm63.c to support LM64
[kernel/u-boot.git] / drivers / hwmon / lm63.c
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/LM64 Temperature Sensor
27  * Main difference: LM 64 has -16 Kelvin temperature offset
28  */
29
30 #include <common.h>
31 #include <i2c.h>
32 #include <dtt.h>
33
34 #define DTT_I2C_LM63_ADDR       0x4C    /* National LM63 device */
35
36 #define DTT_READ_TEMP_RMT_MSB   0x01
37 #define DTT_CONFIG              0x03
38 #define DTT_READ_TEMP_RMT_LSB   0x10
39 #define DTT_TACHLIM_LSB         0x48
40 #define DTT_TACHLIM_MSB         0x49
41 #define DTT_FAN_CONFIG          0x4A
42 #define DTT_PWM_FREQ            0x4D
43 #define DTT_PWM_LOOKUP_BASE     0x50
44
45 struct pwm_lookup_entry {
46         u8 temp;
47         u8 pwm;
48 };
49
50 /*
51  * Device code
52  */
53
54 int dtt_read(int sensor, int reg)
55 {
56         int dlen;
57         uchar data[2];
58
59         /*
60          * Calculate sensor address and register.
61          */
62         if (!sensor)
63                 sensor = DTT_I2C_LM63_ADDR;     /* legacy config */
64
65         dlen = 1;
66
67         /*
68          * Now try to read the register.
69          */
70         if (i2c_read(sensor, reg, 1, data, dlen) != 0)
71                 return -1;
72
73         return (int)data[0];
74 }                               /* dtt_read() */
75
76 int dtt_write(int sensor, int reg, int val)
77 {
78         int dlen;
79         uchar data[2];
80
81         /*
82          * Calculate sensor address and register.
83          */
84         if (!sensor)
85                 sensor = DTT_I2C_LM63_ADDR;     /* legacy config */
86
87         dlen = 1;
88         data[0] = (char)(val & 0xff);
89
90         /*
91          * Write value to register.
92          */
93         if (i2c_write(sensor, reg, 1, data, dlen) != 0)
94                 return 1;
95
96         return 0;
97 }                               /* dtt_write() */
98
99 static int is_lm64(int sensor)
100 {
101         return sensor && (sensor != DTT_I2C_LM63_ADDR);
102 }
103
104 static int _dtt_init(int sensor)
105 {
106         int i;
107         int val;
108
109         struct pwm_lookup_entry pwm_lookup[] = CONFIG_DTT_PWM_LOOKUPTABLE;
110
111         /*
112          * Set PWM Frequency to 2.5% resolution
113          */
114         val = 20;
115         if (dtt_write(sensor, DTT_PWM_FREQ, val) != 0)
116                 return 1;
117
118         /*
119          * Set Tachometer Limit
120          */
121         val = CONFIG_DTT_TACH_LIMIT;
122         if (dtt_write(sensor, DTT_TACHLIM_LSB, val & 0xff) != 0)
123                 return 1;
124         if (dtt_write(sensor, DTT_TACHLIM_MSB, (val >> 8) & 0xff) != 0)
125                 return 1;
126
127         /*
128          * Make sure PWM Lookup-Table is writeable
129          */
130         if (dtt_write(sensor, DTT_FAN_CONFIG, 0x20) != 0)
131                 return 1;
132
133         /*
134          * Setup PWM Lookup-Table
135          */
136         for (i = 0; i < sizeof(pwm_lookup) / sizeof(struct pwm_lookup_entry);
137              i++) {
138                 int address = DTT_PWM_LOOKUP_BASE + 2 * i;
139                 val = pwm_lookup[i].temp;
140                 if (is_lm64(sensor))
141                         val -= 16;
142                 if (dtt_write(sensor, address, val) != 0)
143                         return 1;
144                 val = dtt_read(sensor, address);
145                 val = pwm_lookup[i].pwm;
146                 if (dtt_write(sensor, address + 1, val) != 0)
147                         return 1;
148         }
149
150         /*
151          * Enable PWM Lookup-Table, PWM Clock 360 kHz, Tachometer Mode 2
152          */
153         val = 0x02;
154         if (dtt_write(sensor, DTT_FAN_CONFIG, val) != 0)
155                 return 1;
156
157         /*
158          * Enable Tach input
159          */
160         val = dtt_read(sensor, DTT_CONFIG) | 0x04;
161         if (dtt_write(sensor, DTT_CONFIG, val) != 0)
162                 return 1;
163
164         return 0;
165 }
166
167 int dtt_get_temp(int sensor)
168 {
169         s16 temp = (dtt_read(sensor, DTT_READ_TEMP_RMT_MSB) << 8)
170             | (dtt_read(sensor, DTT_READ_TEMP_RMT_LSB));
171
172         if (is_lm64(sensor))
173                 temp += 16 << 8;
174
175         /* Ignore LSB for now, U-Boot only prints natural numbers */
176         return temp >> 8;
177 }
178
179 int dtt_init(void)
180 {
181         int i;
182         unsigned char sensors[] = CONFIG_DTT_SENSORS;
183         const char *const header = "DTT:   ";
184
185         for (i = 0; i < sizeof(sensors); i++) {
186                 if (_dtt_init(sensors[i]) != 0)
187                         printf("%s%d FAILED INIT\n", header, i + 1);
188                 else
189                         printf("%s%d is %i C\n", header, i + 1,
190                                dtt_get_temp(sensors[i]));
191         }
192
193         return 0;
194 }