~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to hw/tmp105.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
    uint8_t 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
    uint8_t 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 int tmp105_post_load(void *opaque, int version_id)
 
177
{
 
178
    TMP105State *s = opaque;
 
179
 
 
180
    s->faults = tmp105_faultq[(s->config >> 3) & 3];            /* F */
 
181
 
 
182
    tmp105_interrupt_update(s);
 
183
    return 0;
 
184
}
 
185
 
 
186
static const VMStateDescription vmstate_tmp105 = {
 
187
    .name = "TMP105",
 
188
    .version_id = 0,
 
189
    .minimum_version_id = 0,
 
190
    .minimum_version_id_old = 0,
 
191
    .post_load = tmp105_post_load,
 
192
    .fields      = (VMStateField []) {
 
193
        VMSTATE_UINT8(len, TMP105State),
 
194
        VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
 
195
        VMSTATE_UINT8(pointer, TMP105State),
 
196
        VMSTATE_UINT8(config, TMP105State),
 
197
        VMSTATE_INT16(temperature, TMP105State),
 
198
        VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
 
199
        VMSTATE_UINT8(alarm, TMP105State),
 
200
        VMSTATE_I2C_SLAVE(i2c, TMP105State),
 
201
        VMSTATE_END_OF_LIST()
 
202
    }
 
203
};
 
204
 
 
205
static void tmp105_reset(i2c_slave *i2c)
 
206
{
 
207
    TMP105State *s = (TMP105State *) i2c;
 
208
 
 
209
    s->temperature = 0;
 
210
    s->pointer = 0;
 
211
    s->config = 0;
 
212
    s->faults = tmp105_faultq[(s->config >> 3) & 3];
 
213
    s->alarm = 0;
 
214
 
 
215
    tmp105_interrupt_update(s);
 
216
}
 
217
 
 
218
static int tmp105_init(i2c_slave *i2c)
 
219
{
 
220
    TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c);
 
221
 
 
222
    qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
 
223
 
 
224
    tmp105_reset(&s->i2c);
 
225
 
 
226
    return 0;
 
227
}
 
228
 
 
229
static I2CSlaveInfo tmp105_info = {
 
230
    .qdev.name = "tmp105",
 
231
    .qdev.size = sizeof(TMP105State),
 
232
    .qdev.vmsd = &vmstate_tmp105,
 
233
    .init = tmp105_init,
 
234
    .event = tmp105_event,
 
235
    .recv = tmp105_rx,
 
236
    .send = tmp105_tx
 
237
};
 
238
 
 
239
static void tmp105_register_devices(void)
 
240
{
 
241
    i2c_register_slave(&tmp105_info);
 
242
}
 
243
 
 
244
device_init(tmp105_register_devices)