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