Refurbished OMAP I2C emulation to support OMAP3
[qemu] / hw / twl4030.c
index bdbc4dd..32393ee 100644 (file)
@@ -1,5 +1,6 @@
 /*\r
  * TI TWL4030 for beagle board\r
+ * register implementation based on TPS65950 ES1.0 specification\r
  *\r
  * Copyright (C) 2008 yajin<yajin@vm-kernel.org>\r
  *\r
@@ -27,6 +28,7 @@
 #include "cpu-all.h"\r
 \r
 #define VERBOSE 1\r
+#define TRACEW(regname, value) fprintf(stderr, "%s: %s = 0x%02x\n", __FUNCTION__, regname, value);\r
 \r
 //extern CPUState *cpu_single_env;\r
 \r
@@ -41,18 +43,160 @@ struct twl4030_i2c_s {
 \r
 struct twl4030_s {\r
     struct twl4030_i2c_s *i2c[5];\r
+    \r
+    int key_cfg;\r
+    int key_tst;\r
+    \r
+    uint8_t seq_mem[64][4]; /* power-management sequencing memory */\r
+};\r
+\r
+static const uint8_t addr_48_reset_values[256] = {\r
+    0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */\r
+    0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */\r
+    0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */\r
+    0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */\r
+    0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */\r
+    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */\r
+    0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */\r
+    0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */\r
+    0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */\r
+    0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */\r
+    0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00  /* 0xf8...0xff */\r
 };\r
 \r
+static const uint8_t addr_49_reset_values[256] = {\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */\r
+    0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */\r
+    0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */\r
+    0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */\r
+    0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */\r
+    0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */\r
+    0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */\r
+    0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */\r
+    0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */\r
+    0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */\r
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */\r
+    0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */\r
+};\r
+\r
+static const uint8_t addr_4a_reset_values[256] = {\r
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */\r
+    0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */\r
+    0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */\r
+    0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */\r
+    0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */\r
+    0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */\r
+    0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */\r
+    0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */\r
+    0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */\r
+    0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */\r
+    0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */\r
+    0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */\r
+    0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */\r
+};\r
+\r
+static const uint8_t addr_4b_reset_values[256] = {\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */\r
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */\r
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */\r
+    0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */\r
+    0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */\r
+    0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */\r
+    0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */\r
+    0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */\r
+    0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */\r
+    0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */\r
+    0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */\r
+    0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */\r
+    0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */\r
+    0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */\r
+    0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */\r
+    0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */\r
+    0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */\r
+    0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */\r
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */\r
+    0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */\r
+    0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */\r
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */\r
+    0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */\r
+    0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */\r
+    0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */\r
+    0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */\r
+    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */\r
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */\r
+};\r
 \r
 static uint8_t twl4030_48_read(void *opaque, uint8_t addr)\r
 {\r
-    //struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
-    //int reg = 0;\r
-       \r
-    printf("twl4030_48_read addr %x\n",addr);\r
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
        \r
-    switch (addr)\r
-    {\r
+    switch (addr) {\r
+        case 0xfd: /* PHY_PWR_CTRL */\r
+            return s->reg_data[addr];\r
         default:\r
 #ifdef VERBOSE\r
             printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
@@ -66,14 +210,8 @@ static uint8_t twl4030_48_read(void *opaque, uint8_t addr)
 static void twl4030_48_write(void *opaque, uint8_t addr, uint8_t value)\r
 {\r
     //struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
-    //int line;\r
-    //int reg = 0;\r
-    //struct tm tm;\r
        \r
-    printf("twl4030_48_write addr %x value %x \n",addr,value);\r
-    \r
-    switch (addr)\r
-    {\r
+    switch (addr) {\r
         default:\r
 #ifdef VERBOSE\r
             printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
@@ -92,7 +230,7 @@ static int twl4030_48_tx(i2c_slave *i2c, uint8_t data)
         s->reg = data;\r
         s->firstbyte = 0;\r
     } else\r
-        twl4030_48_write(s, s->reg ++, data);\r
+        twl4030_48_write(s, s->reg++, data);\r
        \r
     return 0;\r
 }\r
@@ -101,13 +239,14 @@ static int twl4030_48_rx(i2c_slave *i2c)
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
        \r
-    return twl4030_48_read(s, s->reg ++);\r
+    return twl4030_48_read(s, s->reg++);\r
 }\r
 \r
 static void twl4030_48_reset(i2c_slave *i2c)\r
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
     s->reg = 0x00;\r
+    memcpy(s->reg_data, addr_48_reset_values, 256);\r
 }\r
 \r
 static void twl4030_48_event(i2c_slave *i2c, enum i2c_event event)\r
@@ -120,55 +259,48 @@ static void twl4030_48_event(i2c_slave *i2c, enum i2c_event event)
 \r
 static uint8_t twl4030_49_read(void *opaque, uint8_t addr)\r
 {\r
-    //struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
-    //int reg = 0;\r
-       \r
-    printf("twl4030_49_read addr %x\n",addr);\r
-       \r
-    switch (addr)\r
-    {\r
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
+\r
+    switch (addr) {\r
+        case 0x9b: /* GPIO_DATADIR1 */\r
+        case 0xb1: /* GPIO_ISR1A */\r
+        case 0xb2: /* GPIO_ISR2A */\r
+        case 0xb3: /* GPIO_ISR3A */\r
+            return s->reg_data[addr];\r
         default:\r
 #ifdef VERBOSE\r
-            printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
-            //printf("%s: unknown register %02x \n", __FUNCTION__, addr);\r
+            fprintf(stderr, "%s: unknown register %02x pc %x\n",\r
+                    __FUNCTION__, addr,cpu_single_env->regs[15]);\r
 #endif\r
                        exit(-1);\r
-                       break;\r
     }\r
 }\r
 \r
 static void twl4030_49_write(void *opaque, uint8_t addr, uint8_t value)\r
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
-    //int line;\r
-    //int reg = 0;\r
-    //struct tm tm;\r
-       \r
-    //printf("twl4030_49_write addr %x value %x \n", addr, value);\r
        \r
-    switch (addr)\r
-    {\r
-        case 0xaa:\r
-        case 0xab:\r
-        case 0xac:\r
-        case 0xad:\r
-        case 0xae:\r
-        case 0xaf:\r
-            fprintf(stderr,"%s: addr %x value %02x\n", __FUNCTION__, addr, value);\r
-            /* fallthrough */\r
-           case 0xb4:  /*GPIO IMR*/\r
-           case 0xb5:\r
-           case 0xb6:\r
-           case 0xb7:\r
-           case 0xb8:\r
-           case 0xb9:\r
-           case 0xba:\r
-           case 0xbb:\r
-           case 0xbc:\r
-           case 0xc5:\r
-               s->reg_data[addr] = value;\r
-               break;\r
-            \r
+    switch (addr) {\r
+        case 0xaa: /* GPIO_CTRL */\r
+        case 0xab: /* GPIOPUPDCTR1 */\r
+        case 0xac: /* GPIOPUPDCTR2 */\r
+        case 0xad: /* GPIOPUPDCTR3 */\r
+        case 0xae: /* GPIOPUPDCTR4 */\r
+            s->reg_data[addr] = value;\r
+            break;\r
+        case 0xaf: /* GPIOPUPDCTR5 */\r
+            s->reg_data[addr] = value & 0x0f;\r
+            break;\r
+           case 0xb4: /* GPIO_IMR1A */\r
+           case 0xb5: /* GPIO_IMR2A */\r
+            s->reg_data[addr] = value;\r
+            break;\r
+           case 0xb6: /* GPIO_IMR3A */\r
+            s->reg_data[addr] = value & 0x03;\r
+            break;\r
+           case 0xc5: /* GPIO_SIH_CTRL */\r
+            s->reg_data[addr] = value & 0x07;\r
+            break;\r
         default:\r
 #ifdef VERBOSE\r
             printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,\r
@@ -189,7 +321,7 @@ static int twl4030_49_tx(i2c_slave *i2c, uint8_t data)
         s->reg = data;\r
         s->firstbyte = 0;\r
     } else\r
-        twl4030_49_write(s, s->reg ++, data);\r
+        twl4030_49_write(s, s->reg++, data);\r
        \r
     return 0;\r
 }\r
@@ -198,13 +330,14 @@ static int twl4030_49_rx(i2c_slave *i2c)
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
        \r
-    return twl4030_49_read(s, s->reg ++);\r
+    return twl4030_49_read(s, s->reg++);\r
 }\r
 \r
 static void twl4030_49_reset(i2c_slave *i2c)\r
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
     s->reg = 0x00;\r
+    memcpy(s->reg_data, addr_49_reset_values, 256);\r
 }\r
 \r
 static void twl4030_49_event(i2c_slave *i2c, enum i2c_event event)\r
@@ -217,13 +350,15 @@ static void twl4030_49_event(i2c_slave *i2c, enum i2c_event event)
 \r
 static uint8_t twl4030_4a_read(void *opaque, uint8_t addr)\r
 {\r
-    //struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
-    //int reg = 0;\r
-       \r
-    printf("twl4030_4a_read addr %x\n",addr);\r
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
        \r
-    switch (addr)\r
-    {\r
+    switch (addr) {\r
+        case 0x61: /* MADC_ISR1 */\r
+        case 0xb9: /* BCIISR1A */\r
+        case 0xba: /* BCIISR2A */\r
+        case 0xe3: /* KEYP_ISR1 */\r
+        case 0xee: /* LEDEN */\r
+            return s->reg_data[addr];\r
         default:\r
 #ifdef VERBOSE\r
                printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
@@ -241,24 +376,45 @@ static void twl4030_4a_write(void *opaque, uint8_t addr, uint8_t value)
     //int reg = 0;\r
     //struct tm tm;\r
        \r
-    fprintf(stderr, "%s: addr %x value %02x\n", __FUNCTION__, addr, value);\r
-       \r
-    switch (addr)\r
-    {\r
-        case 0xee:  /*LED EN*/\r
-        case 0xe4:\r
-        case 0xe9:\r
-        case 0xbb:\r
-        case 0xbc:\r
-        case 0x62:\r
-            \r
-        case 0x61:\r
-        case 0xb9:\r
-        case 0xba:\r
-        case 0xef:\r
-        case 0xf0:\r
+    switch (addr) {\r
+        case 0x61: /* MADC_ISR1 */\r
+            s->reg_data[value] &= ~(value & 0x0f);\r
+            break;\r
+        case 0x62: /* MADC_IMR1 */\r
+            s->reg_data[value] = value & 0x0f;\r
+            break;\r
+        case 0xb9: /* BCIISR1A */\r
+            s->reg_data[value] &= ~value;\r
+            break;\r
+        case 0xba: /* BCIISR2A */\r
+            s->reg_data[value] &= ~(value & 0x0f);\r
+            break;\r
+        case 0xbb: /* BCIIMR1A */\r
+            s->reg_data[addr] = value;\r
+            break;\r
+        case 0xbc: /* BCIIMR2A */\r
+            s->reg_data[addr] = value & 0x0f;\r
+            break;\r
+        case 0xe4: /* KEYP_IMR1 */\r
+            s->reg_data[addr] = value & 0x0f;\r
+            break;\r
+        case 0xe9: /* KEYP_SIH_CTRL */\r
+            s->reg_data[addr] = value & 0x07;\r
+            break;\r
+        case 0xee: /* LEDEN */\r
+            s->reg_data[addr] = value;\r
+#ifdef VERBOSE\r
+            fprintf(stderr, "%s: LEDA power=%s/enable=%s, LEDB power=%s/enable=%s\n", __FUNCTION__,\r
+                    value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",\r
+                    value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");\r
+#endif      \r
+            break;\r
+        case 0xef: /* PWMAON */\r
             s->reg_data[addr] = value;\r
             break;\r
+        case 0xf0: /* PWMAOFF */\r
+            s->reg_data[addr] = value & 0x7f;\r
+            break;\r
         default:\r
 #ifdef VERBOSE\r
                printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
@@ -277,7 +433,7 @@ static int twl4030_4a_tx(i2c_slave *i2c, uint8_t data)
         s->reg = data;\r
         s->firstbyte = 0;\r
     } else\r
-        twl4030_4a_write(s, s->reg ++, data);\r
+        twl4030_4a_write(s, s->reg++, data);\r
        \r
     return 0;\r
 }\r
@@ -286,13 +442,14 @@ static int twl4030_4a_rx(i2c_slave *i2c)
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
        \r
-    return twl4030_4a_read(s, s->reg ++);\r
+    return twl4030_4a_read(s, s->reg++);\r
 }\r
 \r
 static void twl4030_4a_reset(i2c_slave *i2c)\r
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
     s->reg = 0x00;\r
+    memcpy(s->reg_data, addr_4a_reset_values, 256);\r
 }\r
 \r
 static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)\r
@@ -305,13 +462,14 @@ static void twl4030_4a_event(i2c_slave *i2c, enum i2c_event event)
 \r
 static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)\r
 {\r
-    //struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
-    //int reg = 0;\r
-       \r
-    printf("twl4030_4b_read addr %x\n",addr);\r
+    struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
        \r
-    switch (addr)\r
-    {\r
+    switch (addr) {\r
+        case 0x2e: /* PWR_ISR1 */\r
+        case 0x33: /* PWR_EDR1 */\r
+        case 0x34: /* PWR_EDR2 */\r
+        case 0x45: /* STS_HW_CONDITIONS */\r
+            return s->reg_data[addr];\r
         default:\r
 #ifdef VERBOSE\r
                printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
@@ -322,50 +480,121 @@ static uint8_t twl4030_4b_read(void *opaque, uint8_t addr)
     }\r
 }\r
 \r
+\r
 static void twl4030_4b_write(void *opaque, uint8_t addr, uint8_t value)\r
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) opaque;\r
+    uint8_t seq_addr, seq_sub;\r
        \r
-    fprintf(stderr, "%s: addr %x value %02x\n", __FUNCTION__, addr, value);\r
-       \r
-    switch (addr)\r
-    {\r
-        case 0x2f:\r
-        case 0x35:\r
-        case 0x3b:\r
-        case 0x44:\r
-        case 0x82:\r
-        case 0x85:\r
-        case 0x7a:\r
-        case 0x7d:\r
-        case 0x8e:\r
-        case 0x91:\r
-        case 0x96:\r
-        case 0x99:\r
-\r
-        case 0x46:\r
-        case 0x47:\r
-        case 0x48:\r
-        case 0x55:\r
-        case 0x56:\r
-        case 0x57:\r
-        case 0x59:\r
-        case 0x5a:\r
-        case 0xcc:\r
-        case 0xcd:\r
-        case 0xcf:\r
-        case 0xd0:\r
-        case 0xd2:\r
-        case 0xd3:\r
-        case 0xd8:\r
-        case 0xd9:\r
-        case 0xe6:\r
+    switch (addr) {\r
+        case 0x46: /* P1_SW_EVENTS */\r
+        case 0x47: /* P2_SW_EVENTS */\r
+        case 0x48: /* P3_SW_EVENTS */\r
+            s->reg_data[addr] = value & 0x78;\r
+            break;\r
+        case 0x52: /* SEQ_ADD_W2P */\r
+        case 0x53: /* SEQ_ADD_P2A */\r
+        case 0x54: /* SEQ_ADD_A2W */\r
+        case 0x55: /* SEQ_ADD_A2S */\r
+        case 0x56: /* SEQ_ADD_S2A12 */\r
+        case 0x57: /* SEQ_ADD_S2A3 */\r
+        case 0x58: /* SEQ_ADD_WARM */\r
+            if (s->twl4030->key_cfg)\r
+                s->reg_data[addr] = value & 0x3f;\r
+            break;\r
+        case 0x59: /* MEMORY_ADDRESS */\r
+            if (s->twl4030->key_cfg)\r
+                s->reg_data[addr] = value;\r
+            break;\r
+        case 0x5a: /* MEMORY_DATA */\r
+            if (s->twl4030->key_cfg) {\r
+                s->reg_data[addr] = value;\r
+                seq_addr = s->reg_data[0x59];\r
+                seq_sub = seq_addr & 3;\r
+                seq_addr >>= 2;\r
+                if ((seq_addr >= 0x2b && seq_addr <= 0x3e) || (seq_addr <= 0x0e && seq_sub == 3))\r
+                    s->twl4030->seq_mem[seq_addr][seq_sub] = value;\r
+            }\r
+            s->reg_data[0x59]++; /* TODO: check if autoincrement is write-protected as well */\r
+            break;\r
+        case 0x7a: /* VAUX3_DEV_GRP */\r
+        case 0x82: /* VMMC1_DEV_GRP */\r
+        case 0x8e: /* VPLL2_DEV_GRP */\r
+        case 0x96: /* VDAC_DEV_GRP */\r
+        case 0xcc: /* VUSB1V5_DEV_GRP */\r
+        case 0xcf: /* VUSB1V8_DEV_GRP */\r
+        case 0xd2: /* VUSB3V1_DEV_GRP */\r
+        case 0xe6: /* HFCLKOUT_DEV_GRP */\r
+            s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0); \r
+            break;\r
+        case 0x2f: /* PWR_IMR1 */\r
+            s->reg_data[addr] = value;\r
+            break;\r
+        case 0x35: /* PWR_SIH_CTRL */\r
+            s->reg_data[addr] = value & 0x07;\r
+            break;\r
+        case 0x3b: /* CFG_BOOT */\r
+            if (s->twl4030->key_cfg)\r
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);\r
+            break;\r
+        case 0x44: /* PROTECT_KEY */\r
+            s->twl4030->key_cfg = 0;\r
+            s->twl4030->key_tst = 0;\r
+            switch (value) {\r
+                case 0x0C: \r
+                    if (s->reg_data[addr] == 0xC0)\r
+                        s->twl4030->key_cfg = 1;\r
+                    break;\r
+                case 0xE0:\r
+                    if (s->reg_data[addr] == 0x0E)\r
+                        s->twl4030->key_tst = 1;\r
+                    break;\r
+                case 0xEC:\r
+                    if (s->reg_data[addr] == 0xCE) {\r
+                        s->twl4030->key_cfg = 1;\r
+                        s->twl4030->key_tst = 1;\r
+                    }\r
+                    break;\r
+                default:\r
+                    break;\r
+            }\r
             s->reg_data[addr] = value;\r
             break;\r
+        case 0x7d: /* VAUX3_DEDICATED */\r
+            if (s->twl4030->key_tst)\r
+                s->reg_data[addr] = value & 0x77;\r
+            else\r
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);\r
+            break;\r
+        case 0x85: /* VMMC1_DEDICATED */\r
+        case 0x99: /* VDAC_DEDICATED */\r
+            if (s->twl4030->key_tst) \r
+                s->reg_data[addr] = value & 0x73;\r
+            else\r
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);\r
+            break;\r
+        case 0x91: /* VPLL2_DEDICATED */\r
+            if (s->twl4030->key_tst)\r
+                s->reg_data[addr] = value & 0x7f;\r
+            else\r
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);\r
+            break;\r
+        case 0xcd: /* VUSB1V5_TYPE */\r
+        case 0xd0: /* VUSB1V8_TYPE */\r
+        case 0xd3: /* VUSB3V1_TYPE */\r
+            s->reg_data[addr] = value & 0x1f;\r
+            break;\r
+        case 0xd8: /* VUSB_DEDICATED1 */\r
+            s->reg_data[addr] = value & 0x1f;\r
+            break;\r
+        case 0xd9: /* VUSB_DEDICATED2 */\r
+            s->reg_data[addr] = value & 0x08;\r
+            break;\r
+            \r
         default:\r
 #ifdef VERBOSE\r
-               printf("%s: unknown register %02x pc %x \n", __FUNCTION__, addr,cpu_single_env->regs[15] );\r
-               //printf("%s: unknown register %02x \n", __FUNCTION__, addr);\r
+               fprintf(stderr, "%s: unknown register %02x value %0x pc %x \n", __FUNCTION__, \r
+                    addr, value, cpu_single_env->regs[15]);\r
 #endif\r
             exit(-1);\r
             break;\r
@@ -380,7 +609,7 @@ static int twl4030_4b_tx(i2c_slave *i2c, uint8_t data)
         s->reg = data;\r
         s->firstbyte = 0;\r
     } else\r
-        twl4030_4b_write(s, s->reg ++, data);\r
+        twl4030_4b_write(s, s->reg++, data);\r
        \r
     return 1;\r
 }\r
@@ -389,13 +618,16 @@ static int twl4030_4b_rx(i2c_slave *i2c)
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
        \r
-    return twl4030_4b_read(s, s->reg ++);\r
+    return twl4030_4b_read(s, s->reg++);\r
 }\r
 \r
 static void twl4030_4b_reset(i2c_slave *i2c)\r
 {\r
     struct twl4030_i2c_s *s = (struct twl4030_i2c_s *) i2c;\r
     s->reg = 0x00;\r
+    memcpy(s->reg_data, addr_4b_reset_values, 256);\r
+    s->twl4030->key_cfg = 0;\r
+    s->twl4030->key_tst = 0;\r
 }\r
 \r
 static void twl4030_4b_event(i2c_slave *i2c, enum i2c_event event)\r