2 * AK8973 Compass Emulation
4 * Copyright (c) 2010 Samsung Electronics.
5 * Contributed by Junsik.Park <okdear.park@samsung.com>
8 #include "i2c-addressable.h"
13 #define AK8973_ST 0xC0
14 #define AK8973_TMPS 0xC1
15 #define AK8973_H1X 0xC2
16 #define AK8973_H1Y 0xC3
17 #define AK8973_H1Z 0xC4
19 #define AK8973_MS1 0xE0
20 #define AK8973_HXDA 0xE1
21 #define AK8973_HYDA 0xE2
22 #define AK8973_HZDA 0xE3
23 #define AK8973_HXGA 0xE4
24 #define AK8973_HYGA 0xE5
25 #define AK8973_HZGA 0xE6
27 #define AK8973_ETS 0x62
28 #define AK8973_EVIR 0x63
29 #define AK8973_EIHE 0x64
30 #define AK8973_ETST 0x65
31 #define AK8973_EHXGA 0x66
32 #define AK8973_EHYGA 0x67
33 #define AK8973_EHZGA 0x68
34 #define AK8973_WRAL1 0x60
37 typedef struct AK8973State {
38 I2CAddressableState i2c_addressable;
52 static void ak8973_reset(DeviceState *d)
55 FROM_I2CADDR_SLAVE(AK8973State, I2CADDR_SLAVE_FROM_QDEV(d));
58 /* Random coordinates */
63 /* 20 degree Celsius */
66 /* EEPROM data-write disable / Powerdown mode */
69 /* TODO: get the defaults */
80 static uint8_t ak8973_read(void *opaque, uint32_t address, uint8_t offset)
82 struct AK8973State *s = (struct AK8973State *)opaque;
83 uint32_t ret = 0, index = address + offset;
90 /* IRQ is lowered when any of data registers are read */
91 qemu_irq_lower(s->irq);
96 qemu_irq_lower(s->irq);
101 qemu_irq_lower(s->irq);
106 qemu_irq_lower(s->irq);
116 ret = s->dac[index - AK8973_HXDA];
121 ret = s->gain[index - AK8973_HXGA];
131 if ((s->ms1 & 3) == 2 && (s->ms1 & 0xF8) != 0xA8) {
132 /* TODO: implement EEPROM reading */
139 hw_error("ak8973: bad read offset 0x%x\n", index);
143 printf("ak8973_read IDX = 0x%x, Data = 0x%x\n", index, ret);
149 static void ak8973_write(void *opaque, uint32_t address, uint8_t offset,
152 struct AK8973State *s = (struct AK8973State *)opaque;
153 uint32_t index = address + offset;
156 printf("ak8973_write IDX = 0x%x, Data = 0x%x\n", index, val);
161 if ((val & 3) == 2) {
162 /* EEPROM access mode */
163 /* TODO: implement this mode */
166 /* All other mode setting finishes in power-down mode */
169 if ((val & 3) == 0) {
170 /* Measurement mode */
171 qemu_irq_raise(s->irq);
173 /* TODO: change measurement registers accordingly */
179 /* TODO: implement DAC changes influence on reported data */
180 s->dac[index - AK8973_HXDA] = val;
185 /* TODO: implement gain changes influence on reported data */
186 s->gain[index - AK8973_HXGA] = val;
196 if ((s->ms1 & 3) == 2 && (s->ms1 & 0xF8) == 0xA8) {
197 /* TODO: implement EEPROM writing */
201 hw_error("ak8973: bad write offset 0x%x\n", index);
205 static void ak8973_save(QEMUFile *f, void *opaque)
207 struct AK8973State *s = (struct AK8973State *)opaque;
209 qemu_put_8s(f, &s->status);
210 qemu_put_8s(f, &s->ms1);
211 qemu_put_buffer(f, s->dac, 3);
212 qemu_put_buffer(f, s->gain, 3);
215 static int ak8973_load(QEMUFile *f, void *opaque, int version_id)
217 struct AK8973State *s = (struct AK8973State *)opaque;
219 if (version_id != 1) {
223 qemu_get_8s(f, &s->status);
224 qemu_get_8s(f, &s->ms1);
225 qemu_get_buffer(f, s->dac, 3);
226 qemu_get_buffer(f, s->gain, 3);
231 void ak8973_update(DeviceState *dev,
232 uint8_t x, uint8_t y, uint8_t z, uint8_t temp)
235 FROM_I2CADDR_SLAVE(AK8973State, I2CADDR_SLAVE_FROM_QDEV(dev));
241 printf("compass update : %d %d %d %d\n", x, y, z, temp);
246 static int ak8973_init(I2CAddressableState *s)
248 AK8973State *t = FROM_I2CADDR_SLAVE(AK8973State, s);
250 /* Set irq address */
251 qdev_init_gpio_out(&s->i2c.qdev, &t->irq, 1);
253 ak8973_reset(&s->i2c.qdev);
255 register_savevm(&s->i2c.qdev, "ak8973", -1, 1,
256 ak8973_save, ak8973_load, s);
261 static I2CAddressableDeviceInfo ak8973_info = {
262 .i2c.qdev.name = "ak8973",
263 .i2c.qdev.size = sizeof(AK8973State),
264 .i2c.qdev.reset = ak8973_reset,
267 .write = ak8973_write,
272 static void ak8973_register_devices(void)
274 i2c_addressable_register_device(&ak8973_info);
277 device_init(ak8973_register_devices)