root / hw / tmp105.c @ 60398748
History | View | Annotate | Download (6 kB)
1 | 7e7c5e4c | balrog | /*
|
---|---|---|---|
2 | 7e7c5e4c | balrog | * Texas Instruments TMP105 temperature sensor.
|
3 | 7e7c5e4c | balrog | *
|
4 | 7e7c5e4c | balrog | * Copyright (C) 2008 Nokia Corporation
|
5 | 7e7c5e4c | balrog | * Written by Andrzej Zaborowski <andrew@openedhand.com>
|
6 | 7e7c5e4c | balrog | *
|
7 | 7e7c5e4c | balrog | * This program is free software; you can redistribute it and/or
|
8 | 7e7c5e4c | balrog | * modify it under the terms of the GNU General Public License as
|
9 | 7e7c5e4c | balrog | * published by the Free Software Foundation; either version 2 or
|
10 | 7e7c5e4c | balrog | * (at your option) version 3 of the License.
|
11 | 7e7c5e4c | balrog | *
|
12 | 7e7c5e4c | balrog | * This program is distributed in the hope that it will be useful,
|
13 | 7e7c5e4c | balrog | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | 7e7c5e4c | balrog | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 | 7e7c5e4c | balrog | * GNU General Public License for more details.
|
16 | 7e7c5e4c | balrog | *
|
17 | fad6cb1a | aurel32 | * You should have received a copy of the GNU General Public License along
|
18 | 8167ee88 | Blue Swirl | * with this program; if not, see <http://www.gnu.org/licenses/>.
|
19 | 7e7c5e4c | balrog | */
|
20 | 7e7c5e4c | balrog | |
21 | 7e7c5e4c | balrog | #include "hw.h" |
22 | 7e7c5e4c | balrog | #include "i2c.h" |
23 | 7e7c5e4c | balrog | |
24 | bc24a225 | Paul Brook | typedef struct { |
25 | 7e7c5e4c | balrog | i2c_slave i2c; |
26 | 6f3a7798 | Juan Quintela | uint8_t len; |
27 | 7e7c5e4c | balrog | uint8_t buf[2];
|
28 | 7e7c5e4c | balrog | qemu_irq pin; |
29 | 7e7c5e4c | balrog | |
30 | 7e7c5e4c | balrog | uint8_t pointer; |
31 | 7e7c5e4c | balrog | uint8_t config; |
32 | 7e7c5e4c | balrog | int16_t temperature; |
33 | 7e7c5e4c | balrog | int16_t limit[2];
|
34 | 7e7c5e4c | balrog | int faults;
|
35 | 6f3a7798 | Juan Quintela | uint8_t alarm; |
36 | bc24a225 | Paul Brook | } TMP105State; |
37 | 7e7c5e4c | balrog | |
38 | bc24a225 | Paul Brook | static void tmp105_interrupt_update(TMP105State *s) |
39 | 7e7c5e4c | balrog | { |
40 | 7e7c5e4c | balrog | qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */ |
41 | 7e7c5e4c | balrog | } |
42 | 7e7c5e4c | balrog | |
43 | bc24a225 | Paul Brook | static void tmp105_alarm_update(TMP105State *s) |
44 | 7e7c5e4c | balrog | { |
45 | 7e7c5e4c | balrog | if ((s->config >> 0) & 1) { /* SD */ |
46 | 7e7c5e4c | balrog | if ((s->config >> 7) & 1) /* OS */ |
47 | 7e7c5e4c | balrog | s->config &= ~(1 << 7); /* OS */ |
48 | 7e7c5e4c | balrog | else
|
49 | 7e7c5e4c | balrog | return;
|
50 | 7e7c5e4c | balrog | } |
51 | 7e7c5e4c | balrog | |
52 | 7e7c5e4c | balrog | if ((s->config >> 1) & 1) { /* TM */ |
53 | 7e7c5e4c | balrog | if (s->temperature >= s->limit[1]) |
54 | 7e7c5e4c | balrog | s->alarm = 1;
|
55 | 7e7c5e4c | balrog | else if (s->temperature < s->limit[0]) |
56 | 7e7c5e4c | balrog | s->alarm = 1;
|
57 | 7e7c5e4c | balrog | } else {
|
58 | 7e7c5e4c | balrog | if (s->temperature >= s->limit[1]) |
59 | 7e7c5e4c | balrog | s->alarm = 1;
|
60 | 7e7c5e4c | balrog | else if (s->temperature < s->limit[0]) |
61 | 7e7c5e4c | balrog | s->alarm = 0;
|
62 | 7e7c5e4c | balrog | } |
63 | 7e7c5e4c | balrog | |
64 | 7e7c5e4c | balrog | tmp105_interrupt_update(s); |
65 | 7e7c5e4c | balrog | } |
66 | 7e7c5e4c | balrog | |
67 | 7e7c5e4c | balrog | /* Units are 0.001 centigrades relative to 0 C. */
|
68 | 7e7c5e4c | balrog | void tmp105_set(i2c_slave *i2c, int temp) |
69 | 7e7c5e4c | balrog | { |
70 | bc24a225 | Paul Brook | TMP105State *s = (TMP105State *) i2c; |
71 | 7e7c5e4c | balrog | |
72 | 7e7c5e4c | balrog | if (temp >= 128000 || temp < -128000) { |
73 | 7e7c5e4c | balrog | fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
|
74 | 7e7c5e4c | balrog | __FUNCTION__, temp / 1000, temp % 1000); |
75 | 7e7c5e4c | balrog | exit(-1);
|
76 | 7e7c5e4c | balrog | } |
77 | 7e7c5e4c | balrog | |
78 | 7e7c5e4c | balrog | s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4; |
79 | 7e7c5e4c | balrog | |
80 | 7e7c5e4c | balrog | tmp105_alarm_update(s); |
81 | 7e7c5e4c | balrog | } |
82 | 7e7c5e4c | balrog | |
83 | 7e7c5e4c | balrog | static const int tmp105_faultq[4] = { 1, 2, 4, 6 }; |
84 | 7e7c5e4c | balrog | |
85 | bc24a225 | Paul Brook | static void tmp105_read(TMP105State *s) |
86 | 7e7c5e4c | balrog | { |
87 | 7e7c5e4c | balrog | s->len = 0;
|
88 | 7e7c5e4c | balrog | |
89 | 7e7c5e4c | balrog | if ((s->config >> 1) & 1) { /* TM */ |
90 | 7e7c5e4c | balrog | s->alarm = 0;
|
91 | 7e7c5e4c | balrog | tmp105_interrupt_update(s); |
92 | 7e7c5e4c | balrog | } |
93 | 7e7c5e4c | balrog | |
94 | 7e7c5e4c | balrog | switch (s->pointer & 3) { |
95 | 7e7c5e4c | balrog | case 0: /* Temperature */ |
96 | 7e7c5e4c | balrog | s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
|
97 | 7e7c5e4c | balrog | s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
|
98 | 7e7c5e4c | balrog | (0xf0 << ((~s->config >> 5) & 3)); /* R */ |
99 | 7e7c5e4c | balrog | break;
|
100 | 7e7c5e4c | balrog | |
101 | 7e7c5e4c | balrog | case 1: /* Configuration */ |
102 | 7e7c5e4c | balrog | s->buf[s->len ++] = s->config; |
103 | 7e7c5e4c | balrog | break;
|
104 | 7e7c5e4c | balrog | |
105 | 7e7c5e4c | balrog | case 2: /* T_LOW */ |
106 | 7e7c5e4c | balrog | s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8; |
107 | 7e7c5e4c | balrog | s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0; |
108 | 7e7c5e4c | balrog | break;
|
109 | 7e7c5e4c | balrog | |
110 | 7e7c5e4c | balrog | case 3: /* T_HIGH */ |
111 | 7e7c5e4c | balrog | s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8; |
112 | 7e7c5e4c | balrog | s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0; |
113 | 7e7c5e4c | balrog | break;
|
114 | 7e7c5e4c | balrog | } |
115 | 7e7c5e4c | balrog | } |
116 | 7e7c5e4c | balrog | |
117 | bc24a225 | Paul Brook | static void tmp105_write(TMP105State *s) |
118 | 7e7c5e4c | balrog | { |
119 | 7e7c5e4c | balrog | switch (s->pointer & 3) { |
120 | 7e7c5e4c | balrog | case 0: /* Temperature */ |
121 | 7e7c5e4c | balrog | break;
|
122 | 7e7c5e4c | balrog | |
123 | 7e7c5e4c | balrog | case 1: /* Configuration */ |
124 | 7e7c5e4c | balrog | if (s->buf[0] & ~s->config & (1 << 0)) /* SD */ |
125 | 7e7c5e4c | balrog | printf("%s: TMP105 shutdown\n", __FUNCTION__);
|
126 | 7e7c5e4c | balrog | s->config = s->buf[0];
|
127 | 7e7c5e4c | balrog | s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */ |
128 | 7e7c5e4c | balrog | tmp105_alarm_update(s); |
129 | 7e7c5e4c | balrog | break;
|
130 | 7e7c5e4c | balrog | |
131 | 7e7c5e4c | balrog | case 2: /* T_LOW */ |
132 | 7e7c5e4c | balrog | case 3: /* T_HIGH */ |
133 | 7e7c5e4c | balrog | if (s->len >= 3) |
134 | 7e7c5e4c | balrog | s->limit[s->pointer & 1] = (int16_t)
|
135 | 7e7c5e4c | balrog | ((((uint16_t) s->buf[0]) << 8) | s->buf[1]); |
136 | 7e7c5e4c | balrog | tmp105_alarm_update(s); |
137 | 7e7c5e4c | balrog | break;
|
138 | 7e7c5e4c | balrog | } |
139 | 7e7c5e4c | balrog | } |
140 | 7e7c5e4c | balrog | |
141 | 7e7c5e4c | balrog | static int tmp105_rx(i2c_slave *i2c) |
142 | 7e7c5e4c | balrog | { |
143 | bc24a225 | Paul Brook | TMP105State *s = (TMP105State *) i2c; |
144 | 7e7c5e4c | balrog | |
145 | 7e7c5e4c | balrog | if (s->len < 2) |
146 | 7e7c5e4c | balrog | return s->buf[s->len ++];
|
147 | 7e7c5e4c | balrog | else
|
148 | 7e7c5e4c | balrog | return 0xff; |
149 | 7e7c5e4c | balrog | } |
150 | 7e7c5e4c | balrog | |
151 | 7e7c5e4c | balrog | static int tmp105_tx(i2c_slave *i2c, uint8_t data) |
152 | 7e7c5e4c | balrog | { |
153 | bc24a225 | Paul Brook | TMP105State *s = (TMP105State *) i2c; |
154 | 7e7c5e4c | balrog | |
155 | 7e7c5e4c | balrog | if (!s->len ++)
|
156 | 7e7c5e4c | balrog | s->pointer = data; |
157 | 7e7c5e4c | balrog | else {
|
158 | 7e7c5e4c | balrog | if (s->len <= 2) |
159 | 7e7c5e4c | balrog | s->buf[s->len - 1] = data;
|
160 | 7e7c5e4c | balrog | tmp105_write(s); |
161 | 7e7c5e4c | balrog | } |
162 | 7e7c5e4c | balrog | |
163 | 7e7c5e4c | balrog | return 0; |
164 | 7e7c5e4c | balrog | } |
165 | 7e7c5e4c | balrog | |
166 | 7e7c5e4c | balrog | static void tmp105_event(i2c_slave *i2c, enum i2c_event event) |
167 | 7e7c5e4c | balrog | { |
168 | bc24a225 | Paul Brook | TMP105State *s = (TMP105State *) i2c; |
169 | 7e7c5e4c | balrog | |
170 | 7e7c5e4c | balrog | if (event == I2C_START_RECV)
|
171 | 7e7c5e4c | balrog | tmp105_read(s); |
172 | 7e7c5e4c | balrog | |
173 | 7e7c5e4c | balrog | s->len = 0;
|
174 | 7e7c5e4c | balrog | } |
175 | 7e7c5e4c | balrog | |
176 | 371a4468 | Juan Quintela | static void tmp105_post_save(void *opaque) |
177 | 7e7c5e4c | balrog | { |
178 | 371a4468 | Juan Quintela | TMP105State *s = opaque; |
179 | 7e7c5e4c | balrog | s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */ |
180 | 7e7c5e4c | balrog | } |
181 | 7e7c5e4c | balrog | |
182 | 371a4468 | Juan Quintela | static int tmp105_post_load(void *opaque, int version_id) |
183 | 7e7c5e4c | balrog | { |
184 | 371a4468 | Juan Quintela | TMP105State *s = opaque; |
185 | 7e7c5e4c | balrog | |
186 | 7e7c5e4c | balrog | tmp105_interrupt_update(s); |
187 | 7e7c5e4c | balrog | return 0; |
188 | 7e7c5e4c | balrog | } |
189 | 7e7c5e4c | balrog | |
190 | 371a4468 | Juan Quintela | static const VMStateDescription vmstate_tmp105 = { |
191 | 371a4468 | Juan Quintela | .name = "TMP105",
|
192 | 371a4468 | Juan Quintela | .version_id = 0,
|
193 | 371a4468 | Juan Quintela | .minimum_version_id = 0,
|
194 | 371a4468 | Juan Quintela | .minimum_version_id_old = 0,
|
195 | 371a4468 | Juan Quintela | .post_save = tmp105_post_save, |
196 | 371a4468 | Juan Quintela | .post_load = tmp105_post_load, |
197 | 371a4468 | Juan Quintela | .fields = (VMStateField []) { |
198 | 371a4468 | Juan Quintela | VMSTATE_UINT8(len, TMP105State), |
199 | 371a4468 | Juan Quintela | VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
|
200 | 371a4468 | Juan Quintela | VMSTATE_UINT8(pointer, TMP105State), |
201 | 371a4468 | Juan Quintela | VMSTATE_UINT8(config, TMP105State), |
202 | 371a4468 | Juan Quintela | VMSTATE_INT16(temperature, TMP105State), |
203 | 371a4468 | Juan Quintela | VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
|
204 | 371a4468 | Juan Quintela | VMSTATE_UINT8(alarm, TMP105State), |
205 | 371a4468 | Juan Quintela | VMSTATE_I2C_SLAVE(i2c, TMP105State), |
206 | 371a4468 | Juan Quintela | VMSTATE_END_OF_LIST() |
207 | 371a4468 | Juan Quintela | } |
208 | 371a4468 | Juan Quintela | }; |
209 | 371a4468 | Juan Quintela | |
210 | 697454eb | Paul Brook | static void tmp105_reset(i2c_slave *i2c) |
211 | 7e7c5e4c | balrog | { |
212 | bc24a225 | Paul Brook | TMP105State *s = (TMP105State *) i2c; |
213 | 7e7c5e4c | balrog | |
214 | 7e7c5e4c | balrog | s->temperature = 0;
|
215 | 7e7c5e4c | balrog | s->pointer = 0;
|
216 | 7e7c5e4c | balrog | s->config = 0;
|
217 | 7e7c5e4c | balrog | s->faults = tmp105_faultq[(s->config >> 3) & 3]; |
218 | 7e7c5e4c | balrog | s->alarm = 0;
|
219 | 7e7c5e4c | balrog | |
220 | 7e7c5e4c | balrog | tmp105_interrupt_update(s); |
221 | 7e7c5e4c | balrog | } |
222 | 7e7c5e4c | balrog | |
223 | 81a322d4 | Gerd Hoffmann | static int tmp105_init(i2c_slave *i2c) |
224 | 7e7c5e4c | balrog | { |
225 | 697454eb | Paul Brook | TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c); |
226 | 7e7c5e4c | balrog | |
227 | 697454eb | Paul Brook | qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
|
228 | 7e7c5e4c | balrog | |
229 | 7e7c5e4c | balrog | tmp105_reset(&s->i2c); |
230 | 7e7c5e4c | balrog | |
231 | 371a4468 | Juan Quintela | vmstate_register(-1, &vmstate_tmp105, s);
|
232 | 81a322d4 | Gerd Hoffmann | return 0; |
233 | 697454eb | Paul Brook | } |
234 | 697454eb | Paul Brook | |
235 | 697454eb | Paul Brook | static I2CSlaveInfo tmp105_info = {
|
236 | 074f2fff | Gerd Hoffmann | .qdev.name = "tmp105",
|
237 | 074f2fff | Gerd Hoffmann | .qdev.size = sizeof(TMP105State),
|
238 | 697454eb | Paul Brook | .init = tmp105_init, |
239 | 697454eb | Paul Brook | .event = tmp105_event, |
240 | 697454eb | Paul Brook | .recv = tmp105_rx, |
241 | 697454eb | Paul Brook | .send = tmp105_tx |
242 | 697454eb | Paul Brook | }; |
243 | 7e7c5e4c | balrog | |
244 | 697454eb | Paul Brook | static void tmp105_register_devices(void) |
245 | 697454eb | Paul Brook | { |
246 | 074f2fff | Gerd Hoffmann | i2c_register_slave(&tmp105_info); |
247 | 7e7c5e4c | balrog | } |
248 | 697454eb | Paul Brook | |
249 | 697454eb | Paul Brook | device_init(tmp105_register_devices) |