~ubuntu-branches/ubuntu/saucy/qemu/saucy

« back to all changes in this revision

Viewing changes to debian/patches/patches-arm-1.4.0/0049-Add-triton2-twl4030-driver.patch

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
From 70fcbbed0057225cb301a3d2ae1d8d1889f60195 Mon Sep 17 00:00:00 2001
2
 
From: Peter Maydell <peter.maydell@linaro.org>
3
 
Date: Mon, 18 Feb 2013 16:58:31 +0000
4
 
Subject: [PATCH 49/77] Add triton2 (twl4030) driver
5
 
MIME-Version: 1.0
6
 
Content-Type: text/plain; charset=UTF-8
7
 
Content-Transfer-Encoding: 8bit
8
 
 
9
 
The swiss knife companion chip for omap3
10
 
 
11
 
includes change from Loïc Minier <lool@dooz.org>:
12
 
twl4030: Add PWMB OFF and ON regs
13
 
twl4030: add SW2 conversion channels
14
 
includes change from PMM: add dummy BCISIHCTRL
15
 
includes change from Riku: add carkit analog control registers
16
 
includes change from Riku: add rtc alarm and periodic interrupts
17
 
includes: twl4030: add callback for providing madc results
18
 
 
19
 
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
20
 
Signed-off-by: Riku Voipo <riku.voipio@nokia.com>
21
 
Signed-off-by: Loïc Minier <lool@dooz.org>
22
 
---
23
 
 hw/arm/Makefile.objs |    1 +
24
 
 hw/i2c.h             |   19 +
25
 
 hw/twl4030.c         | 1808 ++++++++++++++++++++++++++++++++++++++++++++++++++
26
 
 3 files changed, 1828 insertions(+)
27
 
 create mode 100644 hw/twl4030.c
28
 
 
29
 
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
30
 
index b8bc7aa..3e9cfd7 100644
31
 
--- a/hw/arm/Makefile.objs
32
 
+++ b/hw/arm/Makefile.objs
33
 
@@ -20,6 +20,7 @@ obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
34
 
 obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
35
 
                 omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
36
 
 obj-y += omap3.o omap_usb.o omap3_boot.o omap3_mmc.o dsi.o
37
 
+obj-y += twl4030.o
38
 
 obj-y += omap_sx1.o palm.o tsc210x.o
39
 
 obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
40
 
 obj-y += mst_fpga.o mainstone.o
41
 
diff --git a/hw/i2c.h b/hw/i2c.h
42
 
index 0e80d5a..0eba883 100644
43
 
--- a/hw/i2c.h
44
 
+++ b/hw/i2c.h
45
 
@@ -75,6 +75,25 @@ void wm8750_set_bclk_in(void *opaque, int new_hz);
46
 
 /* lm832x.c */
47
 
 void lm832x_key_event(DeviceState *dev, int key, int state);
48
 
 
49
 
+/* twl4030.c */
50
 
+typedef struct {
51
 
+    int code;
52
 
+    int column;
53
 
+    int row;
54
 
+} TWL4030KeyMap;
55
 
+typedef enum twl4030_adc_type {
56
 
+    TWL4030_ADC_RT,
57
 
+    TWL4030_ADC_GP,
58
 
+    TWL4030_ADC_BCI
59
 
+} twl4030_adc_type;
60
 
+typedef uint16_t (*twl4030_madc_callback)(twl4030_adc_type type, int ch);
61
 
+void *twl4030_init(i2c_bus *bus, qemu_irq irq1, qemu_irq irq2,
62
 
+                   const TWL4030KeyMap *keymap);
63
 
+void *twl5031_init(i2c_bus *bus, qemu_irq irq1, qemu_irq irq2,
64
 
+                   const TWL4030KeyMap *keymap);
65
 
+void twl4030_set_powerbutton_state(void *opaque, int pressed);
66
 
+void twl4030_madc_attach(void *opaque, twl4030_madc_callback cb);
67
 
+
68
 
 extern const VMStateDescription vmstate_i2c_slave;
69
 
 
70
 
 #define VMSTATE_I2C_SLAVE(_field, _state) {                          \
71
 
diff --git a/hw/twl4030.c b/hw/twl4030.c
72
 
new file mode 100644
73
 
index 0000000..27e19e9
74
 
--- /dev/null
75
 
+++ b/hw/twl4030.c
76
 
@@ -0,0 +1,1808 @@
77
 
+/*
78
 
+ * TI TWL4030 emulation
79
 
+ *
80
 
+ * Copyright (C) 2008 yajin<yajin@vm-kernel.org>
81
 
+ * Copyright (C) 2009-2010 Nokia Corporation
82
 
+ *
83
 
+ * Register implementation based on TPS65950 ES1.0 specification.
84
 
+ *
85
 
+ * This program is free software; you can redistribute it and/or
86
 
+ * modify it under the terms of the GNU General Public License as
87
 
+ * published by the Free Software Foundation; either version 2 or
88
 
+ * (at your option) version 3 of the License.
89
 
+ *
90
 
+ * This program is distributed in the hope that it will be useful,
91
 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
92
 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
93
 
+ * GNU General Public License for more details.
94
 
+ *
95
 
+ * You should have received a copy of the GNU General Public License
96
 
+ * along with this program; if not, write to the Free Software
97
 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
98
 
+ * MA 02111-1307 USA
99
 
+ */
100
 
+
101
 
+#include <sys/time.h>
102
 
+#include "hw.h"
103
 
+#include "qemu/timer.h"
104
 
+#include "i2c.h"
105
 
+#include "sysemu/sysemu.h"
106
 
+#include "ui/console.h"
107
 
+#include "exec/cpu-all.h"
108
 
+
109
 
+//#define DEBUG_GENERAL
110
 
+//#define DEBUG_RTC
111
 
+
112
 
+#define DEBUG_TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", \
113
 
+                                      __FUNCTION__, __LINE__, ##__VA_ARGS__)
114
 
+
115
 
+#ifdef DEBUG_GENERAL
116
 
+#define TRACE(...) DEBUG_TRACE(__VA_ARGS__)
117
 
+#else
118
 
+#define TRACE(...)
119
 
+#endif
120
 
+
121
 
+#ifdef DEBUG_RTC
122
 
+#define TRACE_RTC(...) DEBUG_TRACE(__VA_ARGS__)
123
 
+#else
124
 
+#define TRACE_RTC(...)
125
 
+#endif
126
 
+
127
 
+typedef struct TWL4030State TWL4030State;
128
 
+typedef struct TWL4030NodeState TWL4030NodeState;
129
 
+
130
 
+typedef uint8_t (*twl4030_read_func)(TWL4030NodeState *s,
131
 
+                                     uint8_t addr);
132
 
+typedef void (*twl4030_write_func)(TWL4030NodeState *s,
133
 
+                                   uint8_t addr, uint8_t value);
134
 
+
135
 
+struct TWL4030NodeState {
136
 
+    I2CSlave i2c;
137
 
+    int firstbyte;
138
 
+    uint8_t reg;
139
 
+
140
 
+    twl4030_read_func read_func;
141
 
+    twl4030_write_func write_func;
142
 
+    TWL4030State *twl4030;
143
 
+
144
 
+    uint8 reg_data[256];
145
 
+};
146
 
+
147
 
+struct TWL4030State {
148
 
+    qemu_irq irq1;
149
 
+    qemu_irq irq2;
150
 
+    QEMUTimer *alarm_timer;
151
 
+    QEMUTimer *periodic_timer;
152
 
+    const TWL4030KeyMap *keymap;
153
 
+    int extended_key;
154
 
+    uint8_t twl5031;
155
 
+    uint8_t twl5031_aciid;
156
 
+    twl4030_madc_callback madc_cb;
157
 
+
158
 
+    int key_cfg;
159
 
+    int key_tst;
160
 
+
161
 
+    TWL4030NodeState *i2c[4];
162
 
+
163
 
+    uint8_t seq_mem[64][4]; /* power-management sequencing memory */
164
 
+};
165
 
+
166
 
+static const uint8_t addr_48_reset_values[256] = {
167
 
+    0x51, 0x04, 0x02, 0xc0, 0x41, 0x41, 0x41, 0x10, /* 0x00...0x07 */
168
 
+    0x10, 0x10, 0x06, 0x06, 0x06, 0x1f, 0x1f, 0x1f, /* 0x08...0x0f */
169
 
+    0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
170
 
+    0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, /* 0x18...0x1f */
171
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0a, 0x03, /* 0x20...0x27 */
172
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
173
 
+    0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, /* 0x30...0x37 */
174
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
175
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
176
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
177
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
178
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
179
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
180
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
181
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
182
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
183
 
+    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, /* 0x80...0x87 */
184
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
185
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90...0x97 */
186
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
187
 
+    0x00, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
188
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
189
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
190
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8...0xb8 */
191
 
+    0xa0, 0xa0, 0x64, 0x7f, 0x6c, 0x75, 0x64, 0x20, /* 0xc0...0xc7 */
192
 
+    0x01, 0x17, 0x01, 0x02, 0x00, 0x36, 0x44, 0x07, /* 0xc8...0xcf */
193
 
+    0x3b, 0x17, 0x6b, 0x04, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
194
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
195
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
196
 
+    0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
197
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
198
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00  /* 0xf8...0xff */
199
 
+};
200
 
+
201
 
+static const uint8_t addr_49_reset_values[256] = {
202
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
203
 
+    0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, /* 0x08...0x0f */
204
 
+    0x3f, 0x3f, 0x3f, 0x3f, 0x25, 0x00, 0x00, 0x00, /* 0x10...0x17 */
205
 
+    0x00, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x55, /* 0x18...0x1f */
206
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
207
 
+    0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
208
 
+    0x13, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x00, /* 0x30...0x37 */
209
 
+    0x00, 0x00, 0x06, 0x00, 0x44, 0x69, 0x00, 0x00, /* 0x38...0x3f */
210
 
+    0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, /* 0x40...0x47 */
211
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
212
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
213
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
214
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60...0x67 */
215
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
216
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
217
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
218
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80...0x87 */
219
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88...0x8f */
220
 
+    0x00, 0x90, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, /* 0x90...0x97 */
221
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98...0x9f */
222
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
223
 
+    0x00, 0x00, 0x04, 0x00, 0x55, 0x01, 0x55, 0x05, /* 0xa8...0xaf */
224
 
+    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, /* 0xb0...0xb7 */
225
 
+    0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, /* 0xb8...0xbf */
226
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* 0xc0...0xc7 */
227
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
228
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
229
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
230
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0...0xe7 */
231
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
232
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
233
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8...0xff */
234
 
+};
235
 
+
236
 
+static const uint8_t addr_4a_reset_values[256] = {
237
 
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
238
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
239
 
+    0xc0, 0x8c, 0xde, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
240
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18...0x1f */
241
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20...0x27 */
242
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28...0x2f */
243
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30...0x37 */
244
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38...0x3f */
245
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
246
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48...0x4f */
247
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50...0x57 */
248
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
249
 
+    0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x55, 0x07, /* 0x60...0x67 */
250
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
251
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70...0x77 */
252
 
+    0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78...0x7f */
253
 
+    0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, /* 0x80...0x87 */
254
 
+    0x00, 0x68, 0x9b, 0x86, 0x48, 0x2a, 0x07, 0x28, /* 0x88...0x8f */
255
 
+    0x09, 0x69, 0x90, 0x00, 0x2a, 0x00, 0x02, 0x00, /* 0x90...0x97 */
256
 
+    0x10, 0xcd, 0x02, 0x68, 0x03, 0x00, 0x00, 0x00, /* 0x98...0x9f */
257
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0...0xa7 */
258
 
+    0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
259
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
260
 
+    0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, /* 0xb8...0xbf */
261
 
+    0x0f, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x01, 0x00, /* 0xc0...0xc7 */
262
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8...0xcf */
263
 
+    0x00, 0x00, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, /* 0xd0...0xd7 */
264
 
+    0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8...0xdf */
265
 
+    0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x00, /* 0xe0...0xe7 */
266
 
+    0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8...0xef */
267
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
268
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */
269
 
+};
270
 
+
271
 
+static const uint8_t addr_4b_reset_values[256] = {
272
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00...0x07 */
273
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08...0x0f */
274
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10...0x17 */
275
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x18...0x1f */
276
 
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, /* 0x20...0x27 */
277
 
+    0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, /* 0x28...0x2f */
278
 
+    0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0xbf, 0xbf, /* 0x30...0x37 */
279
 
+    0xbf, 0xab, 0x00, 0x08, 0x3f, 0x15, 0x40, 0x0e, /* 0x38...0x3f */
280
 
+    0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40...0x47 */
281
 
+    0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, /* 0x48...0x4f */
282
 
+    0x00, 0x02, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x00, /* 0x50...0x57 */
283
 
+    0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58...0x5f */
284
 
+    0x00, 0x00, 0x2f, 0x18, 0x0f, 0x08, 0x0f, 0x08, /* 0x60...0x67 */
285
 
+    0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68...0x6f */
286
 
+    0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x80, 0x03, /* 0x70...0x77 */
287
 
+    0x08, 0x09, 0x00, 0x00, 0x08, 0x03, 0x80, 0x03, /* 0x78...0x7f */
288
 
+    0x08, 0x02, 0x00, 0x00, 0x08, 0x00, 0x80, 0x03, /* 0x80...0x87 */
289
 
+    0x08, 0x08, 0x20, 0x00, 0x00, 0x02, 0x80, 0x04, /* 0x88...0x8f */
290
 
+    0x08, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, /* 0x90...0x97 */
291
 
+    0x08, 0x02, 0xe0, 0x01, 0x08, 0x00, 0xe0, 0x00, /* 0x98...0x9f */
292
 
+    0x08, 0x01, 0xe0, 0x01, 0x08, 0x04, 0xe0, 0x03, /* 0xa0...0xa7 */
293
 
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8...0xaf */
294
 
+    0x20, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0...0xb7 */
295
 
+    0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, /* 0xb8...0xbf */
296
 
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, /* 0xc0...0xc7 */
297
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, /* 0xc8...0xcf */
298
 
+    0x00, 0x08, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, /* 0xd0...0xd7 */
299
 
+    0x14, 0x08, 0xe0, 0x02, 0x08, 0xe0, 0x00, 0x08, /* 0xd8...0xdf */
300
 
+    0xe0, 0x05, 0x08, 0xe0, 0x06, 0x08, 0xe0, 0x00, /* 0xe0...0xe7 */
301
 
+    0x08, 0xe0, 0x00, 0x08, 0xe0, 0x06, 0x06, 0xe0, /* 0xe8...0xef */
302
 
+    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0...0xf7 */
303
 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* 0xf8...0xff */
304
 
+};
305
 
+
306
 
+static void twl4030_interrupt_update(TWL4030State *s)
307
 
+{
308
 
+    uint8_t x = 0;
309
 
+    /* TODO: USB, BCI and GPIO interrupts */
310
 
+    if (s->irq1) {
311
 
+        /* KEYPAD */
312
 
+        if (((s->i2c[2]->reg_data[0xda] & 0x10) && /* SIR_EN */
313
 
+             s->i2c[2]->reg_data[0xe7]) ||         /* KEYP_SIR */
314
 
+            (s->i2c[2]->reg_data[0xe3] &           /* KEYP_ISR1 */
315
 
+             ~s->i2c[2]->reg_data[0xe4]))          /* KEYP_IMR1 */
316
 
+            x |= 0x02;                             /* PIH_ISR1 */
317
 
+        /* MADC */
318
 
+        if (s->i2c[2]->reg_data[0x65] ||           /* MADC_SIR */
319
 
+            (s->i2c[2]->reg_data[0x61] &           /* MADC_ISR1 */
320
 
+             ~s->i2c[2]->reg_data[0x62]))          /* MADC_IMR1 */
321
 
+            x |= 0x08;                             /* PIH_ISR3 */
322
 
+        /* PM */
323
 
+        if ((s->i2c[3]->reg_data[0x2e] &           /* PWR_ISR1 */
324
 
+             ~s->i2c[3]->reg_data[0x2f]))          /* PWR_IMR1 */
325
 
+            x |= 0x20;                             /* PIH_ISR5 */
326
 
+
327
 
+        s->i2c[1]->reg_data[0x81] = x;             /* PIH_ISR_P1 */
328
 
+        qemu_set_irq(s->irq1, x);
329
 
+    }
330
 
+    if (s->irq2) {
331
 
+        /* KEYPAD */
332
 
+        if (((s->i2c[2]->reg_data[0xda] & 0x10) && /* SIR_EN */
333
 
+             s->i2c[2]->reg_data[0xe7]) ||         /* KEYP_SIR */
334
 
+            (s->i2c[2]->reg_data[0xe5] &           /* KEYP_ISR2 */
335
 
+             ~s->i2c[2]->reg_data[0xe6]))          /* KEYP_IMR2 */
336
 
+            x |= 0x02;                             /* PIH_ISR1 */
337
 
+        /* MADC */
338
 
+        if (s->i2c[2]->reg_data[0x65] ||           /* MADC_SIR */
339
 
+            (s->i2c[2]->reg_data[0x63] &           /* MADC_ISR2 */
340
 
+             ~s->i2c[2]->reg_data[0x64]))          /* MADC_IMR2 */
341
 
+            x |= 0x08;                             /* PIH_ISR3 */
342
 
+        /* PM */
343
 
+        if ((s->i2c[3]->reg_data[0x30] &           /* PWR_ISR2 */
344
 
+             ~s->i2c[3]->reg_data[0x31]))          /* PWR_IMR2 */
345
 
+            x |= 0x20;                             /* PIH_ISR5 */
346
 
+
347
 
+        s->i2c[1]->reg_data[0x82] = x;             /* PIH_ISR_P2 */
348
 
+        qemu_set_irq(s->irq2, x);
349
 
+    }
350
 
+}
351
 
+
352
 
+static uint8_t twl4030_48_read(TWL4030NodeState *s, uint8_t addr)
353
 
+{
354
 
+    TRACE("addr=0x%02x", addr);
355
 
+    switch (addr) {
356
 
+        case 0x00: /* VENDOR_ID_LO */
357
 
+        case 0x01: /* VENDOR_ID_HI */
358
 
+        case 0x02: /* PRODUCT_ID_LO */
359
 
+        case 0x03: /* PRODUCT_ID_HI */
360
 
+            return s->reg_data[addr];
361
 
+        case 0x04: /* FUNC_CTRL */
362
 
+        case 0x05: /* FUNC_CRTL_SET */
363
 
+        case 0x06: /* FUNC_CRTL_CLR */
364
 
+            return s->reg_data[0x04];
365
 
+        case 0x07: /* IFC_CTRL */
366
 
+        case 0x08: /* IFC_CRTL_SET */
367
 
+        case 0x09: /* IFC_CRTL_CLR */
368
 
+            return s->reg_data[0x07];
369
 
+        case 0x13: /* USB_INT_STS */
370
 
+        case 0x16: /* SCRATCH_REG */
371
 
+            return s->reg_data[addr];
372
 
+        case 0xac: /* POWER_CTRL */
373
 
+        case 0xad: /* POWER_SET */
374
 
+        case 0xae: /* POWER_CLR */
375
 
+            return s->reg_data[0xac];
376
 
+        case 0xbb: /* CARKIT_AND_CTRL */
377
 
+        case 0xbc: /* CARKIT_ANA_SET */
378
 
+        case 0xbd: /* CARKIT_ANA_CLR */
379
 
+            return s->reg_data[0xbb];
380
 
+        case 0xfd: /* PHY_PWR_CTRL */
381
 
+        case 0xfe: /* PHY_CLK_CTRL */
382
 
+            return s->reg_data[addr];
383
 
+        case 0xff: /* PHY_CLK_CTRL_STS */
384
 
+            if (s->reg_data[0xfd] & 1) /* PHY_PWR_CTRL */
385
 
+                return 0;
386
 
+            if (s->reg_data[0xfe] & 1) /* REQ_PHY_DPLL_CLK */
387
 
+                return 1;
388
 
+            return (s->reg_data[0x04] >> 6) & 1; /* SUSPENDM */
389
 
+        default:
390
 
+            hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
391
 
+            break;
392
 
+    }
393
 
+    return 0;
394
 
+}
395
 
+
396
 
+static void twl4030_48_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
397
 
+{
398
 
+    TRACE("addr=0x%02x, value=0x%02x", addr, value);
399
 
+    switch (addr) {
400
 
+        case 0x04: /* FUNC_CTRL */
401
 
+            s->reg_data[0x04] = value & 0x7f;
402
 
+            break;
403
 
+        case 0x05: /* FUNC_CRTL_SET */
404
 
+            s->reg_data[0x04] = (s->reg_data[0x04] | value) & 0x7f;
405
 
+            break;
406
 
+        case 0x06: /* FUNC_CTRL_CLEAR */
407
 
+            s->reg_data[0x04] = (s->reg_data[0x04] & ~value) & 0x7f;
408
 
+            break;
409
 
+        case 0x07: /* IFC_CTRL */
410
 
+            s->reg_data[0x07] = value & 0x9e;
411
 
+            break;
412
 
+        case 0x08: /* IFC_CRTL_SET */
413
 
+            s->reg_data[0x07] = (s->reg_data[0x07] | value) & 0x9e;
414
 
+            break;
415
 
+        case 0x09: /* IFC_CRTL_CLEAR */
416
 
+            s->reg_data[0x07] = (s->reg_data[0x07] & ~value) & 0x9e;
417
 
+            break;
418
 
+        case 0x16: /* SCRATCH_REG */
419
 
+            s->reg_data[0x16] = value;
420
 
+            break;
421
 
+        case 0xa1: /* CARKIT_SM_CTRL */
422
 
+            s->reg_data[0xa1] = value & 0x3f;
423
 
+            break;
424
 
+        case 0xa2: /* CARKIT_SM_CTRL_SET */
425
 
+            s->reg_data[0xa1] = (s->reg_data[0xa1] | value) & 0x3f;
426
 
+            break;
427
 
+        case 0xa3: /* CARKIT_SM_CTRL_CLR */
428
 
+            s->reg_data[0xa1] = (s->reg_data[0xa1] & ~value) & 0x3f;
429
 
+            break;
430
 
+        case 0xac: /* POWER_CTRL */
431
 
+            s->reg_data[0xac] = value & 0x20;
432
 
+            break;
433
 
+        case 0xad: /* POWER_SET */
434
 
+            s->reg_data[0xac] = (s->reg_data[0xac] | value) & 0x20;
435
 
+            break;
436
 
+        case 0xae: /* POWER_CLEAR */
437
 
+            s->reg_data[0xac] = (s->reg_data[0xac] & ~value) & 0x20;
438
 
+            break;
439
 
+        case 0xbb: /* CARKIT_ANA_CTRL */
440
 
+            s->reg_data[0xbb] = value;
441
 
+            break;
442
 
+        case 0xbc: /* CARKIT_ANA_CTRL_SET */
443
 
+            s->reg_data[0xbb] |= value;
444
 
+            break;
445
 
+        case 0xbd: /* CARKIT_ANA_CTRL_CLR */
446
 
+            s->reg_data[0xbb] &= ~value;
447
 
+            break;
448
 
+        case 0xfd: /* PHY_PWR_CTRL */
449
 
+            s->reg_data[addr] = value & 0x1;
450
 
+            break;
451
 
+        case 0xfe: /* PHY_CLK_CTRL */
452
 
+            s->reg_data[addr] = value & 0x7;
453
 
+            break;
454
 
+        default:
455
 
+            hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
456
 
+                       break;
457
 
+    }
458
 
+}
459
 
+
460
 
+static uint8_t twl4030_49_read(TWL4030NodeState *s, uint8_t addr)
461
 
+{
462
 
+    TRACE("addr=0x%02x", addr);
463
 
+    switch (addr) {
464
 
+        /* AUDIO_VOICE region */
465
 
+        case 0x01 ... 0x49:
466
 
+            return s->reg_data[addr];
467
 
+        /* Test region */
468
 
+        case 0x4c ... 0x60:
469
 
+            return s->reg_data[addr];
470
 
+        /* PIH region */
471
 
+        case 0x81: /* PIH_ISR_P1 */
472
 
+        case 0x82: /* PIH_ISR_P2 */
473
 
+        case 0x83: /* PIH_SIR */
474
 
+            return s->reg_data[addr];
475
 
+        /* INTBR region */
476
 
+        case 0x85 ... 0x90:
477
 
+            if (s->reg_data[0x97] != 0x49) {
478
 
+                return 0;
479
 
+            }
480
 
+            /* fallthrough */
481
 
+        case 0x91 ... 0x97:
482
 
+            return s->reg_data[addr];
483
 
+        /* GPIO region */
484
 
+        case 0x98 ... 0xc5:
485
 
+            return s->reg_data[addr];
486
 
+        default:
487
 
+            hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
488
 
+                       break;
489
 
+    }
490
 
+    return 0;
491
 
+}
492
 
+
493
 
+static void twl4030_49_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
494
 
+{
495
 
+    TRACE("addr=0x%02x, value=0x%02x", addr, value);
496
 
+    switch (addr) {
497
 
+        /* AUDIO_VOICE region */
498
 
+        case 0x01 ... 0x49:
499
 
+            s->reg_data[addr] = value;
500
 
+            break;
501
 
+        /* Test region */
502
 
+        case 0x4c ... 0x59:
503
 
+            s->reg_data[addr] = value;
504
 
+            break;
505
 
+        case 0x5a ... 0x60:
506
 
+            /* read-only, ignore */
507
 
+            break;
508
 
+        /* PIH region */
509
 
+        case 0x81: /* PIH_ISR_P1 */
510
 
+        case 0x82: /* PIH_ISR_P2 */
511
 
+        case 0x83: /* PIH_SIR */
512
 
+            s->reg_data[addr] = value;
513
 
+            twl4030_interrupt_update(s->twl4030);
514
 
+            break;
515
 
+        /* INTBR region */
516
 
+        case 0x85 ... 0x90:
517
 
+            /* read-only, ignore */
518
 
+            break;
519
 
+        case 0x91 ... 0x97:
520
 
+            s->reg_data[addr] = value;
521
 
+            break;
522
 
+        /* GPIO region */
523
 
+        case 0x98 ... 0x9a:
524
 
+            /* read-only, ignore */
525
 
+            break;
526
 
+        case 0x9b ... 0xae:
527
 
+            s->reg_data[addr] = value;
528
 
+            break;
529
 
+        case 0xaf: /* GPIOPUPDCTR5 */
530
 
+            s->reg_data[addr] = value & 0x0f;
531
 
+            break;
532
 
+        case 0xb0 ... 0xb5:
533
 
+            s->reg_data[addr] = value;
534
 
+            break;
535
 
+           case 0xb6: /* GPIO_IMR3A */
536
 
+            s->reg_data[addr] = value & 0x03;
537
 
+            break;
538
 
+        case 0xb7 ... 0xc4:
539
 
+            s->reg_data[addr] = value;
540
 
+            break;
541
 
+           case 0xc5: /* GPIO_SIH_CTRL */
542
 
+            s->reg_data[addr] = value & 0x07;
543
 
+            break;
544
 
+        default:
545
 
+            hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
546
 
+            break;
547
 
+    }
548
 
+}
549
 
+
550
 
+static uint8_t twl4030_4a_read(TWL4030NodeState *s, uint8_t addr)
551
 
+{
552
 
+    static const uint8_t twl5031_aciid_data[] = {
553
 
+        0x55, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
554
 
+    };
555
 
+    TRACE("addr=0x%02x", addr);
556
 
+    switch (addr) {
557
 
+        /* MADC region */
558
 
+        case 0x00 ... 0x13:
559
 
+        case 0x62:
560
 
+        case 0x64 ... 0x67:
561
 
+            return s->reg_data[addr];
562
 
+        case 0x17 ... 0x36: /* RT conversion result */
563
 
+            if (s->twl4030->madc_cb) {
564
 
+                uint16_t x = s->twl4030->madc_cb(TWL4030_ADC_RT,
565
 
+                                                 (addr - 0x17) >> 1);
566
 
+                return (addr & 1) ? (uint8_t)((x & 3) << 6)
567
 
+                                  : (uint8_t)((x >> 2) & 0xff);
568
 
+            }
569
 
+            return s->reg_data[addr];
570
 
+        case 0x37 ... 0x56: /* GP conversion result */
571
 
+            if (s->twl4030->madc_cb) {
572
 
+                uint16_t x = s->twl4030->madc_cb(TWL4030_ADC_GP,
573
 
+                                                 (addr - 0x37) >> 1);
574
 
+                return (addr & 1) ? (uint8_t)((x & 3) << 6)
575
 
+                                  : (uint8_t)((x >> 2) & 0xff);
576
 
+            }
577
 
+            return s->reg_data[addr];
578
 
+        case 0x57 ... 0x60: /* BCI conversion result */
579
 
+            if (s->twl4030->madc_cb) {
580
 
+                uint16_t x = s->twl4030->madc_cb(TWL4030_ADC_BCI,
581
 
+                                                 (addr - 0x57) >> 1);
582
 
+                return (addr & 1) ? (uint8_t)((x & 3) << 6)
583
 
+                                  : (uint8_t)((x >> 2) & 0xff);
584
 
+            }
585
 
+            return s->reg_data[addr];
586
 
+        case 0x61: /* MADC_ISR1 */
587
 
+        case 0x63: /* MADC_ISR2 */
588
 
+            {
589
 
+                uint8_t data = s->reg_data[addr];
590
 
+                if (s->reg_data[0x67] & 0x04) { /* COR */
591
 
+                    s->reg_data[addr] = 0x00;
592
 
+                    twl4030_interrupt_update(s->twl4030);
593
 
+                }
594
 
+                return data;
595
 
+            }
596
 
+        /* MAIN_CHARGE(TWL4030) / ACCESSORY(TWL5031) region */
597
 
+        case 0x74 ... 0xa9:
598
 
+            if (s->twl4030->twl5031) {
599
 
+                switch (addr) {
600
 
+                    case 0x74: /* ACIID */
601
 
+                        if (s->twl4030->twl5031_aciid >=
602
 
+                            sizeof(twl5031_aciid_data)) {
603
 
+                            s->twl4030->twl5031_aciid = 0;
604
 
+                        }
605
 
+                        return twl5031_aciid_data[s->twl4030->twl5031_aciid++];
606
 
+                    case 0x79: /* ACIIMR_LSB */
607
 
+                    case 0x7a: /* ACIIMR_MSB */
608
 
+                    case 0x7b: /* ACIIDR_LSB */
609
 
+                    case 0x7c: /* ACIIDR_MSB */
610
 
+                    case 0x80: /* AV_CTRL */
611
 
+                    case 0x82: /* BCIA_CTRL */
612
 
+                    case 0x83: /* ACCISR1 */
613
 
+                        return s->reg_data[addr];
614
 
+                    default:
615
 
+                        hw_error("%s: unknown twl5031 register 0x%02x",
616
 
+                                 __FUNCTION__, addr);
617
 
+                        break;
618
 
+                }
619
 
+            }
620
 
+            return s->reg_data[addr];
621
 
+        /* PRECHARGE region */
622
 
+        case 0xaa ... 0xb8:
623
 
+            return s->reg_data[addr];
624
 
+        /* Interrupt region */
625
 
+        case 0xb9 ... 0xc6:
626
 
+            return s->reg_data[addr];
627
 
+        /* KEYPAD region */
628
 
+        case 0xd2 ... 0xe2:
629
 
+        case 0xe4:
630
 
+        case 0xe6 ... 0xe9:
631
 
+            return s->reg_data[addr];
632
 
+        case 0xe3: /* KEYP_ISR1 */
633
 
+        case 0xe5: /* KEYP_ISR2 */
634
 
+            {
635
 
+                uint8_t data = s->reg_data[addr];
636
 
+                if (s->reg_data[0xe9] & 0x04) { /* COR */
637
 
+                    s->reg_data[addr] = 0x00;
638
 
+                    twl4030_interrupt_update(s->twl4030);
639
 
+                }
640
 
+                return data;
641
 
+            }
642
 
+        /* LED region */
643
 
+        case 0xee: /* LEDEN */
644
 
+            return s->reg_data[addr];
645
 
+        /* PWMA region */
646
 
+        case 0xef: /* PWMAON */
647
 
+        case 0xf0: /* PWMAOFF */
648
 
+            return s->reg_data[addr];
649
 
+        /* PWMB region */
650
 
+        case 0xf1: /* PWMBON */
651
 
+        case 0xf2: /* PWMBOFF */
652
 
+            return s->reg_data[addr];
653
 
+        /* PWM0 region */
654
 
+        case 0xf8: /* PWM0ON */
655
 
+        case 0xf9: /* PWM0OFF */
656
 
+            return s->reg_data[addr];
657
 
+        /* PWM1 region */
658
 
+        case 0xfb: /* PWM1ON */
659
 
+        case 0xfc: /* PWM1OFF */
660
 
+            return s->reg_data[addr];
661
 
+        default:
662
 
+               hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
663
 
+            break;
664
 
+    }
665
 
+    return 0;
666
 
+}
667
 
+
668
 
+static void twl4030_4a_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
669
 
+{
670
 
+    TRACE("addr=0x%02x, value=0x%02x", addr, value);
671
 
+    switch (addr) {
672
 
+        /* MADC region */
673
 
+
674
 
+        case 0x00: /* CTRL1 */
675
 
+        case 0x01: /* CTRL2 */
676
 
+            s->reg_data[addr] = value;
677
 
+            break;
678
 
+        case 0x06: /* SW1SELECT_LSB */
679
 
+        case 0x07: /* SW1SELECT_MSB */
680
 
+        case 0x08: /* SW1AVERAGE_LSB */
681
 
+        case 0x09: /* SW1AVERAGE_MSB */
682
 
+        case 0x0a: /* SW2SELECT_LSB */
683
 
+        case 0x0b: /* SW2SELECT_MSB */
684
 
+        case 0x0c: /* SW2AVERAGE_LSB */
685
 
+        case 0x0d: /* SW2AVERAGE_MSB */
686
 
+            s->reg_data[addr] = value;
687
 
+            break;
688
 
+        case 0x12: /* CTRL_SW1 */
689
 
+        case 0x13: /* CTRL_SW2 */
690
 
+            /* always set all conversions ready, not busy */
691
 
+            s->reg_data[addr] = 0x3e;
692
 
+            if (value & 0x20) { /* SW1/SW2 */
693
 
+                s->reg_data[0x61] |= 2 << (addr - 0x12); /* SW1_ISR/SW2_ISR */
694
 
+                s->reg_data[0x63] |= 2 << (addr - 0x12); /* SW1_ISR/SW2_ISR */
695
 
+                twl4030_interrupt_update(s->twl4030);
696
 
+            }
697
 
+            break;
698
 
+        case 0x17 ... 0x60: /* conversion results */
699
 
+            /* read-only, ignore */
700
 
+            break;
701
 
+        case 0x61: /* MADC_ISR1 */
702
 
+        case 0x63: /* MADC_ISR2 */
703
 
+            if (!(s->reg_data[0x67] & 0x04)) { /* COR */
704
 
+                s->reg_data[addr] &= ~(value & 0x0f);
705
 
+                twl4030_interrupt_update(s->twl4030);
706
 
+            }
707
 
+            break;
708
 
+        case 0x62: /* MADC_IMR1 */
709
 
+        case 0x64: /* MADC_IMR2 */
710
 
+        case 0x65: /* MADC_SIR */
711
 
+            s->reg_data[addr] = value & 0x0f;
712
 
+            twl4030_interrupt_update(s->twl4030);
713
 
+            break;
714
 
+        case 0x66: /* MADC_EDR */
715
 
+            s->reg_data[addr] = value;
716
 
+            break;
717
 
+        case 0x67: /* MADC_SIH_CTRL */
718
 
+            s->reg_data[addr] = value & 0x07;
719
 
+            break;
720
 
+
721
 
+        /* MAIN_CHARGE(TWL4030) / ACCESSORY(TWL5031) region */
722
 
+
723
 
+        case 0x74: /* BCIMDEN(TWL4030) / ACIID(TWL5031) */
724
 
+            if (s->twl4030->twl5031) {
725
 
+                s->twl4030->twl5031_aciid = 0;
726
 
+            } else {
727
 
+                /* read-only */
728
 
+            }
729
 
+            break;
730
 
+        case 0x75: /* BCIMDKEY(TWL4030) / ACICOMR_LSB(TWL5031) */
731
 
+            s->reg_data[addr] = value;
732
 
+            if (!s->twl4030->twl5031) {
733
 
+                switch (value) {
734
 
+                    case 0x25: s->reg_data[0x74] = 0x12; break;
735
 
+                    case 0x26: s->reg_data[0x74] = 0x11; break;
736
 
+                    case 0x27: s->reg_data[0x74] = 0x0a; break;
737
 
+                    case 0x28: s->reg_data[0x74] = 0x06; break;
738
 
+                    case 0x29: s->reg_data[0x74] = 0x05; break;
739
 
+                    default: s->reg_data[0x74] = 0; break;
740
 
+                }
741
 
+            }
742
 
+            break;
743
 
+        case 0x76 ... 0x84:
744
 
+            if (s->twl4030->twl5031) {
745
 
+                switch (addr) {
746
 
+                    case 0x79: /* ACIIMR_LSB */
747
 
+                        s->reg_data[addr] = value;
748
 
+                        twl4030_interrupt_update(s->twl4030);
749
 
+                        break;
750
 
+                    case 0x7a: /* ACIIMR_MSB */
751
 
+                        s->reg_data[addr] = value & 0x01;
752
 
+                        twl4030_interrupt_update(s->twl4030);
753
 
+                        break;
754
 
+                    case 0x7b: /* ACIIDR_LSB */
755
 
+                        s->reg_data[addr] &= ~value;
756
 
+                        twl4030_interrupt_update(s->twl4030);
757
 
+                        break;
758
 
+                    case 0x7c: /* ACIIDR_MSB */
759
 
+                        s->reg_data[addr] &= ~(value & 0x01);
760
 
+                        twl4030_interrupt_update(s->twl4030);
761
 
+                        break;
762
 
+                    case 0x7f: /* ECI_DBI_CTRL */
763
 
+                        s->reg_data[addr] = value;
764
 
+                        twl4030_interrupt_update(s->twl4030);
765
 
+                        break;
766
 
+                    case 0x80: /* ACI_AV_CTRL */
767
 
+                        s->reg_data[addr] = (s->reg_data[addr] & 0x18) |
768
 
+                                            (value & ~0x18);
769
 
+                        twl4030_interrupt_update(s->twl4030);
770
 
+                        break;
771
 
+                    case 0x82: /* BCIA_CTRL */
772
 
+                        s->reg_data[addr] = value & 0x07;
773
 
+                        break;
774
 
+                    case 0x83: /* ACCISR1 */
775
 
+                        s->reg_data[addr] &= ~(value & 0x03);
776
 
+                        twl4030_interrupt_update(s->twl4030);
777
 
+                        break;
778
 
+                    case 0x84: /* ACCIMR1 */
779
 
+                        s->reg_data[addr] = value & 0x03;
780
 
+                        twl4030_interrupt_update(s->twl4030);
781
 
+                        break;
782
 
+                    default:
783
 
+                        hw_error("%s: unknown twl5031 register 0x%02x",
784
 
+                                 __FUNCTION__, addr);
785
 
+                        break;
786
 
+                }
787
 
+            } else {
788
 
+                /* read-only registers */
789
 
+            }
790
 
+            break;
791
 
+        case 0x97: /* BCICTL1 */
792
 
+            if (!s->twl4030->twl5031) {
793
 
+                s->reg_data[addr] = value;
794
 
+            } else {
795
 
+                hw_error("%s: unknown twl5031 register 0x%02x",
796
 
+                         __FUNCTION__, addr);
797
 
+            }
798
 
+            break;
799
 
+
800
 
+        /* PRECHARGE region */
801
 
+
802
 
+        case 0xaa ... 0xb8: /* FIXME: unknown registers */
803
 
+            s->reg_data[addr] = value;
804
 
+            break;
805
 
+
806
 
+        /* Interrupt region */
807
 
+
808
 
+        case 0xb9: /* BCIISR1A */
809
 
+            s->reg_data[addr] &= ~value;
810
 
+            break;
811
 
+        case 0xba: /* BCIISR2A */
812
 
+            s->reg_data[addr] &= ~(value & 0x0f);
813
 
+            break;
814
 
+        case 0xbb: /* BCIIMR1A */
815
 
+            s->reg_data[addr] = value;
816
 
+            break;
817
 
+        case 0xbc: /* BCIIMR2A */
818
 
+            s->reg_data[addr] = value & 0x0f;
819
 
+            break;
820
 
+        case 0xc6: /* BCISIHCTRL */
821
 
+            s->reg_data[addr] = value & 0x07;
822
 
+            break;
823
 
+
824
 
+        /* KEYPAD region */
825
 
+
826
 
+        case 0xd2: /* KEYP_CTRL_REG */
827
 
+            s->reg_data[addr] = value & 0x7f;
828
 
+            break;
829
 
+        case 0xd3: /* KEYP_DEB_REG */
830
 
+            s->reg_data[addr] = value & 0x3f;
831
 
+            break;
832
 
+        case 0xd5: /* LK_PTV_REG */
833
 
+            s->reg_data[addr] = value & 0xef;
834
 
+            break;
835
 
+        case 0xda: /* KEYP_SMS */
836
 
+            s->reg_data[addr] = (s->reg_data[addr] & ~0x30) | (value & 0x30);
837
 
+            twl4030_interrupt_update(s->twl4030);
838
 
+            break;
839
 
+        case 0xe3: /* KEYP_ISR1 */
840
 
+        case 0xe5: /* KEYP_ISR2 */
841
 
+            if (!(s->reg_data[0xe9] & 0x04)) { /* COR */
842
 
+                s->reg_data[addr] &= ~value;
843
 
+                twl4030_interrupt_update(s->twl4030);
844
 
+            }
845
 
+            break;
846
 
+        case 0xe4: /* KEYP_IMR1 */
847
 
+        case 0xe6: /* KEYP_IMR2 */
848
 
+        case 0xe7: /* KEYP_SIR */
849
 
+            s->reg_data[addr] = value & 0x0f;
850
 
+            twl4030_interrupt_update(s->twl4030);
851
 
+            break;
852
 
+        case 0xe9: /* KEYP_SIH_CTRL */
853
 
+            s->reg_data[addr] = value & 0x07;
854
 
+            break;
855
 
+        case 0xd4: /* LONG_KEY_REG1 */
856
 
+        case 0xd6: /* TIME_OUT_REG1 */
857
 
+        case 0xd7: /* TIME_OUT_REG2 */
858
 
+        case 0xd8: /* KBC_REG */
859
 
+        case 0xe8: /* KEYP_EDR */
860
 
+            s->reg_data[addr] = value;
861
 
+            break;
862
 
+        case 0xd9: /* KBR_REG */
863
 
+        case 0xdb ... 0xe2: /* FULL_CODE_xx_yy */
864
 
+            /* read-only, ignore */
865
 
+            break;
866
 
+
867
 
+        /* LED region */
868
 
+
869
 
+        case 0xee: /* LEDEN */
870
 
+            s->reg_data[addr] = value;
871
 
+            TRACE("LEDA power=%s/enable=%s, LEDB power=%s/enable=%s",
872
 
+                    value & 0x10 ? "on" : "off", value & 0x01 ? "yes" : "no",
873
 
+                    value & 0x20 ? "on" : "off", value & 0x02 ? "yes" : "no");
874
 
+            break;
875
 
+
876
 
+        /* PWMA/B/0/1 regions */
877
 
+
878
 
+        case 0xef: /* PWMAON */
879
 
+        case 0xf1: /* PWMBON */
880
 
+        case 0xf8: /* PWM0ON */
881
 
+        case 0xfb: /* PWM1ON */
882
 
+            s->reg_data[addr] = value;
883
 
+            break;
884
 
+        case 0xf0: /* PWMAOFF */
885
 
+        case 0xf2: /* PWMBOFF */
886
 
+        case 0xf9: /* PWM0OFF */
887
 
+        case 0xfc: /* PWM1OFF */
888
 
+            s->reg_data[addr] = value & 0x7f;
889
 
+            break;
890
 
+
891
 
+        default:
892
 
+               hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
893
 
+            break;
894
 
+    }
895
 
+}
896
 
+
897
 
+static inline struct tm *twl4030_gettime(void)
898
 
+{
899
 
+    time_t epoch_time = time(NULL);
900
 
+    return gmtime(&epoch_time);//localtime(&epoch_time);
901
 
+}
902
 
+
903
 
+static uint8_t twl4030_4b_read(TWL4030NodeState *s, uint8_t addr)
904
 
+{
905
 
+    uint8_t x;
906
 
+       TRACE("addr=0x%02x value=0x%02x", addr, s->reg_data[addr]);
907
 
+    switch (addr) {
908
 
+        /* SECURED_REG region */
909
 
+        case 0x00 ... 0x13:
910
 
+            return s->reg_data[addr];
911
 
+        /* BACKUP_REG region */
912
 
+        case 0x14 ... 0x1b:
913
 
+            return s->reg_data[addr];
914
 
+        /* RTC region */
915
 
+        case 0x1c: /* SECONDS_REG */
916
 
+            x = s->reg_data[addr];
917
 
+            if (x == 0xff) {
918
 
+                struct tm *t = twl4030_gettime();
919
 
+                x = ((t->tm_sec / 10) << 4) | (t->tm_sec % 10);
920
 
+            } else {
921
 
+                s->reg_data[addr] = 0xff;
922
 
+            }
923
 
+            TRACE_RTC("SECONDS_REG returns 0x%02x", x);
924
 
+            return x;
925
 
+        case 0x1d: /* MINUTES_REG */
926
 
+            x = s->reg_data[addr];
927
 
+            if (x == 0xff) {
928
 
+                struct tm *t = twl4030_gettime();
929
 
+                x = ((t->tm_min / 10) << 4) | (t->tm_min % 10);
930
 
+            } else {
931
 
+                s->reg_data[addr] = 0xff;
932
 
+            }
933
 
+            TRACE_RTC("MINUTES_REG returns 0x%02x", x);
934
 
+            return x;
935
 
+        case 0x1e: /* HOURS_REG */
936
 
+            x = s->reg_data[addr];
937
 
+            if (x == 0xff) {
938
 
+                struct tm *t = twl4030_gettime();
939
 
+                if (s->reg_data[0x29] & 0x08) { /* MODE_12_24 */
940
 
+                    int h12 = t->tm_hour;
941
 
+                    if (h12 > 11) {
942
 
+                        h12 -= 12;
943
 
+                        x = ((h12 / 10) << 4) | (h12 % 10) | 0x80; /* PM_NAM */
944
 
+                    } else {
945
 
+                        x = ((h12 / 10) << 4) | (h12 % 10);
946
 
+                    }
947
 
+                } else {
948
 
+                    x = ((t->tm_hour / 10) << 4) | (t->tm_hour % 10);
949
 
+                }
950
 
+            } else {
951
 
+                s->reg_data[addr] = 0xff;
952
 
+            }
953
 
+            TRACE_RTC("HOURS_REG returns 0x%02x", x);
954
 
+            return x;
955
 
+        case 0x1f: /* DAYS_REG */
956
 
+            x = s->reg_data[addr];
957
 
+            if (x == 0xff) {
958
 
+                struct tm *t = twl4030_gettime();
959
 
+                x = ((t->tm_mday / 10) << 4) | (t->tm_mday % 10);
960
 
+            } else {
961
 
+                s->reg_data[addr] = 0xff;
962
 
+            }
963
 
+            TRACE_RTC("DAYS_REG returns 0x%02x", x);
964
 
+            return x;
965
 
+        case 0x20: /* MONTHS_REG */
966
 
+            x = s->reg_data[addr];
967
 
+            if (x == 0xff) {
968
 
+                struct tm *t = twl4030_gettime();
969
 
+                x = (((t->tm_mon + 1) / 10) << 4) | ((t->tm_mon + 1) % 10);
970
 
+            } else {
971
 
+                s->reg_data[addr] = 0xff;
972
 
+            }
973
 
+            TRACE_RTC("MONTHS_REG returns 0x%02x", x);
974
 
+            return x;
975
 
+        case 0x21: /* YEARS_REG */
976
 
+            x = s->reg_data[addr];
977
 
+            if (x == 0xff) {
978
 
+                struct tm *t = twl4030_gettime();
979
 
+                x = (((t->tm_year % 100) / 10) << 4) | (t->tm_year % 10);
980
 
+            } else {
981
 
+                s->reg_data[addr] = 0xff;
982
 
+            }
983
 
+            TRACE_RTC("YEARS_REG returns 0x%02x", x);
984
 
+            return x;
985
 
+        case 0x22: /* WEEKS_REG */
986
 
+            x = s->reg_data[addr];
987
 
+            if (x == 0xff) {
988
 
+                struct tm *t = twl4030_gettime();
989
 
+                x = t->tm_wday;
990
 
+            } else {
991
 
+                s->reg_data[addr] = 0xff;
992
 
+            }
993
 
+            TRACE_RTC("WEEKS_REG returns 0x%02x", x);
994
 
+            return x;
995
 
+        case 0x23: /* ALARM_SECONDS_REG */
996
 
+            x = s->reg_data[addr];
997
 
+            TRACE_RTC("ALARM_SECONDS_REG returns 0x%02x", x);
998
 
+            return x;
999
 
+        case 0x24: /* ALARM_MINUTES_REG */
1000
 
+            x = s->reg_data[addr];
1001
 
+            TRACE_RTC("ALARM_MINUTES_REG returns 0x%02x", x);
1002
 
+            return x;
1003
 
+        case 0x25: /* ALARM_HOURS_REG */
1004
 
+            x = s->reg_data[addr];
1005
 
+            TRACE_RTC("ALARM_HOURS_REG returns 0x%02x", x);
1006
 
+            return x;
1007
 
+        case 0x26: /* ALARM_DAYS_REG */
1008
 
+            x = s->reg_data[addr];
1009
 
+            TRACE_RTC("ALARM_DAYS_REG returns 0x%02x", x);
1010
 
+            return x;
1011
 
+        case 0x27: /* ALARM_MONTHS_REG */
1012
 
+            x = s->reg_data[addr];
1013
 
+            TRACE_RTC("ALARM_MONTHS_REG returns 0x%02x", x);
1014
 
+            return x;
1015
 
+        case 0x28: /* ALARM_YEARS_REG */
1016
 
+            x = s->reg_data[addr];
1017
 
+            TRACE_RTC("ALARM_YEARS_REG returns 0x%02x", x);
1018
 
+            return x;
1019
 
+        case 0x29: /* RTC_CTRL_REG */
1020
 
+            x = s->reg_data[addr];
1021
 
+            TRACE_RTC("RTC_CTRL_REG returns 0x%02x", x);
1022
 
+            return x;
1023
 
+        case 0x2a: /* RTC_STATUS_REG */
1024
 
+            x = s->reg_data[addr];
1025
 
+            TRACE_RTC("RTC_STATUS_REG returns 0x%02x", x);
1026
 
+            return x;
1027
 
+        case 0x2b: /* RTC_INTERRUPTS_REG */
1028
 
+            x = s->reg_data[addr];
1029
 
+            TRACE_RTC("RTC_INTERRUPTS_REG returns 0x%02x", x);
1030
 
+            return x;
1031
 
+        case 0x2c: /* RTC_COMP_LSB_REG */
1032
 
+            x = s->reg_data[addr];
1033
 
+            TRACE_RTC("RTC_COMP_LSB_REG returns 0x%02x", x);
1034
 
+            return x;
1035
 
+        case 0x2d: /* RTC_COMP_MSB_REG */
1036
 
+            x = s->reg_data[addr];
1037
 
+            TRACE_RTC("RTC_CTRL_REG returns 0x%02x", x);
1038
 
+            return x;
1039
 
+        /* INT region */
1040
 
+        case 0x2f:
1041
 
+        case 0x31 ... 0x35:
1042
 
+            return s->reg_data[addr];
1043
 
+        case 0x2e: /* PWR_ISR1 */
1044
 
+        case 0x30: /* PWR_ISR2 */
1045
 
+            {
1046
 
+                uint8_t data = s->reg_data[addr];
1047
 
+                if (s->reg_data[0x35] & 0x04) { /* COR */
1048
 
+                    s->reg_data[addr] = 0x00;
1049
 
+                    twl4030_interrupt_update(s->twl4030);
1050
 
+                }
1051
 
+                return data;
1052
 
+            }
1053
 
+        /* PM_MASTER region */
1054
 
+        case 0x36 ... 0x44:
1055
 
+            return s->reg_data[addr];
1056
 
+        case 0x45: /* STS_HW_CONDITIONS */
1057
 
+            /* FIXME: force USB always connected, no VBUS (host usb) */
1058
 
+            return (s->reg_data[addr] & ~0x80) | 0x04;
1059
 
+        case 0x46 ... 0x5a:
1060
 
+            return s->reg_data[addr];
1061
 
+        /* PM_RECEIVER region */
1062
 
+        case 0x5b ... 0xf1:
1063
 
+            return s->reg_data[addr];
1064
 
+        default:
1065
 
+               hw_error("%s: unknown register 0x%02x", __FUNCTION__, addr);
1066
 
+            break;
1067
 
+    }
1068
 
+    return 0;
1069
 
+}
1070
 
+
1071
 
+static void twl4030_setup_alarm(TWL4030NodeState *s)
1072
 
+{
1073
 
+    if (s->reg_data[0x2b] & 0x08) { /* IT_ALARM */
1074
 
+        struct tm a = {
1075
 
+            .tm_sec = ((s->reg_data[0x23] >> 4) & 7) * 10
1076
 
+                      + (s->reg_data[0x23] & 0x0f),
1077
 
+            .tm_min = ((s->reg_data[0x24] >> 4) & 7) * 10
1078
 
+                      + (s->reg_data[0x24] & 0x0f),
1079
 
+            .tm_hour = ((s->reg_data[0x29] & 0x08)
1080
 
+                        ? (s->reg_data[0x25] >> 7) * 12 : 0)
1081
 
+                       + ((s->reg_data[0x25] >> 4) & 3) * 10
1082
 
+                       + (s->reg_data[0x25] & 0x0f),
1083
 
+            .tm_mday = ((s->reg_data[0x26] >> 4) & 3) * 10
1084
 
+                       + (s->reg_data[0x26] & 0x0f),
1085
 
+            .tm_mon = ((s->reg_data[0x27] >> 4) & 1) * 10
1086
 
+                      + (s->reg_data[0x27] & 0x0f)
1087
 
+                      - 1,
1088
 
+            .tm_year = (s->reg_data[0x28] >> 4) * 10
1089
 
+                       + (s->reg_data[0x28] & 0x0f)
1090
 
+                       + 100,
1091
 
+            .tm_isdst = -1,
1092
 
+        };
1093
 
+        TRACE_RTC("enable alarm on %02d/%02d/%04d at %02d:%02d:%02d (UTC)",
1094
 
+                  a.tm_mday, a.tm_mon + 1, a.tm_year + 1900,
1095
 
+                  a.tm_hour, a.tm_min, a.tm_sec);
1096
 
+        time_t at = mktime(&a); /* alarm time interpreted in local time */
1097
 
+        if (at < 0) {
1098
 
+            TRACE_RTC("unable to parse alarm calendar time");
1099
 
+        } else {
1100
 
+            /* fix alarm time to utc */
1101
 
+            struct timezone tz;
1102
 
+            struct timeval tv;
1103
 
+            if (!gettimeofday(&tv, &tz)) {
1104
 
+                at -= tz.tz_minuteswest * 60;
1105
 
+            }
1106
 
+            int64_t delta = (int64_t)difftime(at, time(NULL));
1107
 
+            if (delta <= 0) {
1108
 
+                TRACE_RTC("alarm is in the past");
1109
 
+            } else {
1110
 
+                TRACE_RTC("new alarm interrupt in %" PRId64 " seconds", delta);
1111
 
+                qemu_mod_timer(s->twl4030->alarm_timer,
1112
 
+                               qemu_get_clock_ns(vm_clock)
1113
 
+                               + get_ticks_per_sec() * delta);
1114
 
+            }
1115
 
+        }
1116
 
+    } else {
1117
 
+        qemu_del_timer(s->twl4030->alarm_timer);
1118
 
+    }
1119
 
+}
1120
 
+
1121
 
+static void twl4030_setup_periodic(TWL4030NodeState *s)
1122
 
+{
1123
 
+    if (s->reg_data[0x2b] & 0x04) { /* IT_TIMER */
1124
 
+        uint32_t t = 0;
1125
 
+        switch (s->reg_data[0x2b] & 3) {
1126
 
+            case 0: t = 1; break;
1127
 
+            case 1: t = 60; break;
1128
 
+            case 2: t = 60 * 60; break;
1129
 
+            case 3: t = 24 * 60 * 60; break;
1130
 
+        }
1131
 
+        TRACE_RTC("new periodic interrupt in %u seconds", t);
1132
 
+        qemu_mod_timer(s->twl4030->periodic_timer,
1133
 
+                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() * t);
1134
 
+    } else {
1135
 
+        qemu_del_timer(s->twl4030->periodic_timer);
1136
 
+    }
1137
 
+}
1138
 
+
1139
 
+static void twl4030_alarm(void *opaque)
1140
 
+{
1141
 
+    TWL4030State *s = opaque;
1142
 
+    s->i2c[3]->reg_data[0x2a] |= 0x40;      /* RTC_STATUS_REG |= ALARM */
1143
 
+    if (s->i2c[3]->reg_data[0x33] & 0xc0) { /* RTC_IT_RISING|RTC_IT_FALLING */
1144
 
+        TRACE_RTC("triggering RTC alarm interrupt");
1145
 
+        s->i2c[3]->reg_data[0x2e] |= 0x08;  /* PWR_ISR1 |= RTC_IT */
1146
 
+        s->i2c[3]->reg_data[0x30] |= 0x08;  /* PWR_ISR2 |= RTC_IT */
1147
 
+        twl4030_interrupt_update(s);
1148
 
+    }
1149
 
+    qemu_del_timer(s->alarm_timer);
1150
 
+}
1151
 
+
1152
 
+static void twl4030_periodic(void *opaque)
1153
 
+{
1154
 
+    TWL4030State *s = opaque;
1155
 
+    uint8_t b = 0x04 << (s->i2c[3]->reg_data[0x2b] & 3);
1156
 
+    s->i2c[3]->reg_data[0x2a] |= b;         /* TODO: when are these cleared? */
1157
 
+    if (s->i2c[3]->reg_data[0x33] & 0xc0) { /* RTC_IT_RISING|RTC_IT_FALLING */
1158
 
+        TRACE_RTC("triggering RTC periodic interrupt");
1159
 
+        s->i2c[3]->reg_data[0x2e] |= 0x08;  /* PWR_ISR1 |= RTC_IT */
1160
 
+        s->i2c[3]->reg_data[0x30] |= 0x08;  /* PWR_ISR2 |= RTC_IT */
1161
 
+        twl4030_interrupt_update(s);
1162
 
+    }
1163
 
+    twl4030_setup_periodic(s->i2c[3]);
1164
 
+}
1165
 
+
1166
 
+static void twl4030_4b_write(TWL4030NodeState *s, uint8_t addr, uint8_t value)
1167
 
+{
1168
 
+    uint8_t seq_addr, seq_sub;
1169
 
+
1170
 
+       TRACE("addr=0x%02x, value=0x%02x", addr, value);
1171
 
+    switch (addr) {
1172
 
+        case 0x1c: /* SECONDS_REG */
1173
 
+            TRACE_RTC("SECONDS_REG = 0x%02x", value);
1174
 
+            s->reg_data[addr] = value & 0x7f;
1175
 
+            break;
1176
 
+        case 0x1d: /* MINUTES_REG */
1177
 
+            TRACE_RTC("MINUTES_REG = 0x%02x", value);
1178
 
+            s->reg_data[addr] = value & 0x7f;
1179
 
+            break;
1180
 
+        case 0x1e: /* HOURS_REG */
1181
 
+            TRACE_RTC("HOURS_REG = 0x%02x", value);
1182
 
+            s->reg_data[addr] = value & 0xbf;
1183
 
+            break;
1184
 
+        case 0x1f: /* DAYS_REG */
1185
 
+            TRACE_RTC("DAYS_REG = 0x%02x", value);
1186
 
+            s->reg_data[addr] = value & 0x3f;
1187
 
+            break;
1188
 
+        case 0x20: /* MONTHS_REG */
1189
 
+            TRACE_RTC("MONTHS_REG = 0x%02x", value);
1190
 
+            s->reg_data[addr] = value & 0x1f;
1191
 
+            break;
1192
 
+        case 0x21: /* YEARS_REG */
1193
 
+            TRACE_RTC("YEARS_REG = 0x%02x", value);
1194
 
+            s->reg_data[addr] = value;
1195
 
+            break;
1196
 
+        case 0x22: /* WEEKS_REG */
1197
 
+            TRACE_RTC("WEEKS_REG = 0x%02x", value);
1198
 
+            s->reg_data[addr] = value & 0x07;
1199
 
+            break;
1200
 
+        case 0x23: /* ALARM_SECONDS_REG */
1201
 
+            TRACE_RTC("ALARM_SECONDS_REG = 0x%02x", value);
1202
 
+            s->reg_data[addr] = value & 0x7f;
1203
 
+            twl4030_setup_alarm(s);
1204
 
+            break;
1205
 
+        case 0x24: /* ALARM_MINUTES_REG */
1206
 
+            TRACE_RTC("ALARM_MINUTES_REG = 0x%02x", value);
1207
 
+            s->reg_data[addr] = value & 0x7f;
1208
 
+            twl4030_setup_alarm(s);
1209
 
+            break;
1210
 
+        case 0x25: /* ALARM_HOURS_REG */
1211
 
+            TRACE_RTC("ALARM_HOURS_REG = 0x%02x", value);
1212
 
+            s->reg_data[addr] = value & 0xbf;
1213
 
+            twl4030_setup_alarm(s);
1214
 
+            break;
1215
 
+        case 0x26: /* ALARM_DAYS_REG */
1216
 
+            TRACE_RTC("ALARM_DAYS_REG = 0x%02x", value);
1217
 
+            s->reg_data[addr] = value & 0x3f;
1218
 
+            twl4030_setup_alarm(s);
1219
 
+            break;
1220
 
+        case 0x27: /* ALARM_MONTHS_REG */
1221
 
+            TRACE_RTC("ALARM_MONTHS_REG = 0x%02x", value);
1222
 
+            s->reg_data[addr] = value & 0x1f;
1223
 
+            twl4030_setup_alarm(s);
1224
 
+            break;
1225
 
+        case 0x28: /* ALARM_YEARS_REG */
1226
 
+            TRACE_RTC("ALARM_YEARS_REG = 0x%02x", value);
1227
 
+            s->reg_data[addr] = value;
1228
 
+            twl4030_setup_alarm(s);
1229
 
+            break;
1230
 
+        case 0x29: /* RTC_CTRL_REG */
1231
 
+            TRACE_RTC("RTC_CTRL_REG = 0x%02x", value);
1232
 
+            s->reg_data[addr] = value & 0x3f;
1233
 
+            s->reg_data[0x2a] = (s->reg_data[0x2a] & ~0x02) |
1234
 
+                                ((value & 0x01) << 1);
1235
 
+            if (value & 0x40) { /* GET_TIME */
1236
 
+                struct tm *t = twl4030_gettime();
1237
 
+                s->reg_data[0x1c] = ((t->tm_sec / 10) << 4) | (t->tm_sec % 10);
1238
 
+                s->reg_data[0x1d] = ((t->tm_min / 10) << 4) | (t->tm_min % 10);
1239
 
+                if (value & 0x08) { /* MODE_12_24 */
1240
 
+                    int h12 = t->tm_hour;
1241
 
+                    /* TODO: should we report hours 0-11 or 1-12? */
1242
 
+                    if (h12 > 11) {
1243
 
+                        h12 -= 12;
1244
 
+                        s->reg_data[0x1e] = ((h12 / 10) << 4) | (h12 % 10) |
1245
 
+                                            0x80; /* PM_NAM */
1246
 
+                    } else {
1247
 
+                        s->reg_data[0x1e] = ((h12 / 10) << 4) | (h12 % 10);
1248
 
+                    }
1249
 
+                } else {
1250
 
+                    s->reg_data[0x1e] = ((t->tm_hour / 10) << 4) |
1251
 
+                                        (t->tm_hour % 10);
1252
 
+                }
1253
 
+                s->reg_data[0x1f] = ((t->tm_mday / 10) << 4) |
1254
 
+                                    (t->tm_mday % 10);
1255
 
+                s->reg_data[0x20] = (((t->tm_mon + 1) / 10) << 4) |
1256
 
+                                    ((t->tm_mon + 1) % 10);
1257
 
+                s->reg_data[0x21] = (((t->tm_year % 100) / 10) << 4) |
1258
 
+                                    (t->tm_year % 10);
1259
 
+                s->reg_data[0x22] = t->tm_wday;
1260
 
+            }
1261
 
+            /* TODO: support bits 1, 2, 4 and 5 */
1262
 
+            break;
1263
 
+        case 0x2a: /* RTC_STATUS_REG */
1264
 
+            TRACE_RTC("RTC_STATUS_REG = 0x%02x", value);
1265
 
+            s->reg_data[addr] &= ~(value & 0xc0);
1266
 
+            break;
1267
 
+        case 0x2b: /* RTC_INTERRUPTS_REG */
1268
 
+            TRACE_RTC("RTC_INTERRUPTS_REG = 0x%02x", value);
1269
 
+            {
1270
 
+                uint8_t change = s->reg_data[addr] ^ value;
1271
 
+                s->reg_data[addr] = value & 0x0f;
1272
 
+                if (change & 0x08) { /* IT_ALARM */
1273
 
+                    twl4030_setup_alarm(s);
1274
 
+                }
1275
 
+                if (change & 0x04) { /* IT_TIMER */
1276
 
+                    twl4030_setup_periodic(s);
1277
 
+                }
1278
 
+            }
1279
 
+            break;
1280
 
+        case 0x2c: /* RTC_COMP_LSB_REG */
1281
 
+        case 0x2d: /* RTC_COMP_MSB_REG */
1282
 
+            TRACE_RTC("RTC_COMP_%s_REG = 0x%02x",
1283
 
+                      (addr == 0x2c) ? "LSB" : "MSB", value);
1284
 
+            s->reg_data[addr] = value;
1285
 
+            break;
1286
 
+        case 0x2e: /* PWR_ISR1 */
1287
 
+        case 0x30: /* PWR_ISR2 */
1288
 
+            if (!(s->reg_data[0x35] & 0x04)) { /* COR */
1289
 
+                s->reg_data[addr] &= ~value;
1290
 
+                twl4030_interrupt_update(s->twl4030);
1291
 
+            }
1292
 
+            break;
1293
 
+        case 0x2f: /* PWR_IMR1 */
1294
 
+        case 0x31: /* PWR_IMR2 */
1295
 
+            s->reg_data[addr] = value;
1296
 
+            twl4030_interrupt_update(s->twl4030);
1297
 
+            break;
1298
 
+        case 0x33: /* PWR_EDR1 */
1299
 
+        case 0x34: /* PWR_EDR2 */
1300
 
+            s->reg_data[addr] = value;
1301
 
+            break;
1302
 
+        case 0x35: /* PWR_SIH_CTRL */
1303
 
+            s->reg_data[addr] = value & 0x07;
1304
 
+            break;
1305
 
+        case 0x36: /* CFG_P1_TRANSITION */
1306
 
+        case 0x37: /* CFG_P2_TRANSITION */
1307
 
+        case 0x38: /* CFG_P3_TRANSITION */
1308
 
+            if (s->twl4030->key_cfg)
1309
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x40) | (value & 0xbf);
1310
 
+            break;
1311
 
+        case 0x39: /* CFG_P123_TRANSITION */
1312
 
+            if (s->twl4030->key_cfg)
1313
 
+                s->reg_data[addr] = value;
1314
 
+            break;
1315
 
+        case 0x3a: /* STS_BOOT */
1316
 
+            s->reg_data[addr] = value;
1317
 
+            break;
1318
 
+        case 0x3b: /* CFG_BOOT */
1319
 
+            if (s->twl4030->key_cfg)
1320
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x8f);
1321
 
+            break;
1322
 
+        case 0x3c: /* SHUNDAN */
1323
 
+            s->reg_data[addr] = value & 0x3f;
1324
 
+            break;
1325
 
+        case 0x3d: /* BOOT_BCI */
1326
 
+            s->reg_data[addr] = (s->reg_data[addr] & 0x20) | (value & 0x17);
1327
 
+            break;
1328
 
+        case 0x3e: /* CFG_PWRANA1 */
1329
 
+            if (s->twl4030->key_tst)
1330
 
+                s->reg_data[addr] = value & 0x7f;
1331
 
+            break;
1332
 
+        case 0x3f: /* CFG_PWRANA2 */
1333
 
+            if (s->twl4030->key_tst)
1334
 
+                s->reg_data[addr] = value;
1335
 
+            break;
1336
 
+        case 0x44: /* PROTECT_KEY */
1337
 
+            s->twl4030->key_cfg = 0;
1338
 
+            s->twl4030->key_tst = 0;
1339
 
+            switch (value) {
1340
 
+                case 0x0C:
1341
 
+                    if (s->reg_data[addr] == 0xC0)
1342
 
+                        s->twl4030->key_cfg = 1;
1343
 
+                    break;
1344
 
+                case 0xE0:
1345
 
+                    if (s->reg_data[addr] == 0x0E)
1346
 
+                        s->twl4030->key_tst = 1;
1347
 
+                    break;
1348
 
+                case 0xEC:
1349
 
+                    if (s->reg_data[addr] == 0xCE) {
1350
 
+                        s->twl4030->key_cfg = 1;
1351
 
+                        s->twl4030->key_tst = 1;
1352
 
+                    }
1353
 
+                    break;
1354
 
+                default:
1355
 
+                    break;
1356
 
+            }
1357
 
+            s->reg_data[addr] = value;
1358
 
+            break;
1359
 
+        case 0x46: /* P1_SW_EVENTS */
1360
 
+        case 0x47: /* P2_SW_EVENTS */
1361
 
+        case 0x48: /* P3_SW_EVENTS */
1362
 
+            s->reg_data[addr] = value & 0x78;
1363
 
+            if (value & 0x01) { /* DEVOFF */
1364
 
+                TRACE("device power off sequence requested");
1365
 
+                qemu_system_shutdown_request();
1366
 
+            }
1367
 
+            break;
1368
 
+        case 0x4a: /* PB_CFG */
1369
 
+            s->reg_data[addr] = value & 0xf;
1370
 
+            break;
1371
 
+        case 0x4b: /* PB_MSB */
1372
 
+        case 0x4c: /* PB_LSB */
1373
 
+            s->reg_data[addr] = value;
1374
 
+            break;
1375
 
+        case 0x52: /* SEQ_ADD_W2P */
1376
 
+        case 0x53: /* SEQ_ADD_P2A */
1377
 
+        case 0x54: /* SEQ_ADD_A2W */
1378
 
+        case 0x55: /* SEQ_ADD_A2S */
1379
 
+        case 0x56: /* SEQ_ADD_S2A12 */
1380
 
+        case 0x57: /* SEQ_ADD_S2A3 */
1381
 
+        case 0x58: /* SEQ_ADD_WARM */
1382
 
+            if (s->twl4030->key_cfg)
1383
 
+                s->reg_data[addr] = value & 0x3f;
1384
 
+            break;
1385
 
+        case 0x59: /* MEMORY_ADDRESS */
1386
 
+            if (s->twl4030->key_cfg)
1387
 
+                s->reg_data[addr] = value;
1388
 
+            break;
1389
 
+        case 0x5a: /* MEMORY_DATA */
1390
 
+            if (s->twl4030->key_cfg) {
1391
 
+                s->reg_data[addr] = value;
1392
 
+                seq_addr = s->reg_data[0x59];
1393
 
+                seq_sub = seq_addr & 3;
1394
 
+                seq_addr >>= 2;
1395
 
+                if ((seq_addr >= 0x2b && seq_addr <= 0x3e) ||
1396
 
+                    (seq_addr <= 0x0e && seq_sub == 3))
1397
 
+                    s->twl4030->seq_mem[seq_addr][seq_sub] = value;
1398
 
+            }
1399
 
+            /* TODO: check if autoincrement is write-protected as well */
1400
 
+            s->reg_data[0x59]++;
1401
 
+            break;
1402
 
+        case 0x5e: /* WATCHDOG_CFG */
1403
 
+        case 0x60: /* VIBRATOR_CFG */
1404
 
+        case 0x6d: /* BB_CFG */
1405
 
+        case 0x73: /* VAUX1_TYPE */
1406
 
+        case 0x77: /* VAUX2_TYPE */
1407
 
+        case 0x7b: /* VAUX3_TYPE */
1408
 
+        case 0x7f: /* VAUX4_TYPE */
1409
 
+        case 0x83: /* VMMC1_TYPE */
1410
 
+        case 0x87: /* VMMC2_TYPE */
1411
 
+        case 0x8b: /* VPLL1_TYPE */
1412
 
+        case 0x8f: /* VPLL2_TYPE */
1413
 
+        case 0x93: /* VSIM_TYPE */
1414
 
+        case 0x97: /* VDAC_TYPE */
1415
 
+        case 0x9b: /* VINTANA1_TYPE */
1416
 
+        case 0x9f: /* VINTANA2_TYPE */
1417
 
+        case 0xa3: /* VINTDIG_TYPE */
1418
 
+        case 0xa7: /* VIO_TYPE */
1419
 
+        case 0xaa: /* VIO_MISC_CFG */
1420
 
+        case 0xb1: /* VDD1_TYPE */
1421
 
+        case 0xb4: /* VDD1_MISC_CFG */
1422
 
+        case 0xbd: /* VDD1_STEP */
1423
 
+        case 0xbf: /* VDD2_TYPE */
1424
 
+        case 0xc2: /* VDD2_MISC_CFG */
1425
 
+        case 0xcb: /* VDD2_STEP */
1426
 
+        case 0xcd: /* VUSB1V5_TYPE */
1427
 
+        case 0xd0: /* VUSB1V8_TYPE */
1428
 
+        case 0xd3: /* VUSB3V1_TYPE */
1429
 
+        case 0xdb: /* REGEN_TYPE */
1430
 
+        case 0xde: /* NRESPWRON_TYPE */
1431
 
+        case 0xe1: /* CLKEN_TYPE */
1432
 
+        case 0xe4: /* SYSEN_TYPE */
1433
 
+        case 0xe7: /* HFCLKOUT_TYPE */
1434
 
+        case 0xea: /* 2KCLKOUT_TYPE */
1435
 
+        case 0xed: /* TRITON_RESET_TYPE */
1436
 
+        case 0xf0: /* MAINREF_TYPE */
1437
 
+            s->reg_data[addr] = value & 0x1f;
1438
 
+            break;
1439
 
+        case 0x5f: /* IT_CHECK_CFG */
1440
 
+        case 0xb9: /* VDD1_VSEL */
1441
 
+        case 0xbb: /* VDD1_VFLOOR */
1442
 
+        case 0xbc: /* VDD1_VROOF */
1443
 
+        case 0xc7: /* VDD2_VSEL */
1444
 
+        case 0xc9: /* VDD2_VFLOOR */
1445
 
+        case 0xca: /* VDD2_VROOF */
1446
 
+            s->reg_data[addr] = value & 0x7f;
1447
 
+            break;
1448
 
+        case 0x61: /* DC/DC_GLOBAL_CFG */
1449
 
+        case 0x68: /* MISC_CFG */
1450
 
+            s->reg_data[addr] = value;
1451
 
+            break;
1452
 
+        case 0x62: /* VDD1_TRIM1 */
1453
 
+        case 0x64: /* VDD2_TRIM1 */
1454
 
+        case 0x66: /* VIO_TRIM1 */
1455
 
+        case 0xac: /* VIO_TEST2 */
1456
 
+        case 0xb6: /* VDD1_TEST2 */
1457
 
+        case 0xc4: /* VDD2_TEST2 */
1458
 
+            if (s->twl4030->key_tst)
1459
 
+                s->reg_data[addr] = value & 0x7f;
1460
 
+            break;
1461
 
+        case 0x63: /* VDD1_TRIM2 */
1462
 
+        case 0x65: /* VDD2_TRIM2 */
1463
 
+        case 0x67: /* VIO_TRIM2 */
1464
 
+            if (s->twl4030->key_tst)
1465
 
+                s->reg_data[addr] = value & 0x3f;
1466
 
+            break;
1467
 
+        case 0x72: /* VAUX1_DEV_GRP */
1468
 
+        case 0x76: /* VAUX2_DEV_GRP */
1469
 
+        case 0x7a: /* VAUX3_DEV_GRP */
1470
 
+        case 0x7e: /* VAUX4_DEV_GRP */
1471
 
+        case 0x82: /* VMMC1_DEV_GRP */
1472
 
+        case 0x86: /* VMMC2_DEV_GRP */
1473
 
+        case 0x8a: /* VPLL1_DEV_GRP */
1474
 
+        case 0x8e: /* VPLL2_DEV_GRP */
1475
 
+        case 0x92: /* VSIM_DEV_GRP */
1476
 
+        case 0x96: /* VDAC_DEV_GRP */
1477
 
+        case 0x9a: /* VINTANA1_DEV_GRP */
1478
 
+        case 0x9e: /* VINTANA2_DEV_GRP */
1479
 
+        case 0xa2: /* VINTDIG_DEV_GRP */
1480
 
+        case 0xa6: /* VIO_DEV_GRP */
1481
 
+        case 0xb0: /* VDD1_DEV_GRP */
1482
 
+        case 0xbe: /* VDD2_DEV_GRP */
1483
 
+        case 0xcc: /* VUSB1V5_DEV_GRP */
1484
 
+        case 0xcf: /* VUSB1V8_DEV_GRP */
1485
 
+        case 0xd2: /* VUSB3V1_DEV_GRP */
1486
 
+        case 0xda: /* REGEN_DEV_GRP */
1487
 
+        case 0xdd: /* NRESPWRON_DEV_GRP */
1488
 
+        case 0xe0: /* CLKEN_DEV_GRP */
1489
 
+        case 0xe3: /* SYSEN_DEV_GRP */
1490
 
+        case 0xe6: /* HFCLKOUT_DEV_GRP */
1491
 
+        case 0xe9: /* 2KCLKOUT_DEV_GRP */
1492
 
+        case 0xec: /* TRITON_RESET_DEV_GRP */
1493
 
+        case 0xef: /* MAINREF_DEV_GRP */
1494
 
+            s->reg_data[addr] = (s->reg_data[addr] & 0x0f) | (value & 0xf0);
1495
 
+            break;
1496
 
+        case 0x75: /* VAUX1_DEDICATED */
1497
 
+        case 0x7d: /* VAUX3_DEDICATED */
1498
 
+        case 0x8d: /* VPLL1_DEDICATED */
1499
 
+        case 0x95: /* VSIM_DEDICATED */
1500
 
+            if (s->twl4030->key_tst)
1501
 
+                s->reg_data[addr] = value & 0x77;
1502
 
+            else
1503
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x07);
1504
 
+            break;
1505
 
+        case 0x79: /* VAUX2_DEDICATED */
1506
 
+        case 0x81: /* VAUX4_DEDICATED */
1507
 
+        case 0x91: /* VPLL2_DEDICATED */
1508
 
+        case 0xa5: /* VINTDIG_DEDICATED */
1509
 
+            if (s->twl4030->key_tst)
1510
 
+                s->reg_data[addr] = value & 0x7f;
1511
 
+            else
1512
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
1513
 
+            break;
1514
 
+        case 0x85: /* VMMC1_DEDICATED */
1515
 
+        case 0x99: /* VDAC_DEDICATED */
1516
 
+            if (s->twl4030->key_tst)
1517
 
+                s->reg_data[addr] = value & 0x73;
1518
 
+            else
1519
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x03);
1520
 
+            break;
1521
 
+        case 0x89: /* VMMC2_DEDICATED */
1522
 
+            if (s->twl4030->key_tst)
1523
 
+                s->reg_data[addr] = value & 0x7f;
1524
 
+            else
1525
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x0f);
1526
 
+            break;
1527
 
+        case 0x9d: /* VINTANA1_DEDICATED */
1528
 
+            if (s->twl4030->key_tst)
1529
 
+                s->reg_data[addr] = value & 0x70;
1530
 
+            break;
1531
 
+        case 0xa1: /* VINTANA2_DEDICATED */
1532
 
+            if (s->twl4030->key_tst)
1533
 
+                s->reg_data[addr] = value & 0x71;
1534
 
+            else
1535
 
+                s->reg_data[addr] = (s->reg_data[addr] & 0x70) | (value & 0x01);
1536
 
+            break;
1537
 
+        case 0x74: /* VAUX1_REMAP */
1538
 
+        case 0x78: /* VAUX2_REMAP */
1539
 
+        case 0x7c: /* VAUX3_REMAP */
1540
 
+        case 0x80: /* VAUX4_REMAP */
1541
 
+        case 0x84: /* VMMC1_REMAP */
1542
 
+        case 0x88: /* VMMC2_REMAP */
1543
 
+        case 0x8c: /* VPLL1_REMAP */
1544
 
+        case 0x90: /* VPLL2_REMAP */
1545
 
+        case 0x94: /* VSIM_REMAP */
1546
 
+        case 0x98: /* VDAC_REMAP */
1547
 
+        case 0x9c: /* VINTANA1_REMAP */
1548
 
+        case 0xa0: /* VINTANA2_REMAP */
1549
 
+        case 0xa4: /* VINTDIG_REMAP */
1550
 
+        case 0xa8: /* VIO_REMAP */
1551
 
+        case 0xb2: /* VDD1_REMAP */
1552
 
+        case 0xc0: /* VDD2_REMAP */
1553
 
+        case 0xce: /* VUSB1V5_REMAP */
1554
 
+        case 0xd1: /* VUSB1V8_REMAP */
1555
 
+        case 0xd4: /* VUSB3V1_REMAP */
1556
 
+        case 0xdc: /* REGEN_REMAP */
1557
 
+        case 0xdf: /* NRESPWRON_REMAP */
1558
 
+        case 0xe2: /* CLKEN_REMAP */
1559
 
+        case 0xe5: /* SYSEN_REMAP */
1560
 
+        case 0xe8: /* HFCLKOUT_REMAP */
1561
 
+        case 0xeb: /* 2KCLKOUT_REMAP */
1562
 
+        case 0xee: /* TRITON_RESET_REMAP */
1563
 
+        case 0xf1: /* MAINREF_REMAP */
1564
 
+            s->reg_data[addr] = value;
1565
 
+            break;
1566
 
+        case 0xa9: /* VIO_CFG */
1567
 
+        case 0xb3: /* VDD1_CFG */
1568
 
+        case 0xc1: /* VDD2_CFG */
1569
 
+            s->reg_data[addr] = value & 0x03;
1570
 
+            break;
1571
 
+        case 0xab: /* VIO_TEST1 */
1572
 
+        case 0xb5: /* VDD1_TEST1 */
1573
 
+        case 0xc3: /* VDD2_TEST1 */
1574
 
+            if (s->twl4030->key_tst)
1575
 
+                s->reg_data[addr] = value;
1576
 
+            break;
1577
 
+        case 0xad: /* VIO_OSC */
1578
 
+        case 0xb7: /* VDD1_OSC */
1579
 
+        case 0xc5: /* VDD2_OSC */
1580
 
+            s->reg_data[addr] = value & 0x5f;
1581
 
+            break;
1582
 
+        case 0xae: /* VIO_RESERVED */
1583
 
+        case 0xb8: /* VDD1_RESERVED */
1584
 
+        case 0xc6: /* VDD2_RESERVED */
1585
 
+            break;
1586
 
+        case 0xaf: /* VIO_VSEL */
1587
 
+            s->reg_data[addr] = value & 0x01;
1588
 
+            break;
1589
 
+        case 0xba: /* VDD1_VMODE_CFG */
1590
 
+        case 0xc8: /* VDD2_VMODE_CFG */
1591
 
+            s->reg_data[addr] = (s->reg_data[addr] & 0x38) | (value & 0x07);
1592
 
+            break;
1593
 
+        case 0xd8: /* VUSB_DEDICATED1 */
1594
 
+            s->reg_data[addr] = value & 0x1f;
1595
 
+            break;
1596
 
+        case 0xd9: /* VUSB_DEDICATED2 */
1597
 
+            s->reg_data[addr] = value & 0x08;
1598
 
+            break;
1599
 
+
1600
 
+        default:
1601
 
+               hw_error("%s: unknown register 0x%02x value 0x%02x",
1602
 
+                    __FUNCTION__, addr, value);
1603
 
+            break;
1604
 
+    }
1605
 
+}
1606
 
+
1607
 
+static void twl4030_key_setstate(TWL4030NodeState *s,
1608
 
+                                 int col, int row, int state)
1609
 
+{
1610
 
+    TRACE("col=%d, row=%d, state=%d", col, row, state);
1611
 
+    if (col >= 0 && col < 8 && row >= 0 && row < 8) {
1612
 
+        s->reg_data[0xd8] = col; /* KBC_REG */
1613
 
+        s->reg_data[0xd9] = row; /* KBR_REG */
1614
 
+        int gen_int = 0;
1615
 
+        if (state) {
1616
 
+            s->reg_data[0xdb + row] |= 1 << col; /* FULL_CODE_xx_yy */
1617
 
+            gen_int = s->reg_data[0xe8] & 0x02;  /* ITKPRISING */
1618
 
+        } else {
1619
 
+            s->reg_data[0xdb + row] &= ~(1 << col); /* FULL_CODE_xx_yy */
1620
 
+            gen_int = s->reg_data[0xe8] & 0x01;     /* ITKPFALLING */
1621
 
+        }
1622
 
+        if (gen_int) {
1623
 
+            s->reg_data[0xe3] |= 0x01; /* ITKPISR1 */
1624
 
+            s->reg_data[0xe5] |= 0x01; /* ITKPISR2 */
1625
 
+            twl4030_interrupt_update(s->twl4030);
1626
 
+        }
1627
 
+    }
1628
 
+}
1629
 
+
1630
 
+static void twl4030_key_handler(void *opaque, int keycode)
1631
 
+{
1632
 
+    TWL4030NodeState *s = (TWL4030NodeState *)opaque;
1633
 
+    if (!s->twl4030->extended_key && keycode == 0xe0) {
1634
 
+        s->twl4030->extended_key = 0x80;
1635
 
+    } else {
1636
 
+        const TWL4030KeyMap *k = s->twl4030->keymap;
1637
 
+        int fullcode = (keycode & 0x7f) | (s->twl4030->extended_key);
1638
 
+        for (; k && k->code >= 0; k++) {
1639
 
+            if (k->code == fullcode) {
1640
 
+                twl4030_key_setstate(s, k->column, k->row, !(keycode & 0x80));
1641
 
+            }
1642
 
+        }
1643
 
+        s->twl4030->extended_key = 0;
1644
 
+    }
1645
 
+}
1646
 
+
1647
 
+static void twl4030_node_reset(TWL4030NodeState *s,
1648
 
+                               const uint8_t *reset_values)
1649
 
+{
1650
 
+    s->firstbyte = 0;
1651
 
+    s->reg = 0x00;
1652
 
+    memcpy(s->reg_data, reset_values, 256);
1653
 
+}
1654
 
+
1655
 
+static void twl4030_node_init(TWL4030NodeState *s,
1656
 
+                              twl4030_read_func read,
1657
 
+                              twl4030_write_func write,
1658
 
+                              const uint8_t *reset_values)
1659
 
+{
1660
 
+    s->read_func = read;
1661
 
+    s->write_func = write;
1662
 
+    twl4030_node_reset(s, reset_values);
1663
 
+}
1664
 
+
1665
 
+static int twl4030_48_init(I2CSlave *i2c)
1666
 
+{
1667
 
+    twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
1668
 
+                      twl4030_48_read, twl4030_48_write,
1669
 
+                      addr_48_reset_values);
1670
 
+    return 0;
1671
 
+}
1672
 
+
1673
 
+static int twl4030_49_init(I2CSlave *i2c)
1674
 
+{
1675
 
+    twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
1676
 
+                      twl4030_49_read, twl4030_49_write,
1677
 
+                      addr_49_reset_values);
1678
 
+    return 0;
1679
 
+}
1680
 
+
1681
 
+static int twl4030_4a_init(I2CSlave *i2c)
1682
 
+{
1683
 
+    TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1684
 
+    twl4030_node_init(s,
1685
 
+                      twl4030_4a_read, twl4030_4a_write,
1686
 
+                      addr_4a_reset_values);
1687
 
+    qemu_add_kbd_event_handler(twl4030_key_handler, s);
1688
 
+    return 0;
1689
 
+}
1690
 
+
1691
 
+static int twl4030_4b_init(I2CSlave *i2c)
1692
 
+{
1693
 
+    twl4030_node_init(FROM_I2C_SLAVE(TWL4030NodeState, i2c),
1694
 
+                      twl4030_4b_read, twl4030_4b_write,
1695
 
+                      addr_4b_reset_values);
1696
 
+    return 0;
1697
 
+}
1698
 
+
1699
 
+static void twl4030_event(I2CSlave *i2c, enum i2c_event event)
1700
 
+{
1701
 
+    if (event == I2C_START_SEND) {
1702
 
+        TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1703
 
+        s->firstbyte = 1;
1704
 
+    }
1705
 
+}
1706
 
+
1707
 
+static int twl4030_rx(I2CSlave *i2c)
1708
 
+{
1709
 
+    TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1710
 
+    return s->read_func(s, s->reg++);
1711
 
+}
1712
 
+
1713
 
+static int twl4030_tx(I2CSlave *i2c, uint8_t data)
1714
 
+{
1715
 
+    TWL4030NodeState *s = FROM_I2C_SLAVE(TWL4030NodeState, i2c);
1716
 
+    if (s->firstbyte) {
1717
 
+        s->reg = data;
1718
 
+        s->firstbyte = 0;
1719
 
+    } else {
1720
 
+        s->write_func(s, s->reg++, data);
1721
 
+       }
1722
 
+    return 1;
1723
 
+}
1724
 
+
1725
 
+static void twl4030_reset(void *opaque)
1726
 
+{
1727
 
+    TWL4030State *s = opaque;
1728
 
+    
1729
 
+    qemu_del_timer(s->alarm_timer);
1730
 
+    qemu_del_timer(s->periodic_timer);
1731
 
+
1732
 
+    twl4030_node_reset(s->i2c[0], addr_48_reset_values);
1733
 
+    twl4030_node_reset(s->i2c[1], addr_49_reset_values);
1734
 
+    twl4030_node_reset(s->i2c[2], addr_4a_reset_values);
1735
 
+    twl4030_node_reset(s->i2c[3], addr_4b_reset_values);
1736
 
+
1737
 
+    s->extended_key = 0;
1738
 
+    s->key_cfg = 0;
1739
 
+    s->key_tst = 0;
1740
 
+    
1741
 
+    memset(s->seq_mem, 0, sizeof(s->seq_mem));
1742
 
+
1743
 
+    /* TODO: indicate correct reset reason */
1744
 
+}
1745
 
+
1746
 
+static void twl4030_48_class_init(ObjectClass *klass, void *data)
1747
 
+{
1748
 
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1749
 
+    k->init = twl4030_48_init;
1750
 
+    k->event = twl4030_event;
1751
 
+    k->recv = twl4030_rx;
1752
 
+    k->send = twl4030_tx;
1753
 
+}
1754
 
+
1755
 
+static void twl4030_49_class_init(ObjectClass *klass, void *data)
1756
 
+{
1757
 
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1758
 
+    k->init = twl4030_49_init;
1759
 
+    k->event = twl4030_event;
1760
 
+    k->recv = twl4030_rx;
1761
 
+    k->send = twl4030_tx;
1762
 
+}
1763
 
+
1764
 
+static void twl4030_4a_class_init(ObjectClass *klass, void *data)
1765
 
+{
1766
 
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1767
 
+    k->init = twl4030_4a_init;
1768
 
+    k->event = twl4030_event;
1769
 
+    k->recv = twl4030_rx;
1770
 
+    k->send = twl4030_tx;
1771
 
+}
1772
 
+static void twl4030_4b_class_init(ObjectClass *klass, void *data)
1773
 
+{
1774
 
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
1775
 
+    k->init = twl4030_4b_init;
1776
 
+    k->event = twl4030_event;
1777
 
+    k->recv = twl4030_rx;
1778
 
+    k->send = twl4030_tx;
1779
 
+}
1780
 
+
1781
 
+static TypeInfo twl4030_info[] = {
1782
 
+    {
1783
 
+        .name = "twl4030_48",
1784
 
+        .parent = TYPE_I2C_SLAVE,
1785
 
+        .instance_size = sizeof(TWL4030NodeState),
1786
 
+        .class_init = twl4030_48_class_init,
1787
 
+    },
1788
 
+    {
1789
 
+        .name = "twl4030_49",
1790
 
+        .parent = TYPE_I2C_SLAVE,
1791
 
+        .instance_size = sizeof(TWL4030NodeState),
1792
 
+        .class_init = twl4030_49_class_init,
1793
 
+    },
1794
 
+    {
1795
 
+        .name = "twl4030_4a",
1796
 
+        .parent = TYPE_I2C_SLAVE,
1797
 
+        .instance_size = sizeof(TWL4030NodeState),
1798
 
+        .class_init = twl4030_4a_class_init,
1799
 
+    },
1800
 
+    {
1801
 
+        .name = "twl4030_4b",
1802
 
+        .parent = TYPE_I2C_SLAVE,
1803
 
+        .instance_size = sizeof(TWL4030NodeState),
1804
 
+        .class_init = twl4030_4b_class_init,
1805
 
+    },
1806
 
+};
1807
 
+
1808
 
+void *twl4030_init(i2c_bus *bus, qemu_irq irq1, qemu_irq irq2,
1809
 
+                   const TWL4030KeyMap *keymap)
1810
 
+{
1811
 
+    TWL4030State *s = (TWL4030State *)g_malloc0(sizeof(*s));
1812
 
+
1813
 
+    s->irq1 = irq1;
1814
 
+    s->irq2 = irq2;
1815
 
+    s->key_cfg = 0;
1816
 
+    s->key_tst = 0;
1817
 
+    s->keymap = keymap;
1818
 
+
1819
 
+    s->alarm_timer = qemu_new_timer_ns(vm_clock, twl4030_alarm, s);
1820
 
+    s->periodic_timer = qemu_new_timer_ns(vm_clock, twl4030_periodic, s);
1821
 
+
1822
 
+    int i;
1823
 
+    for (i = 0; i < ARRAY_SIZE(twl4030_info); i++) {
1824
 
+        DeviceState *ds = i2c_create_slave(bus, twl4030_info[i].name,
1825
 
+                                           0x48 + i);
1826
 
+        s->i2c[i] = FROM_I2C_SLAVE(TWL4030NodeState, I2C_SLAVE(ds));
1827
 
+        s->i2c[i]->twl4030 = s;
1828
 
+    }
1829
 
+
1830
 
+    qemu_register_reset(twl4030_reset, s);
1831
 
+    return s;
1832
 
+}
1833
 
+
1834
 
+void *twl5031_init(i2c_bus *bus, qemu_irq irq1, qemu_irq irq2,
1835
 
+                   const TWL4030KeyMap *keymap)
1836
 
+{
1837
 
+    TWL4030State *s = twl4030_init(bus, irq1, irq2, keymap);
1838
 
+    s->twl5031 = 1;
1839
 
+    return s;
1840
 
+}
1841
 
+
1842
 
+void twl4030_set_powerbutton_state(void *opaque, int pressed)
1843
 
+{
1844
 
+    TWL4030State *s = opaque;
1845
 
+    if (pressed) {
1846
 
+        if (!(s->i2c[3]->reg_data[0x45] & 0x01) && /* STS_PWON */
1847
 
+            (s->i2c[3]->reg_data[0x33] & 0x02)) {  /* PWRON_RISING */
1848
 
+            s->i2c[3]->reg_data[0x2e] |= 0x01;     /* PWRON */
1849
 
+            s->i2c[3]->reg_data[0x30] |= 0x01;     /* PWRON */
1850
 
+            twl4030_interrupt_update(s);
1851
 
+        }
1852
 
+        s->i2c[3]->reg_data[0x45] |= 0x01;         /* STS_PWON */
1853
 
+    } else {
1854
 
+        if ((s->i2c[3]->reg_data[0x45] & 0x01) &&  /* STS_PWON */
1855
 
+            (s->i2c[3]->reg_data[0x33] & 0x01)) {  /* PWRON_FALLING */
1856
 
+            s->i2c[3]->reg_data[0x2e] |= 0x01;     /* PWRON */
1857
 
+            s->i2c[3]->reg_data[0x30] |= 0x01;     /* PWRON */
1858
 
+            twl4030_interrupt_update(s);
1859
 
+        }
1860
 
+        s->i2c[3]->reg_data[0x45] &= ~0x01;        /* STS_PWON */
1861
 
+    }
1862
 
+}
1863
 
+
1864
 
+void twl4030_madc_attach(void *opaque, twl4030_madc_callback cb)
1865
 
+{
1866
 
+    TWL4030State *s = opaque;
1867
 
+    if (s->madc_cb) {
1868
 
+        fprintf(stderr,
1869
 
+                "%s: warning - overriding previously registered callback\n",
1870
 
+                __FUNCTION__);
1871
 
+    }
1872
 
+    s->madc_cb = cb;
1873
 
+}
1874
 
+
1875
 
+static void twl4030_register_types(void)
1876
 
+{
1877
 
+    TypeInfo *p = twl4030_info;
1878
 
+    int i;
1879
 
+    for (i = 0; i < ARRAY_SIZE(twl4030_info); p++, i++) {
1880
 
+        type_register_static(p);
1881
 
+    }
1882
 
+}
1883
 
+
1884
 
+type_init(twl4030_register_types);
1885
 
1.8.1.2
1886