symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/tmp105.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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
       
    18  * along with this program; if not, write to the Free Software
       
    19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       
    20  * MA 02111-1307 USA
       
    21  */
       
    22 
       
    23 #include "hw.h"
       
    24 #include "i2c.h"
       
    25 
       
    26 struct tmp105_s {
       
    27     i2c_slave i2c;
       
    28     int len;
       
    29     uint8_t buf[2];
       
    30     qemu_irq pin;
       
    31 
       
    32     uint8_t pointer;
       
    33     uint8_t config;
       
    34     int16_t temperature;
       
    35     int16_t limit[2];
       
    36     int faults;
       
    37     int alarm;
       
    38 };
       
    39 
       
    40 static void tmp105_interrupt_update(struct tmp105_s *s)
       
    41 {
       
    42     qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1));	/* POL */
       
    43 }
       
    44 
       
    45 static void tmp105_alarm_update(struct tmp105_s *s)
       
    46 {
       
    47     if ((s->config >> 0) & 1) {					/* SD */
       
    48         if ((s->config >> 7) & 1)				/* OS */
       
    49             s->config &= ~(1 << 7);				/* OS */
       
    50         else
       
    51             return;
       
    52     }
       
    53 
       
    54     if ((s->config >> 1) & 1) {					/* TM */
       
    55         if (s->temperature >= s->limit[1])
       
    56             s->alarm = 1;
       
    57         else if (s->temperature < s->limit[0])
       
    58             s->alarm = 1;
       
    59     } else {
       
    60         if (s->temperature >= s->limit[1])
       
    61             s->alarm = 1;
       
    62         else if (s->temperature < s->limit[0])
       
    63             s->alarm = 0;
       
    64     }
       
    65 
       
    66     tmp105_interrupt_update(s);
       
    67 }
       
    68 
       
    69 /* Units are 0.001 centigrades relative to 0 C.  */
       
    70 void tmp105_set(i2c_slave *i2c, int temp)
       
    71 {
       
    72     struct tmp105_s *s = (struct tmp105_s *) i2c;
       
    73 
       
    74     if (temp >= 128000 || temp < -128000) {
       
    75         fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
       
    76                         __FUNCTION__, temp / 1000, temp % 1000);
       
    77         exit(-1);
       
    78     }
       
    79 
       
    80     s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
       
    81 
       
    82     tmp105_alarm_update(s);
       
    83 }
       
    84 
       
    85 static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
       
    86 
       
    87 static void tmp105_read(struct tmp105_s *s)
       
    88 {
       
    89     s->len = 0;
       
    90 
       
    91     if ((s->config >> 1) & 1) {					/* TM */
       
    92         s->alarm = 0;
       
    93         tmp105_interrupt_update(s);
       
    94     }
       
    95 
       
    96     switch (s->pointer & 3) {
       
    97     case 0:	/* Temperature */
       
    98         s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
       
    99         s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
       
   100                 (0xf0 << ((~s->config >> 5) & 3));		/* R */
       
   101         break;
       
   102 
       
   103     case 1:	/* Configuration */
       
   104         s->buf[s->len ++] = s->config;
       
   105         break;
       
   106 
       
   107     case 2:	/* T_LOW */
       
   108         s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
       
   109         s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
       
   110         break;
       
   111 
       
   112     case 3:	/* T_HIGH */
       
   113         s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
       
   114         s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
       
   115         break;
       
   116     }
       
   117 }
       
   118 
       
   119 static void tmp105_write(struct tmp105_s *s)
       
   120 {
       
   121     switch (s->pointer & 3) {
       
   122     case 0:	/* Temperature */
       
   123         break;
       
   124 
       
   125     case 1:	/* Configuration */
       
   126         if (s->buf[0] & ~s->config & (1 << 0))			/* SD */
       
   127             printf("%s: TMP105 shutdown\n", __FUNCTION__);
       
   128         s->config = s->buf[0];
       
   129         s->faults = tmp105_faultq[(s->config >> 3) & 3];	/* F */
       
   130         tmp105_alarm_update(s);
       
   131         break;
       
   132 
       
   133     case 2:	/* T_LOW */
       
   134     case 3:	/* T_HIGH */
       
   135         if (s->len >= 3)
       
   136             s->limit[s->pointer & 1] = (int16_t)
       
   137                     ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
       
   138         tmp105_alarm_update(s);
       
   139         break;
       
   140     }
       
   141 }
       
   142 
       
   143 static int tmp105_rx(i2c_slave *i2c)
       
   144 {
       
   145     struct tmp105_s *s = (struct tmp105_s *) i2c;
       
   146 
       
   147     if (s->len < 2)
       
   148         return s->buf[s->len ++];
       
   149     else
       
   150         return 0xff;
       
   151 }
       
   152 
       
   153 static int tmp105_tx(i2c_slave *i2c, uint8_t data)
       
   154 {
       
   155     struct tmp105_s *s = (struct tmp105_s *) i2c;
       
   156 
       
   157     if (!s->len ++)
       
   158         s->pointer = data;
       
   159     else {
       
   160         if (s->len <= 2)
       
   161             s->buf[s->len - 1] = data;
       
   162         tmp105_write(s);
       
   163     }
       
   164 
       
   165     return 0;
       
   166 }
       
   167 
       
   168 static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
       
   169 {
       
   170     struct tmp105_s *s = (struct tmp105_s *) i2c;
       
   171 
       
   172     if (event == I2C_START_RECV)
       
   173         tmp105_read(s);
       
   174 
       
   175     s->len = 0;
       
   176 }
       
   177 
       
   178 static void tmp105_save(QEMUFile *f, void *opaque)
       
   179 {
       
   180     struct tmp105_s *s = (struct tmp105_s *) opaque;
       
   181 
       
   182     qemu_put_byte(f, s->len);
       
   183     qemu_put_8s(f, &s->buf[0]);
       
   184     qemu_put_8s(f, &s->buf[1]);
       
   185 
       
   186     qemu_put_8s(f, &s->pointer);
       
   187     qemu_put_8s(f, &s->config);
       
   188     qemu_put_sbe16s(f, &s->temperature);
       
   189     qemu_put_sbe16s(f, &s->limit[0]);
       
   190     qemu_put_sbe16s(f, &s->limit[1]);
       
   191     qemu_put_byte(f, s->alarm);
       
   192     s->faults = tmp105_faultq[(s->config >> 3) & 3];		/* F */
       
   193 
       
   194     i2c_slave_save(f, &s->i2c);
       
   195 }
       
   196 
       
   197 static int tmp105_load(QEMUFile *f, void *opaque, int version_id)
       
   198 {
       
   199     struct tmp105_s *s = (struct tmp105_s *) opaque;
       
   200 
       
   201     s->len = qemu_get_byte(f);
       
   202     qemu_get_8s(f, &s->buf[0]);
       
   203     qemu_get_8s(f, &s->buf[1]);
       
   204 
       
   205     qemu_get_8s(f, &s->pointer);
       
   206     qemu_get_8s(f, &s->config);
       
   207     qemu_get_sbe16s(f, &s->temperature);
       
   208     qemu_get_sbe16s(f, &s->limit[0]);
       
   209     qemu_get_sbe16s(f, &s->limit[1]);
       
   210     s->alarm = qemu_get_byte(f);
       
   211 
       
   212     tmp105_interrupt_update(s);
       
   213 
       
   214     i2c_slave_load(f, &s->i2c);
       
   215     return 0;
       
   216 }
       
   217 
       
   218 void tmp105_reset(i2c_slave *i2c)
       
   219 {
       
   220     struct tmp105_s *s = (struct tmp105_s *) i2c;
       
   221 
       
   222     s->temperature = 0;
       
   223     s->pointer = 0;
       
   224     s->config = 0;
       
   225     s->faults = tmp105_faultq[(s->config >> 3) & 3];
       
   226     s->alarm = 0;
       
   227 
       
   228     tmp105_interrupt_update(s);
       
   229 }
       
   230 
       
   231 struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm)
       
   232 {
       
   233     struct tmp105_s *s = (struct tmp105_s *)
       
   234             i2c_slave_init(bus, 0, sizeof(struct tmp105_s));
       
   235 
       
   236     s->i2c.event = tmp105_event;
       
   237     s->i2c.recv = tmp105_rx;
       
   238     s->i2c.send = tmp105_tx;
       
   239     s->pin = alarm;
       
   240 
       
   241     tmp105_reset(&s->i2c);
       
   242 
       
   243     register_savevm("TMP105", -1, 0, tmp105_save, tmp105_load, s);
       
   244 
       
   245     return &s->i2c;
       
   246 }