r3750 - trunk/src/host/qemu-neo1973/hw
andrew at sita.openmoko.org
andrew at sita.openmoko.org
Fri Dec 28 19:13:58 CET 2007
Author: andrew
Date: 2007-12-28 19:13:57 +0100 (Fri, 28 Dec 2007)
New Revision: 3750
Modified:
trunk/src/host/qemu-neo1973/hw/neo1973.c
Log:
Preliminary LIS302DL accelerometers in the GTA02F.
Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-12-28 07:16:20 UTC (rev 3749)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-12-28 18:13:57 UTC (rev 3750)
@@ -87,6 +87,7 @@
i2c_slave *pmu;
i2c_slave *wm;
i2c_slave *lcm;
+ i2c_slave *accel[2];
CharDriverState *modem;
CharDriverState *gps;
QEMUTimer *modem_timer;
@@ -344,9 +345,207 @@
return &s->i2c;
}
+/* LIS302DL "piccolo" motion sensor/accelerometer */
+struct piccolo_s {
+ i2c_slave i2c;
+ int firstbyte;
+
+ qemu_irq intr[2];
+
+ uint8_t regs[0x40];
+ int reg;
+
+ QEMUTimer *sample;
+};
+
+void piccolo_reset(i2c_slave *i2c)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+
+ memset(s->regs, 0, sizeof(s->regs));
+ s->regs[0x0f] = 0x3b; /* Who_Am_I */
+ s->regs[0x20] = 0x07; /* Ctrl_Reg1 */
+}
+
+static void piccolo_sample_sched(struct piccolo_s *s)
+{
+ int rate = (s->regs[0x20] & (1 << 7)) ? 400 : 100; /* DR */
+
+ qemu_mod_timer(s->sample,
+ qemu_get_clock(vm_clock) + ticks_per_sec / rate);
+}
+
+static void piccolo_sample_tick(void *opaque)
+{
+ struct piccolo_s *s = (struct piccolo_s *) opaque;
+
+ /* TODO */
+ piccolo_sample_sched(s);
+}
+
+static void piccolo_sample_update(struct piccolo_s *s)
+{
+ if (!(s->regs[0x20] & 7)) /* Xen | Yen | Zen */
+ qemu_del_timer(s->sample);
+ else if (!qemu_timer_pending(s->sample))
+ piccolo_sample_sched(s);
+}
+
+static void piccolo_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
+}
+
+static int piccolo_rx(i2c_slave *i2c)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+ int reg = s->reg;
+
+ if (reg >= 0x80) {
+ reg -= 0x80;
+ s->reg ++;
+ } else
+ s->reg = -1;
+
+ switch (reg) {
+ case 0x00 ... 0x0e:
+ case 0x10 ... 0x1f:
+ case 0x2e ... 0x2f:
+ case 0x0f: /* Who_Am_I */
+ case 0x20: /* Ctrl_Reg1 */
+ case 0x21: /* Ctrl_Reg2 */
+ case 0x22: /* Ctrl_Reg3 */
+ case 0x23: /* HP_filter_reset */
+ case 0x27: /* Status_Reg */
+ case 0x29: /* OutX */
+ case 0x2b: /* OutY */
+ case 0x2d: /* OutZ */
+ case 0x30: /* FF_WU_CFG_1 */
+ case 0x31: /* FF_WU_SRC_1 */
+ case 0x32: /* FF_WU_THS_1 */
+ case 0x33: /* FF_WU_DURATION_1 */
+ case 0x34: /* FF_WU_CFG_2 */
+ case 0x35: /* FF_WU_SRC_2 */
+ case 0x36: /* FF_WU_THS_2 */
+ case 0x37: /* FF_WU_DURATION_2 */
+ case 0x38: /* CLICK_CFG */
+ case 0x39: /* CLICK_SRC */
+ case 0x3b: /* CLICK_THSY_X */
+ case 0x3c: /* CLICK_THSZ */
+ case 0x3d: /* CLICK_timelimit */
+ case 0x3e: /* CLICK_latency */
+ case 0x3f: /* CLICK_window */
+ break;
+ default:
+ fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+ return 0x00;
+ }
+
+ return s->regs[reg];
+}
+
+static int piccolo_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+ int reg = s->reg;
+
+ if (s->firstbyte) {
+ s->firstbyte = 0;
+ s->reg = data;
+ return 0;
+ }
+
+ if (reg >= 0x80) {
+ reg -= 0x80;
+ s->reg ++;
+ }
+
+ switch (reg) {
+ case 0x00 ... 0x0e:
+ case 0x10 ... 0x1f:
+ case 0x2e ... 0x2f:
+ fprintf(stderr, "%s: write to a \"do not modify\" register %02x\n",
+ __FUNCTION__, s->reg);
+ fprintf(stderr, "%s: may cause permanent damage!\n", __FUNCTION__);
+ s->regs[reg] = data;
+ break;
+ case 0x20: /* Ctrl_Reg1 */
+ s->regs[reg] = data;
+ if (data & (3 << 3))
+ fprintf(stderr, "%s: Self-Test Enable attempt\n", __FUNCTION__);
+ piccolo_sample_update(s);
+ break;
+
+ case 0x21: /* Ctrl_Reg2 */
+ case 0x22: /* Ctrl_Reg3 */
+ case 0x30: /* FF_WU_CFG_1 */
+ case 0x32: /* FF_WU_THS_1 */
+ case 0x33: /* FF_WU_DURATION_1 */
+ case 0x34: /* FF_WU_CFG_2 */
+ case 0x36: /* FF_WU_THS_2 */
+ case 0x37: /* FF_WU_DURATION_2 */
+ case 0x38: /* CLICK_CFG */
+ case 0x39: /* CLICK_SRC */
+ case 0x3b: /* CLICK_THSY_X */
+ case 0x3c: /* CLICK_THSZ */
+ case 0x3d: /* CLICK_timelimit */
+ case 0x3e: /* CLICK_latency */
+ case 0x3f: /* CLICK_window */
+ /* TODO */
+ s->regs[reg] = data;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void piccolo_save(QEMUFile *f, void *opaque)
+{
+ struct piccolo_s *s = (struct piccolo_s *) opaque;
+
+ qemu_put_buffer(f, s->regs, sizeof(s->regs));
+ i2c_slave_save(f, &s->i2c);
+}
+
+static int piccolo_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct piccolo_s *s = (struct piccolo_s *) opaque;
+
+ qemu_get_buffer(f, s->regs, sizeof(s->regs));
+ i2c_slave_load(f, &s->i2c);
+ return 0;
+}
+
+i2c_slave *lis302dl_init(i2c_bus *bus, qemu_irq int1, qemu_irq int2)
+{
+ struct piccolo_s *s = (struct piccolo_s *)
+ i2c_slave_init(bus, 0, sizeof(struct piccolo_s));
+ s->i2c.event = piccolo_event;
+ s->i2c.send = piccolo_tx;
+ s->i2c.recv = piccolo_rx;
+
+ s->intr[0] = int1;
+ s->intr[1] = int2;
+ s->sample = qemu_new_timer(vm_clock, piccolo_sample_tick, s);
+
+ piccolo_reset(&s->i2c);
+ register_savevm("lis302dl", 0, 0, piccolo_save, piccolo_load, s);
+
+ return &s->i2c;
+}
+
/* I2C bus */
#define NEO_PMU_ADDR 0x08
#define NEO_WM_ADDR 0x1a
+#define NEO_ACCEL_ADDR0 0x1c
+#define NEO_ACCEL_ADDR1 0x1d
#define NEO_AMP_ADDR 0x7c /* ADR wired to low */
static void neo_i2c_setup(struct neo_board_s *s)
@@ -370,6 +569,14 @@
s->lcm = lm4857_init(bus);
i2c_set_slave_address(s->lcm, NEO_AMP_ADDR);
+ /* Attach two LIS302DL slaves to the bus */
+ if (s->id == NEO1973_GTA02 || s->id == NEO1973_GTA02F) {
+ s->accel[0] = lis302dl_init(bus, 0, 0); /* TODO: connect IRQs */
+ s->accel[1] = lis302dl_init(bus, 0, 0); /* TODO: connect IRQs */
+ i2c_set_slave_address(s->accel[0], NEO_ACCEL_ADDR0);
+ i2c_set_slave_address(s->accel[1], NEO_ACCEL_ADDR1);
+ }
+
#ifdef HAS_AUDIO
audio = AUD_init();
if (!audio)
More information about the commitlog
mailing list