Statistics
| Branch: | Revision:

root / hw / tmp105.c @ 81a322d4

History | View | Annotate | Download (6.1 kB)

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)