All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Add v4l2 subdev driver for S5K4ECGX sensor with embedded SoC ISP
@ 2012-07-19 12:14 Sangwook Lee
  2012-07-19 12:14 ` [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor Sangwook Lee
  2012-07-19 12:14 ` [PATCH v2 2/2] v4l: Add v4l2 subdev driver for " Sangwook Lee
  0 siblings, 2 replies; 8+ messages in thread
From: Sangwook Lee @ 2012-07-19 12:14 UTC (permalink / raw)
  To: linux-media
  Cc: mchehab, laurent.pinchart, sakari.ailus, suapapa, quartz.jang,
	linaro-dev, patches, usman.ahmad, david.a.cohen, Sangwook Lee

The following 2 patches add driver for S5K4ECGX sensor with embedded ISP SoC,
and minor v4l2 control API enhancement. S5K4ECGX is 5M CMOS Image sensor from Samsung.

Changes since v1:
- fixed s_stream(0) when it called twice
- changed mutex_X position to be used when strictly necessary
- add additional s_power(0) in case that error happens
- update more accurate debugging statements
- remove dummy else 

Sangwook Lee (2):
  v4l: Add factory register values form S5K4ECGX sensor
  v4l: Add v4l2 subdev driver for S5K4ECGX sensor

 drivers/media/video/Kconfig         |    7 +
 drivers/media/video/Makefile        |    1 +
 drivers/media/video/s5k4ecgx.c      |  881 ++++++++++
 drivers/media/video/s5k4ecgx_regs.h | 3121 +++++++++++++++++++++++++++++++++++
 include/media/s5k4ecgx.h            |   29 +
 5 files changed, 4039 insertions(+)
 create mode 100644 drivers/media/video/s5k4ecgx.c
 create mode 100644 drivers/media/video/s5k4ecgx_regs.h
 create mode 100644 include/media/s5k4ecgx.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor
  2012-07-19 12:14 [PATCH v2 0/2] Add v4l2 subdev driver for S5K4ECGX sensor with embedded SoC ISP Sangwook Lee
@ 2012-07-19 12:14 ` Sangwook Lee
  2012-07-19 19:40   ` Sylwester Nawrocki
  2012-07-19 12:14 ` [PATCH v2 2/2] v4l: Add v4l2 subdev driver for " Sangwook Lee
  1 sibling, 1 reply; 8+ messages in thread
From: Sangwook Lee @ 2012-07-19 12:14 UTC (permalink / raw)
  To: linux-media
  Cc: mchehab, laurent.pinchart, sakari.ailus, suapapa, quartz.jang,
	linaro-dev, patches, usman.ahmad, david.a.cohen, Sangwook Lee

Add factory default settings for S5K4ECGX sensor registers.
I copied them from the reference code of Samsung S.LSI.

According to comments from the reference code, they do not
recommend any changes of these settings.

Signed-off-by: Sangwook Lee <sangwook.lee@linaro.org>
---
 drivers/media/video/s5k4ecgx_regs.h | 3121 +++++++++++++++++++++++++++++++++++
 1 file changed, 3121 insertions(+)
 create mode 100644 drivers/media/video/s5k4ecgx_regs.h

diff --git a/drivers/media/video/s5k4ecgx_regs.h b/drivers/media/video/s5k4ecgx_regs.h
new file mode 100644
index 0000000..3b17934
--- /dev/null
+++ b/drivers/media/video/s5k4ecgx_regs.h
@@ -0,0 +1,3121 @@
+/*
+ * Samsung S5K4ECGX registers table for default values
+ *
+ * Copyright (C) 2012 Linaro
+ * Copyright (C) 2012 Insignal Co,. Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRIVERS_MEDIA_VIDEO_S5K4ECGX_H__
+#define __DRIVERS_MEDIA_VIDEO_S5K4ECGX_H__
+
+/*
+ * Tokens for register write
+ * Default type about how to write values to registers
+ */
+enum token_type {
+	TOK_TERM = 0,	/* terminating token */
+	TOK_CMD,	/* Command write */
+	TOK_WRITE,	/* token for write operation */
+	TOK_DELAY,	/* delay token for reg list */
+	TOK_READ,
+};
+
+struct regval_list {
+	enum	token_type type;
+	u32	addr;
+	u16	val;
+};
+
+/*
+ * FIXME:
+ * The tables are default values of a S5K4ECGX sensor EVT1.1
+ * and are provided from Samsung LSI.
+ * It seems that no information is available for these registers
+ * in the datasheet
+ */
+struct regval_list s5k4ecgx_init_regs[] = {
+	{TOK_CMD, 0xFCFC, 0xD000},
+	{TOK_CMD, 0x0010, 0x0001},
+	{TOK_CMD, 0x1030, 0x0000},
+	{TOK_CMD, 0x0014, 0x0001},
+	{TOK_DELAY, 0x0, 0x64},
+	{TOK_WRITE, 0xD0001082, 0x01AA},
+	{TOK_WRITE, 0xD0001084, 0x01AA},
+	{TOK_WRITE, 0xD0001086, 0x0055},
+	{TOK_WRITE, 0xD0001088, 0x01AF},
+	{TOK_WRITE, 0xD000100E, 0x0000},
+	{TOK_WRITE, 0xD000007A, 0x0000},
+	{TOK_WRITE, 0xD000E406, 0x0092},
+	{TOK_WRITE, 0xD000E410, 0x3804},
+	{TOK_WRITE, 0xD000E41A, 0x0010},
+	{TOK_WRITE, 0xD000E420, 0x0003},
+	{TOK_WRITE, 0xD000E422, 0x0060},
+	{TOK_WRITE, 0xD000E42E, 0x0004},
+	{TOK_WRITE, 0xD000F400, 0x5A3C},
+	{TOK_WRITE, 0xD000F402, 0x0023},
+	{TOK_WRITE, 0xD000F404, 0x8080},
+	{TOK_WRITE, 0xD000F406, 0x03AF},
+	{TOK_WRITE, 0xD000F408, 0x000A},
+	{TOK_WRITE, 0xD000F40A, 0xAA54},
+	{TOK_WRITE, 0xD000F40C, 0x0040},
+	{TOK_WRITE, 0xD000F40E, 0x464E},
+	{TOK_WRITE, 0xD000F410, 0x0240},
+	{TOK_WRITE, 0xD000F412, 0x0240},
+	{TOK_WRITE, 0xD000F414, 0x0040},
+	{TOK_WRITE, 0xD000F416, 0x1000},
+	{TOK_WRITE, 0xD000F418, 0x55FF},
+	{TOK_WRITE, 0xD000F41A, 0xD000},
+	{TOK_WRITE, 0xD000F41C, 0x0010},
+	{TOK_WRITE, 0xD000F41E, 0x0202},
+	{TOK_WRITE, 0xD000F420, 0x0401},
+	{TOK_WRITE, 0xD000F422, 0x0022},
+	{TOK_WRITE, 0xD000F424, 0x0088},
+	{TOK_WRITE, 0xD000F426, 0x009F},
+	{TOK_WRITE, 0xD000F428, 0x0000},
+	{TOK_WRITE, 0xD000F42A, 0x1800},
+	{TOK_WRITE, 0xD000F42C, 0x0088},
+	{TOK_WRITE, 0xD000F42E, 0x0000},
+	{TOK_WRITE, 0xD000F430, 0x2428},
+	{TOK_WRITE, 0xD000F432, 0x0000},
+	{TOK_WRITE, 0xD000F434, 0x03EE},
+	{TOK_WRITE, 0xD000F436, 0x0000},
+	{TOK_WRITE, 0xD000F438, 0x0000},
+	{TOK_WRITE, 0xD000F43A, 0x0000},
+	{TOK_WRITE, 0xD000F552, 0x0708},
+	{TOK_WRITE, 0xD000F554, 0x080C},
+	{TOK_WRITE, 0x700018BC, 0x0004},
+	{TOK_WRITE, 0x700018BE, 0x05B6},
+	{TOK_WRITE, 0x700018C0, 0x0000},
+	{TOK_WRITE, 0x700018C2, 0x0000},
+	{TOK_WRITE, 0x700018C4, 0x0001},
+	{TOK_WRITE, 0x700018C6, 0x05BA},
+	{TOK_WRITE, 0x700018C8, 0x0000},
+	{TOK_WRITE, 0x700018CA, 0x0000},
+	{TOK_WRITE, 0x700018CC, 0x0007},
+	{TOK_WRITE, 0x700018CE, 0x05BA},
+	{TOK_WRITE, 0x700018D0, 0x0000},
+	{TOK_WRITE, 0x700018D2, 0x0000},
+	{TOK_WRITE, 0x700018D4, 0x01F4},
+	{TOK_WRITE, 0x700018D6, 0x024E},
+	{TOK_WRITE, 0x700018D8, 0x0000},
+	{TOK_WRITE, 0x700018DA, 0x0000},
+	{TOK_WRITE, 0x700018DC, 0x01F4},
+	{TOK_WRITE, 0x700018DE, 0x05B6},
+	{TOK_WRITE, 0x700018E0, 0x0000},
+	{TOK_WRITE, 0x700018E2, 0x0000},
+	{TOK_WRITE, 0x700018E4, 0x01F4},
+	{TOK_WRITE, 0x700018E6, 0x05BA},
+	{TOK_WRITE, 0x700018E8, 0x0000},
+	{TOK_WRITE, 0x700018EA, 0x0000},
+	{TOK_WRITE, 0x700018EC, 0x01F4},
+	{TOK_WRITE, 0x700018EE, 0x024F},
+	{TOK_WRITE, 0x700018F0, 0x0000},
+	{TOK_WRITE, 0x700018F2, 0x0000},
+	{TOK_WRITE, 0x700018F4, 0x0000},
+	{TOK_WRITE, 0x700018F6, 0x0000},
+	{TOK_WRITE, 0x700018F8, 0x0000},
+	{TOK_WRITE, 0x700018FA, 0x0000},
+	{TOK_WRITE, 0x700018FC, 0x0075},
+	{TOK_WRITE, 0x700018FE, 0x00CF},
+	{TOK_WRITE, 0x70001900, 0x0000},
+	{TOK_WRITE, 0x70001902, 0x0000},
+	{TOK_WRITE, 0x70001904, 0x0075},
+	{TOK_WRITE, 0x70001906, 0x00D6},
+	{TOK_WRITE, 0x70001908, 0x0000},
+	{TOK_WRITE, 0x7000190A, 0x0000},
+	{TOK_WRITE, 0x7000190C, 0x0004},
+	{TOK_WRITE, 0x7000190E, 0x01F4},
+	{TOK_WRITE, 0x70001910, 0x0000},
+	{TOK_WRITE, 0x70001912, 0x0000},
+	{TOK_WRITE, 0x70001914, 0x00F0},
+	{TOK_WRITE, 0x70001916, 0x01F4},
+	{TOK_WRITE, 0x70001918, 0x029E},
+	{TOK_WRITE, 0x7000191A, 0x05B2},
+	{TOK_WRITE, 0x7000191C, 0x0000},
+	{TOK_WRITE, 0x7000191E, 0x0000},
+	{TOK_WRITE, 0x70001920, 0x0000},
+	{TOK_WRITE, 0x70001922, 0x0000},
+	{TOK_WRITE, 0x70001924, 0x01F8},
+	{TOK_WRITE, 0x70001926, 0x0228},
+	{TOK_WRITE, 0x70001928, 0x0000},
+	{TOK_WRITE, 0x7000192A, 0x0000},
+	{TOK_WRITE, 0x7000192C, 0x0000},
+	{TOK_WRITE, 0x7000192E, 0x0000},
+	{TOK_WRITE, 0x70001930, 0x0208},
+	{TOK_WRITE, 0x70001932, 0x0238},
+	{TOK_WRITE, 0x70001934, 0x0000},
+	{TOK_WRITE, 0x70001936, 0x0000},
+	{TOK_WRITE, 0x70001938, 0x0000},
+	{TOK_WRITE, 0x7000193A, 0x0000},
+	{TOK_WRITE, 0x7000193C, 0x0218},
+	{TOK_WRITE, 0x7000193E, 0x0238},
+	{TOK_WRITE, 0x70001940, 0x0000},
+	{TOK_WRITE, 0x70001942, 0x0000},
+	{TOK_WRITE, 0x70001944, 0x0000},
+	{TOK_WRITE, 0x70001946, 0x0000},
+	{TOK_WRITE, 0x70001948, 0x0001},
+	{TOK_WRITE, 0x7000194A, 0x0009},
+	{TOK_WRITE, 0x7000194C, 0x00DE},
+	{TOK_WRITE, 0x7000194E, 0x05C0},
+	{TOK_WRITE, 0x70001950, 0x0000},
+	{TOK_WRITE, 0x70001952, 0x0000},
+	{TOK_WRITE, 0x70001954, 0x00DF},
+	{TOK_WRITE, 0x70001956, 0x00E4},
+	{TOK_WRITE, 0x70001958, 0x01F8},
+	{TOK_WRITE, 0x7000195A, 0x01FD},
+	{TOK_WRITE, 0x7000195C, 0x05B6},
+	{TOK_WRITE, 0x7000195E, 0x05BB},
+	{TOK_WRITE, 0x70001960, 0x0000},
+	{TOK_WRITE, 0x70001962, 0x0000},
+	{TOK_WRITE, 0x70001964, 0x0000},
+	{TOK_WRITE, 0x70001966, 0x0000},
+	{TOK_WRITE, 0x70001968, 0x0000},
+	{TOK_WRITE, 0x7000196A, 0x0000},
+	{TOK_WRITE, 0x7000196C, 0x0000},
+	{TOK_WRITE, 0x7000196E, 0x0000},
+	{TOK_WRITE, 0x70001970, 0x0000},
+	{TOK_WRITE, 0x70001972, 0x0000},
+	{TOK_WRITE, 0x70001974, 0x0000},
+	{TOK_WRITE, 0x70001976, 0x0000},
+	{TOK_WRITE, 0x70001978, 0x01F8},
+	{TOK_WRITE, 0x7000197A, 0x0000},
+	{TOK_WRITE, 0x7000197C, 0x0000},
+	{TOK_WRITE, 0x7000197E, 0x0077},
+	{TOK_WRITE, 0x70001980, 0x007E},
+	{TOK_WRITE, 0x70001982, 0x024F},
+	{TOK_WRITE, 0x70001984, 0x025E},
+	{TOK_WRITE, 0x70001986, 0x0000},
+	{TOK_WRITE, 0x70001988, 0x0000},
+	{TOK_WRITE, 0x7000198A, 0x0000},
+	{TOK_WRITE, 0x7000198C, 0x0000},
+	{TOK_WRITE, 0x7000198E, 0x0004},
+	{TOK_WRITE, 0x70001990, 0x09D1},
+	{TOK_WRITE, 0x70001992, 0x0000},
+	{TOK_WRITE, 0x70001994, 0x0000},
+	{TOK_WRITE, 0x70001996, 0x0001},
+	{TOK_WRITE, 0x70001998, 0x09D5},
+	{TOK_WRITE, 0x7000199A, 0x0000},
+	{TOK_WRITE, 0x7000199C, 0x0000},
+	{TOK_WRITE, 0x7000199E, 0x0008},
+	{TOK_WRITE, 0x700019A0, 0x09D5},
+	{TOK_WRITE, 0x700019A2, 0x0000},
+	{TOK_WRITE, 0x700019A4, 0x0000},
+	{TOK_WRITE, 0x700019A6, 0x02AA},
+	{TOK_WRITE, 0x700019A8, 0x0326},
+	{TOK_WRITE, 0x700019AA, 0x0000},
+	{TOK_WRITE, 0x700019AC, 0x0000},
+	{TOK_WRITE, 0x700019AE, 0x02AA},
+	{TOK_WRITE, 0x700019B0, 0x09D1},
+	{TOK_WRITE, 0x700019B2, 0x0000},
+	{TOK_WRITE, 0x700019B4, 0x0000},
+	{TOK_WRITE, 0x700019B6, 0x02AA},
+	{TOK_WRITE, 0x700019B8, 0x09D5},
+	{TOK_WRITE, 0x700019BA, 0x0000},
+	{TOK_WRITE, 0x700019BC, 0x0000},
+	{TOK_WRITE, 0x700019BE, 0x02AA},
+	{TOK_WRITE, 0x700019C0, 0x0327},
+	{TOK_WRITE, 0x700019C2, 0x0000},
+	{TOK_WRITE, 0x700019C4, 0x0000},
+	{TOK_WRITE, 0x700019C6, 0x0000},
+	{TOK_WRITE, 0x700019C8, 0x0000},
+	{TOK_WRITE, 0x700019CA, 0x0000},
+	{TOK_WRITE, 0x700019CC, 0x0000},
+	{TOK_WRITE, 0x700019CE, 0x0008},
+	{TOK_WRITE, 0x700019D0, 0x0084},
+	{TOK_WRITE, 0x700019D2, 0x0000},
+	{TOK_WRITE, 0x700019D4, 0x0000},
+	{TOK_WRITE, 0x700019D6, 0x0008},
+	{TOK_WRITE, 0x700019D8, 0x008D},
+	{TOK_WRITE, 0x700019DA, 0x0000},
+	{TOK_WRITE, 0x700019DC, 0x0000},
+	{TOK_WRITE, 0x700019DE, 0x0008},
+	{TOK_WRITE, 0x700019E0, 0x02AA},
+	{TOK_WRITE, 0x700019E2, 0x0000},
+	{TOK_WRITE, 0x700019E4, 0x0000},
+	{TOK_WRITE, 0x700019E6, 0x00AA},
+	{TOK_WRITE, 0x700019E8, 0x02AA},
+	{TOK_WRITE, 0x700019EA, 0x03AD},
+	{TOK_WRITE, 0x700019EC, 0x09CD},
+	{TOK_WRITE, 0x700019EE, 0x0000},
+	{TOK_WRITE, 0x700019F0, 0x0000},
+	{TOK_WRITE, 0x700019F2, 0x0000},
+	{TOK_WRITE, 0x700019F4, 0x0000},
+	{TOK_WRITE, 0x700019F6, 0x02AE},
+	{TOK_WRITE, 0x700019F8, 0x02DE},
+	{TOK_WRITE, 0x700019FA, 0x0000},
+	{TOK_WRITE, 0x700019FC, 0x0000},
+	{TOK_WRITE, 0x700019FE, 0x0000},
+	{TOK_WRITE, 0x70001A00, 0x0000},
+	{TOK_WRITE, 0x70001A02, 0x02BE},
+	{TOK_WRITE, 0x70001A04, 0x02EE},
+	{TOK_WRITE, 0x70001A06, 0x0000},
+	{TOK_WRITE, 0x70001A08, 0x0000},
+	{TOK_WRITE, 0x70001A0A, 0x0000},
+	{TOK_WRITE, 0x70001A0C, 0x0000},
+	{TOK_WRITE, 0x70001A0E, 0x02CE},
+	{TOK_WRITE, 0x70001A10, 0x02EE},
+	{TOK_WRITE, 0x70001A12, 0x0000},
+	{TOK_WRITE, 0x70001A14, 0x0000},
+	{TOK_WRITE, 0x70001A16, 0x0000},
+	{TOK_WRITE, 0x70001A18, 0x0000},
+	{TOK_WRITE, 0x70001A1A, 0x0001},
+	{TOK_WRITE, 0x70001A1C, 0x0009},
+	{TOK_WRITE, 0x70001A1E, 0x0095},
+	{TOK_WRITE, 0x70001A20, 0x09DB},
+	{TOK_WRITE, 0x70001A22, 0x0000},
+	{TOK_WRITE, 0x70001A24, 0x0000},
+	{TOK_WRITE, 0x70001A26, 0x0096},
+	{TOK_WRITE, 0x70001A28, 0x009B},
+	{TOK_WRITE, 0x70001A2A, 0x02AE},
+	{TOK_WRITE, 0x70001A2C, 0x02B3},
+	{TOK_WRITE, 0x70001A2E, 0x09D1},
+	{TOK_WRITE, 0x70001A30, 0x09D6},
+	{TOK_WRITE, 0x70001A32, 0x0000},
+	{TOK_WRITE, 0x70001A34, 0x0000},
+	{TOK_WRITE, 0x70001A36, 0x0000},
+	{TOK_WRITE, 0x70001A38, 0x0000},
+	{TOK_WRITE, 0x70001A3A, 0x0000},
+	{TOK_WRITE, 0x70001A3C, 0x0000},
+	{TOK_WRITE, 0x70001A3E, 0x0000},
+	{TOK_WRITE, 0x70001A40, 0x0000},
+	{TOK_WRITE, 0x70001A42, 0x0000},
+	{TOK_WRITE, 0x70001A44, 0x0000},
+	{TOK_WRITE, 0x70001A46, 0x0000},
+	{TOK_WRITE, 0x70001A48, 0x0000},
+	{TOK_WRITE, 0x70001A4A, 0x02AE},
+	{TOK_WRITE, 0x70001A4C, 0x0000},
+	{TOK_WRITE, 0x70001A4E, 0x0000},
+	{TOK_WRITE, 0x70001A50, 0x0009},
+	{TOK_WRITE, 0x70001A52, 0x0010},
+	{TOK_WRITE, 0x70001A54, 0x0327},
+	{TOK_WRITE, 0x70001A56, 0x0336},
+	{TOK_WRITE, 0x70001A58, 0x0000},
+	{TOK_WRITE, 0x70001A5A, 0x0000},
+	{TOK_WRITE, 0x70001A5C, 0x0000},
+	{TOK_WRITE, 0x70001A5E, 0x0000},
+	{TOK_WRITE, 0x70001AF8, 0x5A3C},
+	{TOK_WRITE, 0x70001896, 0x0002},
+	{TOK_WRITE, 0x70001898, 0x0000},
+	{TOK_WRITE, 0x7000189A, 0x0003},
+	{TOK_WRITE, 0x7000189E, 0x0FB0},
+	{TOK_WRITE, 0x700018AC, 0x0060},
+	{TOK_WRITE, 0x700018AE, 0x0060},
+	{TOK_WRITE, 0x700018B0, 0x05C0},
+	{TOK_WRITE, 0x700018B2, 0x05C0},
+	{TOK_WRITE, 0x70001AEA, 0x8080},
+	{TOK_WRITE, 0x70001AEC, 0x0080},
+	{TOK_WRITE, 0x70001AE0, 0x0000},
+	{TOK_WRITE, 0x70001A72, 0x0000},
+	{TOK_WRITE, 0x700018A2, 0x0004},
+	{TOK_WRITE, 0x70001A6A, 0x009A},
+	{TOK_WRITE, 0x7000385E, 0x024C},
+	{TOK_WRITE, 0x70000EE6, 0x0000},
+	{TOK_WRITE, 0x70001B2A, 0x0300},
+	{TOK_WRITE, 0x70001B2C, 0x00D6},
+	{TOK_WRITE, 0x70001B2E, 0x008D},
+	{TOK_WRITE, 0x70001B30, 0x00CF},
+	{TOK_WRITE, 0x70001B32, 0x0084},
+	{TOK_WRITE, 0x70000722, 0x0100},
+	{TOK_WRITE, 0x70000726, 0x0001},
+	{TOK_WRITE, 0x700008D6, 0x0001},
+	{TOK_WRITE, 0x7000146E, 0x0000},
+	{TOK_WRITE, 0x700008DC, 0x0000},
+	{TOK_WRITE, 0x70003AF8, 0xB570},
+	{TOK_WRITE, 0x70003AFA, 0x4B39},
+	{TOK_WRITE, 0x70003AFC, 0x4939},
+	{TOK_WRITE, 0x70003AFE, 0x483A},
+	{TOK_WRITE, 0x70003B00, 0x2200},
+	{TOK_WRITE, 0x70003B02, 0xC008},
+	{TOK_WRITE, 0x70003B04, 0x6001},
+	{TOK_WRITE, 0x70003B06, 0x4939},
+	{TOK_WRITE, 0x70003B08, 0x4839},
+	{TOK_WRITE, 0x70003B0A, 0x2401},
+	{TOK_WRITE, 0x70003B0C, 0xF000},
+	{TOK_WRITE, 0x70003B0E, 0xFBD4},
+	{TOK_WRITE, 0x70003B10, 0x4938},
+	{TOK_WRITE, 0x70003B12, 0x4839},
+	{TOK_WRITE, 0x70003B14, 0x2502},
+	{TOK_WRITE, 0x70003B16, 0x0022},
+	{TOK_WRITE, 0x70003B18, 0xF000},
+	{TOK_WRITE, 0x70003B1A, 0xFBCE},
+	{TOK_WRITE, 0x70003B1C, 0x4837},
+	{TOK_WRITE, 0x70003B1E, 0x0261},
+	{TOK_WRITE, 0x70003B20, 0x8001},
+	{TOK_WRITE, 0x70003B22, 0x2100},
+	{TOK_WRITE, 0x70003B24, 0x8041},
+	{TOK_WRITE, 0x70003B26, 0x4936},
+	{TOK_WRITE, 0x70003B28, 0x4836},
+	{TOK_WRITE, 0x70003B2A, 0x6041},
+	{TOK_WRITE, 0x70003B2C, 0x4936},
+	{TOK_WRITE, 0x70003B2E, 0x4837},
+	{TOK_WRITE, 0x70003B30, 0x2403},
+	{TOK_WRITE, 0x70003B32, 0x002A},
+	{TOK_WRITE, 0x70003B34, 0xF000},
+	{TOK_WRITE, 0x70003B36, 0xFBC0},
+	{TOK_WRITE, 0x70003B38, 0x4832},
+	{TOK_WRITE, 0x70003B3A, 0x4935},
+	{TOK_WRITE, 0x70003B3C, 0x30C0},
+	{TOK_WRITE, 0x70003B3E, 0x63C1},
+	{TOK_WRITE, 0x70003B40, 0x4930},
+	{TOK_WRITE, 0x70003B42, 0x4834},
+	{TOK_WRITE, 0x70003B44, 0x3980},
+	{TOK_WRITE, 0x70003B46, 0x6408},
+	{TOK_WRITE, 0x70003B48, 0x4833},
+	{TOK_WRITE, 0x70003B4A, 0x4934},
+	{TOK_WRITE, 0x70003B4C, 0x6388},
+	{TOK_WRITE, 0x70003B4E, 0x4934},
+	{TOK_WRITE, 0x70003B50, 0x4834},
+	{TOK_WRITE, 0x70003B52, 0x0022},
+	{TOK_WRITE, 0x70003B54, 0x2504},
+	{TOK_WRITE, 0x70003B56, 0xF000},
+	{TOK_WRITE, 0x70003B58, 0xFBAF},
+	{TOK_WRITE, 0x70003B5A, 0x4933},
+	{TOK_WRITE, 0x70003B5C, 0x4833},
+	{TOK_WRITE, 0x70003B5E, 0x2405},
+	{TOK_WRITE, 0x70003B60, 0x002A},
+	{TOK_WRITE, 0x70003B62, 0xF000},
+	{TOK_WRITE, 0x70003B64, 0xF881},
+	{TOK_WRITE, 0x70003B66, 0x491F},
+	{TOK_WRITE, 0x70003B68, 0x4830},
+	{TOK_WRITE, 0x70003B6A, 0x0022},
+	{TOK_WRITE, 0x70003B6C, 0x2506},
+	{TOK_WRITE, 0x70003B6E, 0x39B6},
+	{TOK_WRITE, 0x70003B70, 0x1D80},
+	{TOK_WRITE, 0x70003B72, 0xF000},
+	{TOK_WRITE, 0x70003B74, 0xF879},
+	{TOK_WRITE, 0x70003B76, 0x482D},
+	{TOK_WRITE, 0x70003B78, 0x492D},
+	{TOK_WRITE, 0x70003B7A, 0x2407},
+	{TOK_WRITE, 0x70003B7C, 0x002A},
+	{TOK_WRITE, 0x70003B7E, 0x300C},
+	{TOK_WRITE, 0x70003B80, 0xF000},
+	{TOK_WRITE, 0x70003B82, 0xF872},
+	{TOK_WRITE, 0x70003B84, 0x4829},
+	{TOK_WRITE, 0x70003B86, 0x492B},
+	{TOK_WRITE, 0x70003B88, 0x0022},
+	{TOK_WRITE, 0x70003B8A, 0x2508},
+	{TOK_WRITE, 0x70003B8C, 0x3010},
+	{TOK_WRITE, 0x70003B8E, 0xF000},
+	{TOK_WRITE, 0x70003B90, 0xF86B},
+	{TOK_WRITE, 0x70003B92, 0x4929},
+	{TOK_WRITE, 0x70003B94, 0x4829},
+	{TOK_WRITE, 0x70003B96, 0x2409},
+	{TOK_WRITE, 0x70003B98, 0x002A},
+	{TOK_WRITE, 0x70003B9A, 0xF000},
+	{TOK_WRITE, 0x70003B9C, 0xFB8D},
+	{TOK_WRITE, 0x70003B9E, 0x4928},
+	{TOK_WRITE, 0x70003BA0, 0x4828},
+	{TOK_WRITE, 0x70003BA2, 0x0022},
+	{TOK_WRITE, 0x70003BA4, 0x250A},
+	{TOK_WRITE, 0x70003BA6, 0xF000},
+	{TOK_WRITE, 0x70003BA8, 0xFB87},
+	{TOK_WRITE, 0x70003BAA, 0x4927},
+	{TOK_WRITE, 0x70003BAC, 0x4827},
+	{TOK_WRITE, 0x70003BAE, 0x240B},
+	{TOK_WRITE, 0x70003BB0, 0x002A},
+	{TOK_WRITE, 0x70003BB2, 0xF000},
+	{TOK_WRITE, 0x70003BB4, 0xFB81},
+	{TOK_WRITE, 0x70003BB6, 0x4926},
+	{TOK_WRITE, 0x70003BB8, 0x4826},
+	{TOK_WRITE, 0x70003BBA, 0x0022},
+	{TOK_WRITE, 0x70003BBC, 0x250C},
+	{TOK_WRITE, 0x70003BBE, 0xF000},
+	{TOK_WRITE, 0x70003BC0, 0xFB7B},
+	{TOK_WRITE, 0x70003BC2, 0x4925},
+	{TOK_WRITE, 0x70003BC4, 0x4825},
+	{TOK_WRITE, 0x70003BC6, 0x240D},
+	{TOK_WRITE, 0x70003BC8, 0x002A},
+	{TOK_WRITE, 0x70003BCA, 0xF000},
+	{TOK_WRITE, 0x70003BCC, 0xFB75},
+	{TOK_WRITE, 0x70003BCE, 0x4924},
+	{TOK_WRITE, 0x70003BD0, 0x4824},
+	{TOK_WRITE, 0x70003BD2, 0x0022},
+	{TOK_WRITE, 0x70003BD4, 0xF000},
+	{TOK_WRITE, 0x70003BD6, 0xFB70},
+	{TOK_WRITE, 0x70003BD8, 0xBC70},
+	{TOK_WRITE, 0x70003BDA, 0xBC08},
+	{TOK_WRITE, 0x70003BDC, 0x4718},
+	{TOK_WRITE, 0x70003BDE, 0x0000},
+	{TOK_WRITE, 0x70003BE0, 0x018F},
+	{TOK_WRITE, 0x70003BE2, 0x4EC2},
+	{TOK_WRITE, 0x70003BE4, 0x037F},
+	{TOK_WRITE, 0x70003BE6, 0x0000},
+	{TOK_WRITE, 0x70003BE8, 0x1F90},
+	{TOK_WRITE, 0x70003BEA, 0x7000},
+	{TOK_WRITE, 0x70003BEC, 0x3C81},
+	{TOK_WRITE, 0x70003BEE, 0x7000},
+	{TOK_WRITE, 0x70003BF0, 0xE38B},
+	{TOK_WRITE, 0x70003BF2, 0x0000},
+	{TOK_WRITE, 0x70003BF4, 0x3CB9},
+	{TOK_WRITE, 0x70003BF6, 0x7000},
+	{TOK_WRITE, 0x70003BF8, 0xC3B1},
+	{TOK_WRITE, 0x70003BFA, 0x0000},
+	{TOK_WRITE, 0x70003BFC, 0x4780},
+	{TOK_WRITE, 0x70003BFE, 0x7000},
+	{TOK_WRITE, 0x70003C00, 0x3D17},
+	{TOK_WRITE, 0x70003C02, 0x7000},
+	{TOK_WRITE, 0x70003C04, 0x0080},
+	{TOK_WRITE, 0x70003C06, 0x7000},
+	{TOK_WRITE, 0x70003C08, 0x3D53},
+	{TOK_WRITE, 0x70003C0A, 0x7000},
+	{TOK_WRITE, 0x70003C0C, 0xB49D},
+	{TOK_WRITE, 0x70003C0E, 0x0000},
+	{TOK_WRITE, 0x70003C10, 0x3DFF},
+	{TOK_WRITE, 0x70003C12, 0x7000},
+	{TOK_WRITE, 0x70003C14, 0x3DB3},
+	{TOK_WRITE, 0x70003C16, 0x7000},
+	{TOK_WRITE, 0x70003C18, 0xFFFF},
+	{TOK_WRITE, 0x70003C1A, 0x00FF},
+	{TOK_WRITE, 0x70003C1C, 0x17E0},
+	{TOK_WRITE, 0x70003C1E, 0x7000},
+	{TOK_WRITE, 0x70003C20, 0x3F7B},
+	{TOK_WRITE, 0x70003C22, 0x7000},
+	{TOK_WRITE, 0x70003C24, 0x053D},
+	{TOK_WRITE, 0x70003C26, 0x0000},
+	{TOK_WRITE, 0x70003C28, 0x0000},
+	{TOK_WRITE, 0x70003C2A, 0x0A89},
+	{TOK_WRITE, 0x70003C2C, 0x6CD2},
+	{TOK_WRITE, 0x70003C2E, 0x0000},
+	{TOK_WRITE, 0x70003C30, 0x0000},
+	{TOK_WRITE, 0x70003C32, 0x0A9A},
+	{TOK_WRITE, 0x70003C34, 0x0000},
+	{TOK_WRITE, 0x70003C36, 0x02D2},
+	{TOK_WRITE, 0x70003C38, 0x3FC9},
+	{TOK_WRITE, 0x70003C3A, 0x7000},
+	{TOK_WRITE, 0x70003C3C, 0x9E65},
+	{TOK_WRITE, 0x70003C3E, 0x0000},
+	{TOK_WRITE, 0x70003C40, 0x403D},
+	{TOK_WRITE, 0x70003C42, 0x7000},
+	{TOK_WRITE, 0x70003C44, 0x7C49},
+	{TOK_WRITE, 0x70003C46, 0x0000},
+	{TOK_WRITE, 0x70003C48, 0x40B1},
+	{TOK_WRITE, 0x70003C4A, 0x7000},
+	{TOK_WRITE, 0x70003C4C, 0x7C63},
+	{TOK_WRITE, 0x70003C4E, 0x0000},
+	{TOK_WRITE, 0x70003C50, 0x40CD},
+	{TOK_WRITE, 0x70003C52, 0x7000},
+	{TOK_WRITE, 0x70003C54, 0x8F01},
+	{TOK_WRITE, 0x70003C56, 0x0000},
+	{TOK_WRITE, 0x70003C58, 0x416F},
+	{TOK_WRITE, 0x70003C5A, 0x7000},
+	{TOK_WRITE, 0x70003C5C, 0x7F3F},
+	{TOK_WRITE, 0x70003C5E, 0x0000},
+	{TOK_WRITE, 0x70003C60, 0x41FD},
+	{TOK_WRITE, 0x70003C62, 0x7000},
+	{TOK_WRITE, 0x70003C64, 0x98C5},
+	{TOK_WRITE, 0x70003C66, 0x0000},
+	{TOK_WRITE, 0x70003C68, 0xB570},
+	{TOK_WRITE, 0x70003C6A, 0x000C},
+	{TOK_WRITE, 0x70003C6C, 0x0015},
+	{TOK_WRITE, 0x70003C6E, 0x0029},
+	{TOK_WRITE, 0x70003C70, 0xF000},
+	{TOK_WRITE, 0x70003C72, 0xFB2A},
+	{TOK_WRITE, 0x70003C74, 0x49F8},
+	{TOK_WRITE, 0x70003C76, 0x00A8},
+	{TOK_WRITE, 0x70003C78, 0x500C},
+	{TOK_WRITE, 0x70003C7A, 0xBC70},
+	{TOK_WRITE, 0x70003C7C, 0xBC08},
+	{TOK_WRITE, 0x70003C7E, 0x4718},
+	{TOK_WRITE, 0x70003C80, 0x6808},
+	{TOK_WRITE, 0x70003C82, 0x0400},
+	{TOK_WRITE, 0x70003C84, 0x0C00},
+	{TOK_WRITE, 0x70003C86, 0x6849},
+	{TOK_WRITE, 0x70003C88, 0x0409},
+	{TOK_WRITE, 0x70003C8A, 0x0C09},
+	{TOK_WRITE, 0x70003C8C, 0x4AF3},
+	{TOK_WRITE, 0x70003C8E, 0x8992},
+	{TOK_WRITE, 0x70003C90, 0x2A00},
+	{TOK_WRITE, 0x70003C92, 0xD00D},
+	{TOK_WRITE, 0x70003C94, 0x2300},
+	{TOK_WRITE, 0x70003C96, 0x1A89},
+	{TOK_WRITE, 0x70003C98, 0xD400},
+	{TOK_WRITE, 0x70003C9A, 0x000B},
+	{TOK_WRITE, 0x70003C9C, 0x0419},
+	{TOK_WRITE, 0x70003C9E, 0x0C09},
+	{TOK_WRITE, 0x70003CA0, 0x23FF},
+	{TOK_WRITE, 0x70003CA2, 0x33C1},
+	{TOK_WRITE, 0x70003CA4, 0x1810},
+	{TOK_WRITE, 0x70003CA6, 0x4298},
+	{TOK_WRITE, 0x70003CA8, 0xD800},
+	{TOK_WRITE, 0x70003CAA, 0x0003},
+	{TOK_WRITE, 0x70003CAC, 0x0418},
+	{TOK_WRITE, 0x70003CAE, 0x0C00},
+	{TOK_WRITE, 0x70003CB0, 0x4AEB},
+	{TOK_WRITE, 0x70003CB2, 0x8150},
+	{TOK_WRITE, 0x70003CB4, 0x8191},
+	{TOK_WRITE, 0x70003CB6, 0x4770},
+	{TOK_WRITE, 0x70003CB8, 0xB5F3},
+	{TOK_WRITE, 0x70003CBA, 0x0004},
+	{TOK_WRITE, 0x70003CBC, 0xB081},
+	{TOK_WRITE, 0x70003CBE, 0x9802},
+	{TOK_WRITE, 0x70003CC0, 0x6800},
+	{TOK_WRITE, 0x70003CC2, 0x0600},
+	{TOK_WRITE, 0x70003CC4, 0x0E00},
+	{TOK_WRITE, 0x70003CC6, 0x2201},
+	{TOK_WRITE, 0x70003CC8, 0x0015},
+	{TOK_WRITE, 0x70003CCA, 0x0021},
+	{TOK_WRITE, 0x70003CCC, 0x3910},
+	{TOK_WRITE, 0x70003CCE, 0x408A},
+	{TOK_WRITE, 0x70003CD0, 0x40A5},
+	{TOK_WRITE, 0x70003CD2, 0x4FE4},
+	{TOK_WRITE, 0x70003CD4, 0x0016},
+	{TOK_WRITE, 0x70003CD6, 0x2C10},
+	{TOK_WRITE, 0x70003CD8, 0xDA03},
+	{TOK_WRITE, 0x70003CDA, 0x8839},
+	{TOK_WRITE, 0x70003CDC, 0x43A9},
+	{TOK_WRITE, 0x70003CDE, 0x8039},
+	{TOK_WRITE, 0x70003CE0, 0xE002},
+	{TOK_WRITE, 0x70003CE2, 0x8879},
+	{TOK_WRITE, 0x70003CE4, 0x43B1},
+	{TOK_WRITE, 0x70003CE6, 0x8079},
+	{TOK_WRITE, 0x70003CE8, 0xF000},
+	{TOK_WRITE, 0x70003CEA, 0xFAF6},
+	{TOK_WRITE, 0x70003CEC, 0x2C10},
+	{TOK_WRITE, 0x70003CEE, 0xDA03},
+	{TOK_WRITE, 0x70003CF0, 0x8839},
+	{TOK_WRITE, 0x70003CF2, 0x4329},
+	{TOK_WRITE, 0x70003CF4, 0x8039},
+	{TOK_WRITE, 0x70003CF6, 0xE002},
+	{TOK_WRITE, 0x70003CF8, 0x8879},
+	{TOK_WRITE, 0x70003CFA, 0x4331},
+	{TOK_WRITE, 0x70003CFC, 0x8079},
+	{TOK_WRITE, 0x70003CFE, 0x49DA},
+	{TOK_WRITE, 0x70003D00, 0x8809},
+	{TOK_WRITE, 0x70003D02, 0x2900},
+	{TOK_WRITE, 0x70003D04, 0xD102},
+	{TOK_WRITE, 0x70003D06, 0xF000},
+	{TOK_WRITE, 0x70003D08, 0xFAEF},
+	{TOK_WRITE, 0x70003D0A, 0x2000},
+	{TOK_WRITE, 0x70003D0C, 0x9902},
+	{TOK_WRITE, 0x70003D0E, 0x6008},
+	{TOK_WRITE, 0x70003D10, 0xBCFE},
+	{TOK_WRITE, 0x70003D12, 0xBC08},
+	{TOK_WRITE, 0x70003D14, 0x4718},
+	{TOK_WRITE, 0x70003D16, 0xB538},
+	{TOK_WRITE, 0x70003D18, 0x9C04},
+	{TOK_WRITE, 0x70003D1A, 0x0015},
+	{TOK_WRITE, 0x70003D1C, 0x002A},
+	{TOK_WRITE, 0x70003D1E, 0x9400},
+	{TOK_WRITE, 0x70003D20, 0xF000},
+	{TOK_WRITE, 0x70003D22, 0xFAEA},
+	{TOK_WRITE, 0x70003D24, 0x4AD1},
+	{TOK_WRITE, 0x70003D26, 0x8811},
+	{TOK_WRITE, 0x70003D28, 0x2900},
+	{TOK_WRITE, 0x70003D2A, 0xD00F},
+	{TOK_WRITE, 0x70003D2C, 0x8820},
+	{TOK_WRITE, 0x70003D2E, 0x4281},
+	{TOK_WRITE, 0x70003D30, 0xD20C},
+	{TOK_WRITE, 0x70003D32, 0x8861},
+	{TOK_WRITE, 0x70003D34, 0x8853},
+	{TOK_WRITE, 0x70003D36, 0x4299},
+	{TOK_WRITE, 0x70003D38, 0xD200},
+	{TOK_WRITE, 0x70003D3A, 0x1E40},
+	{TOK_WRITE, 0x70003D3C, 0x0400},
+	{TOK_WRITE, 0x70003D3E, 0x0C00},
+	{TOK_WRITE, 0x70003D40, 0x8020},
+	{TOK_WRITE, 0x70003D42, 0x8851},
+	{TOK_WRITE, 0x70003D44, 0x8061},
+	{TOK_WRITE, 0x70003D46, 0x4368},
+	{TOK_WRITE, 0x70003D48, 0x1840},
+	{TOK_WRITE, 0x70003D4A, 0x6060},
+	{TOK_WRITE, 0x70003D4C, 0xBC38},
+	{TOK_WRITE, 0x70003D4E, 0xBC08},
+	{TOK_WRITE, 0x70003D50, 0x4718},
+	{TOK_WRITE, 0x70003D52, 0xB5F8},
+	{TOK_WRITE, 0x70003D54, 0x0004},
+	{TOK_WRITE, 0x70003D56, 0x6808},
+	{TOK_WRITE, 0x70003D58, 0x0400},
+	{TOK_WRITE, 0x70003D5A, 0x0C00},
+	{TOK_WRITE, 0x70003D5C, 0x2201},
+	{TOK_WRITE, 0x70003D5E, 0x0015},
+	{TOK_WRITE, 0x70003D60, 0x0021},
+	{TOK_WRITE, 0x70003D62, 0x3910},
+	{TOK_WRITE, 0x70003D64, 0x408A},
+	{TOK_WRITE, 0x70003D66, 0x40A5},
+	{TOK_WRITE, 0x70003D68, 0x4FBE},
+	{TOK_WRITE, 0x70003D6A, 0x0016},
+	{TOK_WRITE, 0x70003D6C, 0x2C10},
+	{TOK_WRITE, 0x70003D6E, 0xDA03},
+	{TOK_WRITE, 0x70003D70, 0x8839},
+	{TOK_WRITE, 0x70003D72, 0x43A9},
+	{TOK_WRITE, 0x70003D74, 0x8039},
+	{TOK_WRITE, 0x70003D76, 0xE002},
+	{TOK_WRITE, 0x70003D78, 0x8879},
+	{TOK_WRITE, 0x70003D7A, 0x43B1},
+	{TOK_WRITE, 0x70003D7C, 0x8079},
+	{TOK_WRITE, 0x70003D7E, 0xF000},
+	{TOK_WRITE, 0x70003D80, 0xFAC3},
+	{TOK_WRITE, 0x70003D82, 0x2C10},
+	{TOK_WRITE, 0x70003D84, 0xDA03},
+	{TOK_WRITE, 0x70003D86, 0x8838},
+	{TOK_WRITE, 0x70003D88, 0x4328},
+	{TOK_WRITE, 0x70003D8A, 0x8038},
+	{TOK_WRITE, 0x70003D8C, 0xE002},
+	{TOK_WRITE, 0x70003D8E, 0x8878},
+	{TOK_WRITE, 0x70003D90, 0x4330},
+	{TOK_WRITE, 0x70003D92, 0x8078},
+	{TOK_WRITE, 0x70003D94, 0x48B6},
+	{TOK_WRITE, 0x70003D96, 0x8800},
+	{TOK_WRITE, 0x70003D98, 0x0400},
+	{TOK_WRITE, 0x70003D9A, 0xD507},
+	{TOK_WRITE, 0x70003D9C, 0x4BB5},
+	{TOK_WRITE, 0x70003D9E, 0x7819},
+	{TOK_WRITE, 0x70003DA0, 0x4AB5},
+	{TOK_WRITE, 0x70003DA2, 0x7810},
+	{TOK_WRITE, 0x70003DA4, 0x7018},
+	{TOK_WRITE, 0x70003DA6, 0x7011},
+	{TOK_WRITE, 0x70003DA8, 0x49B4},
+	{TOK_WRITE, 0x70003DAA, 0x8188},
+	{TOK_WRITE, 0x70003DAC, 0xBCF8},
+	{TOK_WRITE, 0x70003DAE, 0xBC08},
+	{TOK_WRITE, 0x70003DB0, 0x4718},
+	{TOK_WRITE, 0x70003DB2, 0xB538},
+	{TOK_WRITE, 0x70003DB4, 0x48B2},
+	{TOK_WRITE, 0x70003DB6, 0x4669},
+	{TOK_WRITE, 0x70003DB8, 0xF000},
+	{TOK_WRITE, 0x70003DBA, 0xFAAE},
+	{TOK_WRITE, 0x70003DBC, 0x48B1},
+	{TOK_WRITE, 0x70003DBE, 0x49B0},
+	{TOK_WRITE, 0x70003DC0, 0x69C2},
+	{TOK_WRITE, 0x70003DC2, 0x2400},
+	{TOK_WRITE, 0x70003DC4, 0x31A8},
+	{TOK_WRITE, 0x70003DC6, 0x2A00},
+	{TOK_WRITE, 0x70003DC8, 0xD008},
+	{TOK_WRITE, 0x70003DCA, 0x61C4},
+	{TOK_WRITE, 0x70003DCC, 0x684A},
+	{TOK_WRITE, 0x70003DCE, 0x6242},
+	{TOK_WRITE, 0x70003DD0, 0x6282},
+	{TOK_WRITE, 0x70003DD2, 0x466B},
+	{TOK_WRITE, 0x70003DD4, 0x881A},
+	{TOK_WRITE, 0x70003DD6, 0x6302},
+	{TOK_WRITE, 0x70003DD8, 0x885A},
+	{TOK_WRITE, 0x70003DDA, 0x6342},
+	{TOK_WRITE, 0x70003DDC, 0x6A02},
+	{TOK_WRITE, 0x70003DDE, 0x2A00},
+	{TOK_WRITE, 0x70003DE0, 0xD00A},
+	{TOK_WRITE, 0x70003DE2, 0x6204},
+	{TOK_WRITE, 0x70003DE4, 0x6849},
+	{TOK_WRITE, 0x70003DE6, 0x6281},
+	{TOK_WRITE, 0x70003DE8, 0x466B},
+	{TOK_WRITE, 0x70003DEA, 0x8819},
+	{TOK_WRITE, 0x70003DEC, 0x6301},
+	{TOK_WRITE, 0x70003DEE, 0x8859},
+	{TOK_WRITE, 0x70003DF0, 0x6341},
+	{TOK_WRITE, 0x70003DF2, 0x49A5},
+	{TOK_WRITE, 0x70003DF4, 0x88C9},
+	{TOK_WRITE, 0x70003DF6, 0x63C1},
+	{TOK_WRITE, 0x70003DF8, 0xF000},
+	{TOK_WRITE, 0x70003DFA, 0xFA96},
+	{TOK_WRITE, 0x70003DFC, 0xE7A6},
+	{TOK_WRITE, 0x70003DFE, 0xB5F0},
+	{TOK_WRITE, 0x70003E00, 0xB08B},
+	{TOK_WRITE, 0x70003E02, 0x20FF},
+	{TOK_WRITE, 0x70003E04, 0x1C40},
+	{TOK_WRITE, 0x70003E06, 0x49A1},
+	{TOK_WRITE, 0x70003E08, 0x89CC},
+	{TOK_WRITE, 0x70003E0A, 0x4E9E},
+	{TOK_WRITE, 0x70003E0C, 0x6AB1},
+	{TOK_WRITE, 0x70003E0E, 0x4284},
+	{TOK_WRITE, 0x70003E10, 0xD101},
+	{TOK_WRITE, 0x70003E12, 0x489F},
+	{TOK_WRITE, 0x70003E14, 0x6081},
+	{TOK_WRITE, 0x70003E16, 0x6A70},
+	{TOK_WRITE, 0x70003E18, 0x0200},
+	{TOK_WRITE, 0x70003E1A, 0xF000},
+	{TOK_WRITE, 0x70003E1C, 0xFA8D},
+	{TOK_WRITE, 0x70003E1E, 0x0400},
+	{TOK_WRITE, 0x70003E20, 0x0C00},
+	{TOK_WRITE, 0x70003E22, 0x4A96},
+	{TOK_WRITE, 0x70003E24, 0x8A11},
+	{TOK_WRITE, 0x70003E26, 0x9109},
+	{TOK_WRITE, 0x70003E28, 0x2101},
+	{TOK_WRITE, 0x70003E2A, 0x0349},
+	{TOK_WRITE, 0x70003E2C, 0x4288},
+	{TOK_WRITE, 0x70003E2E, 0xD200},
+	{TOK_WRITE, 0x70003E30, 0x0001},
+	{TOK_WRITE, 0x70003E32, 0x4A92},
+	{TOK_WRITE, 0x70003E34, 0x8211},
+	{TOK_WRITE, 0x70003E36, 0x4D97},
+	{TOK_WRITE, 0x70003E38, 0x8829},
+	{TOK_WRITE, 0x70003E3A, 0x9108},
+	{TOK_WRITE, 0x70003E3C, 0x4A8B},
+	{TOK_WRITE, 0x70003E3E, 0x2303},
+	{TOK_WRITE, 0x70003E40, 0x3222},
+	{TOK_WRITE, 0x70003E42, 0x1F91},
+	{TOK_WRITE, 0x70003E44, 0xF000},
+	{TOK_WRITE, 0x70003E46, 0xFA7E},
+	{TOK_WRITE, 0x70003E48, 0x8028},
+	{TOK_WRITE, 0x70003E4A, 0x488E},
+	{TOK_WRITE, 0x70003E4C, 0x4987},
+	{TOK_WRITE, 0x70003E4E, 0x6BC2},
+	{TOK_WRITE, 0x70003E50, 0x6AC0},
+	{TOK_WRITE, 0x70003E52, 0x4282},
+	{TOK_WRITE, 0x70003E54, 0xD201},
+	{TOK_WRITE, 0x70003E56, 0x8CC8},
+	{TOK_WRITE, 0x70003E58, 0x8028},
+	{TOK_WRITE, 0x70003E5A, 0x88E8},
+	{TOK_WRITE, 0x70003E5C, 0x9007},
+	{TOK_WRITE, 0x70003E5E, 0x2240},
+	{TOK_WRITE, 0x70003E60, 0x4310},
+	{TOK_WRITE, 0x70003E62, 0x80E8},
+	{TOK_WRITE, 0x70003E64, 0x2000},
+	{TOK_WRITE, 0x70003E66, 0x0041},
+	{TOK_WRITE, 0x70003E68, 0x194B},
+	{TOK_WRITE, 0x70003E6A, 0x001E},
+	{TOK_WRITE, 0x70003E6C, 0x3680},
+	{TOK_WRITE, 0x70003E6E, 0x8BB2},
+	{TOK_WRITE, 0x70003E70, 0xAF04},
+	{TOK_WRITE, 0x70003E72, 0x527A},
+	{TOK_WRITE, 0x70003E74, 0x4A7D},
+	{TOK_WRITE, 0x70003E76, 0x188A},
+	{TOK_WRITE, 0x70003E78, 0x8897},
+	{TOK_WRITE, 0x70003E7A, 0x83B7},
+	{TOK_WRITE, 0x70003E7C, 0x33A0},
+	{TOK_WRITE, 0x70003E7E, 0x891F},
+	{TOK_WRITE, 0x70003E80, 0xAE01},
+	{TOK_WRITE, 0x70003E82, 0x5277},
+	{TOK_WRITE, 0x70003E84, 0x8A11},
+	{TOK_WRITE, 0x70003E86, 0x8119},
+	{TOK_WRITE, 0x70003E88, 0x1C40},
+	{TOK_WRITE, 0x70003E8A, 0x0400},
+	{TOK_WRITE, 0x70003E8C, 0x0C00},
+	{TOK_WRITE, 0x70003E8E, 0x2806},
+	{TOK_WRITE, 0x70003E90, 0xD3E9},
+	{TOK_WRITE, 0x70003E92, 0xF000},
+	{TOK_WRITE, 0x70003E94, 0xFA5F},
+	{TOK_WRITE, 0x70003E96, 0xF000},
+	{TOK_WRITE, 0x70003E98, 0xFA65},
+	{TOK_WRITE, 0x70003E9A, 0x4F79},
+	{TOK_WRITE, 0x70003E9C, 0x37A8},
+	{TOK_WRITE, 0x70003E9E, 0x2800},
+	{TOK_WRITE, 0x70003EA0, 0xD10A},
+	{TOK_WRITE, 0x70003EA2, 0x1FE0},
+	{TOK_WRITE, 0x70003EA4, 0x38FD},
+	{TOK_WRITE, 0x70003EA6, 0xD001},
+	{TOK_WRITE, 0x70003EA8, 0x1CC0},
+	{TOK_WRITE, 0x70003EAA, 0xD105},
+	{TOK_WRITE, 0x70003EAC, 0x4874},
+	{TOK_WRITE, 0x70003EAE, 0x8829},
+	{TOK_WRITE, 0x70003EB0, 0x3818},
+	{TOK_WRITE, 0x70003EB2, 0x6840},
+	{TOK_WRITE, 0x70003EB4, 0x4348},
+	{TOK_WRITE, 0x70003EB6, 0x6078},
+	{TOK_WRITE, 0x70003EB8, 0x4972},
+	{TOK_WRITE, 0x70003EBA, 0x6878},
+	{TOK_WRITE, 0x70003EBC, 0x6B89},
+	{TOK_WRITE, 0x70003EBE, 0x4288},
+	{TOK_WRITE, 0x70003EC0, 0xD300},
+	{TOK_WRITE, 0x70003EC2, 0x0008},
+	{TOK_WRITE, 0x70003EC4, 0x6078},
+	{TOK_WRITE, 0x70003EC6, 0x2000},
+	{TOK_WRITE, 0x70003EC8, 0x0041},
+	{TOK_WRITE, 0x70003ECA, 0xAA04},
+	{TOK_WRITE, 0x70003ECC, 0x5A53},
+	{TOK_WRITE, 0x70003ECE, 0x194A},
+	{TOK_WRITE, 0x70003ED0, 0x269C},
+	{TOK_WRITE, 0x70003ED2, 0x52B3},
+	{TOK_WRITE, 0x70003ED4, 0xAB01},
+	{TOK_WRITE, 0x70003ED6, 0x5A59},
+	{TOK_WRITE, 0x70003ED8, 0x32A0},
+	{TOK_WRITE, 0x70003EDA, 0x8111},
+	{TOK_WRITE, 0x70003EDC, 0x1C40},
+	{TOK_WRITE, 0x70003EDE, 0x0400},
+	{TOK_WRITE, 0x70003EE0, 0x0C00},
+	{TOK_WRITE, 0x70003EE2, 0x2806},
+	{TOK_WRITE, 0x70003EE4, 0xD3F0},
+	{TOK_WRITE, 0x70003EE6, 0x4965},
+	{TOK_WRITE, 0x70003EE8, 0x9809},
+	{TOK_WRITE, 0x70003EEA, 0x8208},
+	{TOK_WRITE, 0x70003EEC, 0x9808},
+	{TOK_WRITE, 0x70003EEE, 0x8028},
+	{TOK_WRITE, 0x70003EF0, 0x9807},
+	{TOK_WRITE, 0x70003EF2, 0x80E8},
+	{TOK_WRITE, 0x70003EF4, 0x1FE0},
+	{TOK_WRITE, 0x70003EF6, 0x38FD},
+	{TOK_WRITE, 0x70003EF8, 0xD13B},
+	{TOK_WRITE, 0x70003EFA, 0x4D64},
+	{TOK_WRITE, 0x70003EFC, 0x89E8},
+	{TOK_WRITE, 0x70003EFE, 0x1FC1},
+	{TOK_WRITE, 0x70003F00, 0x39FF},
+	{TOK_WRITE, 0x70003F02, 0xD136},
+	{TOK_WRITE, 0x70003F04, 0x4C5F},
+	{TOK_WRITE, 0x70003F06, 0x8AE0},
+	{TOK_WRITE, 0x70003F08, 0xF000},
+	{TOK_WRITE, 0x70003F0A, 0xFA34},
+	{TOK_WRITE, 0x70003F0C, 0x0006},
+	{TOK_WRITE, 0x70003F0E, 0x8B20},
+	{TOK_WRITE, 0x70003F10, 0xF000},
+	{TOK_WRITE, 0x70003F12, 0xFA38},
+	{TOK_WRITE, 0x70003F14, 0x9000},
+	{TOK_WRITE, 0x70003F16, 0x6AA1},
+	{TOK_WRITE, 0x70003F18, 0x6878},
+	{TOK_WRITE, 0x70003F1A, 0x1809},
+	{TOK_WRITE, 0x70003F1C, 0x0200},
+	{TOK_WRITE, 0x70003F1E, 0xF000},
+	{TOK_WRITE, 0x70003F20, 0xFA0B},
+	{TOK_WRITE, 0x70003F22, 0x0400},
+	{TOK_WRITE, 0x70003F24, 0x0C00},
+	{TOK_WRITE, 0x70003F26, 0x0022},
+	{TOK_WRITE, 0x70003F28, 0x3246},
+	{TOK_WRITE, 0x70003F2A, 0x0011},
+	{TOK_WRITE, 0x70003F2C, 0x310A},
+	{TOK_WRITE, 0x70003F2E, 0x2305},
+	{TOK_WRITE, 0x70003F30, 0xF000},
+	{TOK_WRITE, 0x70003F32, 0xFA08},
+	{TOK_WRITE, 0x70003F34, 0x66E8},
+	{TOK_WRITE, 0x70003F36, 0x6B23},
+	{TOK_WRITE, 0x70003F38, 0x0002},
+	{TOK_WRITE, 0x70003F3A, 0x0031},
+	{TOK_WRITE, 0x70003F3C, 0x0018},
+	{TOK_WRITE, 0x70003F3E, 0xF000},
+	{TOK_WRITE, 0x70003F40, 0xFA29},
+	{TOK_WRITE, 0x70003F42, 0x466B},
+	{TOK_WRITE, 0x70003F44, 0x8518},
+	{TOK_WRITE, 0x70003F46, 0x6EEA},
+	{TOK_WRITE, 0x70003F48, 0x6B60},
+	{TOK_WRITE, 0x70003F4A, 0x9900},
+	{TOK_WRITE, 0x70003F4C, 0xF000},
+	{TOK_WRITE, 0x70003F4E, 0xFA22},
+	{TOK_WRITE, 0x70003F50, 0x466B},
+	{TOK_WRITE, 0x70003F52, 0x8558},
+	{TOK_WRITE, 0x70003F54, 0x0029},
+	{TOK_WRITE, 0x70003F56, 0x980A},
+	{TOK_WRITE, 0x70003F58, 0x3170},
+	{TOK_WRITE, 0x70003F5A, 0xF000},
+	{TOK_WRITE, 0x70003F5C, 0xFA23},
+	{TOK_WRITE, 0x70003F5E, 0x0028},
+	{TOK_WRITE, 0x70003F60, 0x3060},
+	{TOK_WRITE, 0x70003F62, 0x8A02},
+	{TOK_WRITE, 0x70003F64, 0x4946},
+	{TOK_WRITE, 0x70003F66, 0x3128},
+	{TOK_WRITE, 0x70003F68, 0x808A},
+	{TOK_WRITE, 0x70003F6A, 0x8A42},
+	{TOK_WRITE, 0x70003F6C, 0x80CA},
+	{TOK_WRITE, 0x70003F6E, 0x8A80},
+	{TOK_WRITE, 0x70003F70, 0x8108},
+	{TOK_WRITE, 0x70003F72, 0xB00B},
+	{TOK_WRITE, 0x70003F74, 0xBCF0},
+	{TOK_WRITE, 0x70003F76, 0xBC08},
+	{TOK_WRITE, 0x70003F78, 0x4718},
+	{TOK_WRITE, 0x70003F7A, 0xB570},
+	{TOK_WRITE, 0x70003F7C, 0x2400},
+	{TOK_WRITE, 0x70003F7E, 0x4D46},
+	{TOK_WRITE, 0x70003F80, 0x4846},
+	{TOK_WRITE, 0x70003F82, 0x8881},
+	{TOK_WRITE, 0x70003F84, 0x4846},
+	{TOK_WRITE, 0x70003F86, 0x8041},
+	{TOK_WRITE, 0x70003F88, 0x2101},
+	{TOK_WRITE, 0x70003F8A, 0x8001},
+	{TOK_WRITE, 0x70003F8C, 0xF000},
+	{TOK_WRITE, 0x70003F8E, 0xFA12},
+	{TOK_WRITE, 0x70003F90, 0x4842},
+	{TOK_WRITE, 0x70003F92, 0x3820},
+	{TOK_WRITE, 0x70003F94, 0x8BC0},
+	{TOK_WRITE, 0x70003F96, 0xF000},
+	{TOK_WRITE, 0x70003F98, 0xFA15},
+	{TOK_WRITE, 0x70003F9A, 0x4B42},
+	{TOK_WRITE, 0x70003F9C, 0x220D},
+	{TOK_WRITE, 0x70003F9E, 0x0712},
+	{TOK_WRITE, 0x70003FA0, 0x18A8},
+	{TOK_WRITE, 0x70003FA2, 0x8806},
+	{TOK_WRITE, 0x70003FA4, 0x00E1},
+	{TOK_WRITE, 0x70003FA6, 0x18C9},
+	{TOK_WRITE, 0x70003FA8, 0x81CE},
+	{TOK_WRITE, 0x70003FAA, 0x8846},
+	{TOK_WRITE, 0x70003FAC, 0x818E},
+	{TOK_WRITE, 0x70003FAE, 0x8886},
+	{TOK_WRITE, 0x70003FB0, 0x824E},
+	{TOK_WRITE, 0x70003FB2, 0x88C0},
+	{TOK_WRITE, 0x70003FB4, 0x8208},
+	{TOK_WRITE, 0x70003FB6, 0x3508},
+	{TOK_WRITE, 0x70003FB8, 0x042D},
+	{TOK_WRITE, 0x70003FBA, 0x0C2D},
+	{TOK_WRITE, 0x70003FBC, 0x1C64},
+	{TOK_WRITE, 0x70003FBE, 0x0424},
+	{TOK_WRITE, 0x70003FC0, 0x0C24},
+	{TOK_WRITE, 0x70003FC2, 0x2C07},
+	{TOK_WRITE, 0x70003FC4, 0xD3EC},
+	{TOK_WRITE, 0x70003FC6, 0xE658},
+	{TOK_WRITE, 0x70003FC8, 0xB510},
+	{TOK_WRITE, 0x70003FCA, 0x4834},
+	{TOK_WRITE, 0x70003FCC, 0x4C34},
+	{TOK_WRITE, 0x70003FCE, 0x88C0},
+	{TOK_WRITE, 0x70003FD0, 0x8060},
+	{TOK_WRITE, 0x70003FD2, 0x2001},
+	{TOK_WRITE, 0x70003FD4, 0x8020},
+	{TOK_WRITE, 0x70003FD6, 0x4831},
+	{TOK_WRITE, 0x70003FD8, 0x3820},
+	{TOK_WRITE, 0x70003FDA, 0x8BC0},
+	{TOK_WRITE, 0x70003FDC, 0xF000},
+	{TOK_WRITE, 0x70003FDE, 0xF9F2},
+	{TOK_WRITE, 0x70003FE0, 0x88E0},
+	{TOK_WRITE, 0x70003FE2, 0x4A31},
+	{TOK_WRITE, 0x70003FE4, 0x2800},
+	{TOK_WRITE, 0x70003FE6, 0xD003},
+	{TOK_WRITE, 0x70003FE8, 0x4930},
+	{TOK_WRITE, 0x70003FEA, 0x8849},
+	{TOK_WRITE, 0x70003FEC, 0x2900},
+	{TOK_WRITE, 0x70003FEE, 0xD009},
+	{TOK_WRITE, 0x70003FF0, 0x2001},
+	{TOK_WRITE, 0x70003FF2, 0x03C0},
+	{TOK_WRITE, 0x70003FF4, 0x8050},
+	{TOK_WRITE, 0x70003FF6, 0x80D0},
+	{TOK_WRITE, 0x70003FF8, 0x2000},
+	{TOK_WRITE, 0x70003FFA, 0x8090},
+	{TOK_WRITE, 0x70003FFC, 0x8110},
+	{TOK_WRITE, 0x70003FFE, 0xBC10},
+	{TOK_WRITE, 0x70004000, 0xBC08},
+	{TOK_WRITE, 0x70004002, 0x4718},
+	{TOK_WRITE, 0x70004004, 0x8050},
+	{TOK_WRITE, 0x70004006, 0x8920},
+	{TOK_WRITE, 0x70004008, 0x80D0},
+	{TOK_WRITE, 0x7000400A, 0x8960},
+	{TOK_WRITE, 0x7000400C, 0x0400},
+	{TOK_WRITE, 0x7000400E, 0x1400},
+	{TOK_WRITE, 0x70004010, 0x8090},
+	{TOK_WRITE, 0x70004012, 0x89A1},
+	{TOK_WRITE, 0x70004014, 0x0409},
+	{TOK_WRITE, 0x70004016, 0x1409},
+	{TOK_WRITE, 0x70004018, 0x8111},
+	{TOK_WRITE, 0x7000401A, 0x89E3},
+	{TOK_WRITE, 0x7000401C, 0x8A24},
+	{TOK_WRITE, 0x7000401E, 0x2B00},
+	{TOK_WRITE, 0x70004020, 0xD104},
+	{TOK_WRITE, 0x70004022, 0x17C3},
+	{TOK_WRITE, 0x70004024, 0x0F5B},
+	{TOK_WRITE, 0x70004026, 0x1818},
+	{TOK_WRITE, 0x70004028, 0x10C0},
+	{TOK_WRITE, 0x7000402A, 0x8090},
+	{TOK_WRITE, 0x7000402C, 0x2C00},
+	{TOK_WRITE, 0x7000402E, 0xD1E6},
+	{TOK_WRITE, 0x70004030, 0x17C8},
+	{TOK_WRITE, 0x70004032, 0x0F40},
+	{TOK_WRITE, 0x70004034, 0x1840},
+	{TOK_WRITE, 0x70004036, 0x10C0},
+	{TOK_WRITE, 0x70004038, 0x8110},
+	{TOK_WRITE, 0x7000403A, 0xE7E0},
+	{TOK_WRITE, 0x7000403C, 0xB510},
+	{TOK_WRITE, 0x7000403E, 0x000C},
+	{TOK_WRITE, 0x70004040, 0x4919},
+	{TOK_WRITE, 0x70004042, 0x2204},
+	{TOK_WRITE, 0x70004044, 0x6820},
+	{TOK_WRITE, 0x70004046, 0x5E8A},
+	{TOK_WRITE, 0x70004048, 0x0140},
+	{TOK_WRITE, 0x7000404A, 0x1A80},
+	{TOK_WRITE, 0x7000404C, 0x0280},
+	{TOK_WRITE, 0x7000404E, 0x8849},
+	{TOK_WRITE, 0x70004050, 0xF000},
+	{TOK_WRITE, 0x70004052, 0xF9C0},
+	{TOK_WRITE, 0x70004054, 0x6020},
+	{TOK_WRITE, 0x70004056, 0xE7D2},
+	{TOK_WRITE, 0x70004058, 0x38D4},
+	{TOK_WRITE, 0x7000405A, 0x7000},
+	{TOK_WRITE, 0x7000405C, 0x17D0},
+	{TOK_WRITE, 0x7000405E, 0x7000},
+	{TOK_WRITE, 0x70004060, 0x5000},
+	{TOK_WRITE, 0x70004062, 0xD000},
+	{TOK_WRITE, 0x70004064, 0x1100},
+	{TOK_WRITE, 0x70004066, 0xD000},
+	{TOK_WRITE, 0x70004068, 0x171A},
+	{TOK_WRITE, 0x7000406A, 0x7000},
+	{TOK_WRITE, 0x7000406C, 0x4780},
+	{TOK_WRITE, 0x7000406E, 0x7000},
+	{TOK_WRITE, 0x70004070, 0x2FCA},
+	{TOK_WRITE, 0x70004072, 0x7000},
+	{TOK_WRITE, 0x70004074, 0x2FC5},
+	{TOK_WRITE, 0x70004076, 0x7000},
+	{TOK_WRITE, 0x70004078, 0x2FC6},
+	{TOK_WRITE, 0x7000407A, 0x7000},
+	{TOK_WRITE, 0x7000407C, 0x2ED8},
+	{TOK_WRITE, 0x7000407E, 0x7000},
+	{TOK_WRITE, 0x70004080, 0x2BD0},
+	{TOK_WRITE, 0x70004082, 0x7000},
+	{TOK_WRITE, 0x70004084, 0x17E0},
+	{TOK_WRITE, 0x70004086, 0x7000},
+	{TOK_WRITE, 0x70004088, 0x2DE8},
+	{TOK_WRITE, 0x7000408A, 0x7000},
+	{TOK_WRITE, 0x7000408C, 0x37E0},
+	{TOK_WRITE, 0x7000408E, 0x7000},
+	{TOK_WRITE, 0x70004090, 0x210C},
+	{TOK_WRITE, 0x70004092, 0x7000},
+	{TOK_WRITE, 0x70004094, 0x1484},
+	{TOK_WRITE, 0x70004096, 0x7000},
+	{TOK_WRITE, 0x70004098, 0xA006},
+	{TOK_WRITE, 0x7000409A, 0x0000},
+	{TOK_WRITE, 0x7000409C, 0x0724},
+	{TOK_WRITE, 0x7000409E, 0x7000},
+	{TOK_WRITE, 0x700040A0, 0xA000},
+	{TOK_WRITE, 0x700040A2, 0xD000},
+	{TOK_WRITE, 0x700040A4, 0x2270},
+	{TOK_WRITE, 0x700040A6, 0x7000},
+	{TOK_WRITE, 0x700040A8, 0x2558},
+	{TOK_WRITE, 0x700040AA, 0x7000},
+	{TOK_WRITE, 0x700040AC, 0x146C},
+	{TOK_WRITE, 0x700040AE, 0x7000},
+	{TOK_WRITE, 0x700040B0, 0xB510},
+	{TOK_WRITE, 0x700040B2, 0x000C},
+	{TOK_WRITE, 0x700040B4, 0x4979},
+	{TOK_WRITE, 0x700040B6, 0x2208},
+	{TOK_WRITE, 0x700040B8, 0x6820},
+	{TOK_WRITE, 0x700040BA, 0x5E8A},
+	{TOK_WRITE, 0x700040BC, 0x0140},
+	{TOK_WRITE, 0x700040BE, 0x1A80},
+	{TOK_WRITE, 0x700040C0, 0x0280},
+	{TOK_WRITE, 0x700040C2, 0x88C9},
+	{TOK_WRITE, 0x700040C4, 0xF000},
+	{TOK_WRITE, 0x700040C6, 0xF986},
+	{TOK_WRITE, 0x700040C8, 0x6020},
+	{TOK_WRITE, 0x700040CA, 0xE798},
+	{TOK_WRITE, 0x700040CC, 0xB5FE},
+	{TOK_WRITE, 0x700040CE, 0x000C},
+	{TOK_WRITE, 0x700040D0, 0x6825},
+	{TOK_WRITE, 0x700040D2, 0x6866},
+	{TOK_WRITE, 0x700040D4, 0x68A0},
+	{TOK_WRITE, 0x700040D6, 0x9001},
+	{TOK_WRITE, 0x700040D8, 0x68E7},
+	{TOK_WRITE, 0x700040DA, 0x1BA8},
+	{TOK_WRITE, 0x700040DC, 0x42B5},
+	{TOK_WRITE, 0x700040DE, 0xDA00},
+	{TOK_WRITE, 0x700040E0, 0x1B70},
+	{TOK_WRITE, 0x700040E2, 0x9000},
+	{TOK_WRITE, 0x700040E4, 0x496D},
+	{TOK_WRITE, 0x700040E6, 0x486E},
+	{TOK_WRITE, 0x700040E8, 0x884A},
+	{TOK_WRITE, 0x700040EA, 0x8843},
+	{TOK_WRITE, 0x700040EC, 0x435A},
+	{TOK_WRITE, 0x700040EE, 0x2304},
+	{TOK_WRITE, 0x700040F0, 0x5ECB},
+	{TOK_WRITE, 0x700040F2, 0x0A92},
+	{TOK_WRITE, 0x700040F4, 0x18D2},
+	{TOK_WRITE, 0x700040F6, 0x02D2},
+	{TOK_WRITE, 0x700040F8, 0x0C12},
+	{TOK_WRITE, 0x700040FA, 0x88CB},
+	{TOK_WRITE, 0x700040FC, 0x8880},
+	{TOK_WRITE, 0x700040FE, 0x4343},
+	{TOK_WRITE, 0x70004100, 0x0A98},
+	{TOK_WRITE, 0x70004102, 0x2308},
+	{TOK_WRITE, 0x70004104, 0x5ECB},
+	{TOK_WRITE, 0x70004106, 0x18C0},
+	{TOK_WRITE, 0x70004108, 0x02C0},
+	{TOK_WRITE, 0x7000410A, 0x0C00},
+	{TOK_WRITE, 0x7000410C, 0x0411},
+	{TOK_WRITE, 0x7000410E, 0x0400},
+	{TOK_WRITE, 0x70004110, 0x1409},
+	{TOK_WRITE, 0x70004112, 0x1400},
+	{TOK_WRITE, 0x70004114, 0x1A08},
+	{TOK_WRITE, 0x70004116, 0x4962},
+	{TOK_WRITE, 0x70004118, 0x39E0},
+	{TOK_WRITE, 0x7000411A, 0x6148},
+	{TOK_WRITE, 0x7000411C, 0x9801},
+	{TOK_WRITE, 0x7000411E, 0x3040},
+	{TOK_WRITE, 0x70004120, 0x7880},
+	{TOK_WRITE, 0x70004122, 0x2800},
+	{TOK_WRITE, 0x70004124, 0xD103},
+	{TOK_WRITE, 0x70004126, 0x9801},
+	{TOK_WRITE, 0x70004128, 0x0029},
+	{TOK_WRITE, 0x7000412A, 0xF000},
+	{TOK_WRITE, 0x7000412C, 0xF959},
+	{TOK_WRITE, 0x7000412E, 0x8839},
+	{TOK_WRITE, 0x70004130, 0x9800},
+	{TOK_WRITE, 0x70004132, 0x4281},
+	{TOK_WRITE, 0x70004134, 0xD814},
+	{TOK_WRITE, 0x70004136, 0x8879},
+	{TOK_WRITE, 0x70004138, 0x9800},
+	{TOK_WRITE, 0x7000413A, 0x4281},
+	{TOK_WRITE, 0x7000413C, 0xD20C},
+	{TOK_WRITE, 0x7000413E, 0x9801},
+	{TOK_WRITE, 0x70004140, 0x0029},
+	{TOK_WRITE, 0x70004142, 0xF000},
+	{TOK_WRITE, 0x70004144, 0xF955},
+	{TOK_WRITE, 0x70004146, 0x9801},
+	{TOK_WRITE, 0x70004148, 0x0029},
+	{TOK_WRITE, 0x7000414A, 0xF000},
+	{TOK_WRITE, 0x7000414C, 0xF951},
+	{TOK_WRITE, 0x7000414E, 0x9801},
+	{TOK_WRITE, 0x70004150, 0x0029},
+	{TOK_WRITE, 0x70004152, 0xF000},
+	{TOK_WRITE, 0x70004154, 0xF94D},
+	{TOK_WRITE, 0x70004156, 0xE003},
+	{TOK_WRITE, 0x70004158, 0x9801},
+	{TOK_WRITE, 0x7000415A, 0x0029},
+	{TOK_WRITE, 0x7000415C, 0xF000},
+	{TOK_WRITE, 0x7000415E, 0xF948},
+	{TOK_WRITE, 0x70004160, 0x9801},
+	{TOK_WRITE, 0x70004162, 0x0032},
+	{TOK_WRITE, 0x70004164, 0x0039},
+	{TOK_WRITE, 0x70004166, 0xF000},
+	{TOK_WRITE, 0x70004168, 0xF94B},
+	{TOK_WRITE, 0x7000416A, 0x6020},
+	{TOK_WRITE, 0x7000416C, 0xE5D0},
+	{TOK_WRITE, 0x7000416E, 0xB57C},
+	{TOK_WRITE, 0x70004170, 0x484C},
+	{TOK_WRITE, 0x70004172, 0xA901},
+	{TOK_WRITE, 0x70004174, 0x0004},
+	{TOK_WRITE, 0x70004176, 0xF000},
+	{TOK_WRITE, 0x70004178, 0xF8CF},
+	{TOK_WRITE, 0x7000417A, 0x466B},
+	{TOK_WRITE, 0x7000417C, 0x88D9},
+	{TOK_WRITE, 0x7000417E, 0x8898},
+	{TOK_WRITE, 0x70004180, 0x4B47},
+	{TOK_WRITE, 0x70004182, 0x3346},
+	{TOK_WRITE, 0x70004184, 0x1E9A},
+	{TOK_WRITE, 0x70004186, 0xF000},
+	{TOK_WRITE, 0x70004188, 0xF943},
+	{TOK_WRITE, 0x7000418A, 0x4846},
+	{TOK_WRITE, 0x7000418C, 0x4944},
+	{TOK_WRITE, 0x7000418E, 0x3812},
+	{TOK_WRITE, 0x70004190, 0x3140},
+	{TOK_WRITE, 0x70004192, 0x8A42},
+	{TOK_WRITE, 0x70004194, 0x888B},
+	{TOK_WRITE, 0x70004196, 0x18D2},
+	{TOK_WRITE, 0x70004198, 0x8242},
+	{TOK_WRITE, 0x7000419A, 0x8AC2},
+	{TOK_WRITE, 0x7000419C, 0x88C9},
+	{TOK_WRITE, 0x7000419E, 0x1851},
+	{TOK_WRITE, 0x700041A0, 0x82C1},
+	{TOK_WRITE, 0x700041A2, 0x0020},
+	{TOK_WRITE, 0x700041A4, 0x4669},
+	{TOK_WRITE, 0x700041A6, 0xF000},
+	{TOK_WRITE, 0x700041A8, 0xF8B7},
+	{TOK_WRITE, 0x700041AA, 0x483F},
+	{TOK_WRITE, 0x700041AC, 0x214D},
+	{TOK_WRITE, 0x700041AE, 0x8301},
+	{TOK_WRITE, 0x700041B0, 0x2196},
+	{TOK_WRITE, 0x700041B2, 0x8381},
+	{TOK_WRITE, 0x700041B4, 0x211D},
+	{TOK_WRITE, 0x700041B6, 0x3020},
+	{TOK_WRITE, 0x700041B8, 0x8001},
+	{TOK_WRITE, 0x700041BA, 0xF000},
+	{TOK_WRITE, 0x700041BC, 0xF931},
+	{TOK_WRITE, 0x700041BE, 0xF000},
+	{TOK_WRITE, 0x700041C0, 0xF937},
+	{TOK_WRITE, 0x700041C2, 0x483A},
+	{TOK_WRITE, 0x700041C4, 0x4C3A},
+	{TOK_WRITE, 0x700041C6, 0x6E00},
+	{TOK_WRITE, 0x700041C8, 0x60E0},
+	{TOK_WRITE, 0x700041CA, 0x466B},
+	{TOK_WRITE, 0x700041CC, 0x8818},
+	{TOK_WRITE, 0x700041CE, 0x8859},
+	{TOK_WRITE, 0x700041D0, 0x0025},
+	{TOK_WRITE, 0x700041D2, 0x1A40},
+	{TOK_WRITE, 0x700041D4, 0x3540},
+	{TOK_WRITE, 0x700041D6, 0x61A8},
+	{TOK_WRITE, 0x700041D8, 0x4831},
+	{TOK_WRITE, 0x700041DA, 0x9900},
+	{TOK_WRITE, 0x700041DC, 0x3060},
+	{TOK_WRITE, 0x700041DE, 0xF000},
+	{TOK_WRITE, 0x700041E0, 0xF92F},
+	{TOK_WRITE, 0x700041E2, 0x466B},
+	{TOK_WRITE, 0x700041E4, 0x8819},
+	{TOK_WRITE, 0x700041E6, 0x1DE0},
+	{TOK_WRITE, 0x700041E8, 0x30F9},
+	{TOK_WRITE, 0x700041EA, 0x8741},
+	{TOK_WRITE, 0x700041EC, 0x8859},
+	{TOK_WRITE, 0x700041EE, 0x8781},
+	{TOK_WRITE, 0x700041F0, 0x2000},
+	{TOK_WRITE, 0x700041F2, 0x71A0},
+	{TOK_WRITE, 0x700041F4, 0x74A8},
+	{TOK_WRITE, 0x700041F6, 0xBC7C},
+	{TOK_WRITE, 0x700041F8, 0xBC08},
+	{TOK_WRITE, 0x700041FA, 0x4718},
+	{TOK_WRITE, 0x700041FC, 0xB5F8},
+	{TOK_WRITE, 0x700041FE, 0x0005},
+	{TOK_WRITE, 0x70004200, 0x6808},
+	{TOK_WRITE, 0x70004202, 0x0400},
+	{TOK_WRITE, 0x70004204, 0x0C00},
+	{TOK_WRITE, 0x70004206, 0x684A},
+	{TOK_WRITE, 0x70004208, 0x0412},
+	{TOK_WRITE, 0x7000420A, 0x0C12},
+	{TOK_WRITE, 0x7000420C, 0x688E},
+	{TOK_WRITE, 0x7000420E, 0x68CC},
+	{TOK_WRITE, 0x70004210, 0x4922},
+	{TOK_WRITE, 0x70004212, 0x884B},
+	{TOK_WRITE, 0x70004214, 0x4343},
+	{TOK_WRITE, 0x70004216, 0x0A98},
+	{TOK_WRITE, 0x70004218, 0x2304},
+	{TOK_WRITE, 0x7000421A, 0x5ECB},
+	{TOK_WRITE, 0x7000421C, 0x18C0},
+	{TOK_WRITE, 0x7000421E, 0x02C0},
+	{TOK_WRITE, 0x70004220, 0x0C00},
+	{TOK_WRITE, 0x70004222, 0x88CB},
+	{TOK_WRITE, 0x70004224, 0x4353},
+	{TOK_WRITE, 0x70004226, 0x0A9A},
+	{TOK_WRITE, 0x70004228, 0x2308},
+	{TOK_WRITE, 0x7000422A, 0x5ECB},
+	{TOK_WRITE, 0x7000422C, 0x18D1},
+	{TOK_WRITE, 0x7000422E, 0x02C9},
+	{TOK_WRITE, 0x70004230, 0x0C09},
+	{TOK_WRITE, 0x70004232, 0x2701},
+	{TOK_WRITE, 0x70004234, 0x003A},
+	{TOK_WRITE, 0x70004236, 0x40AA},
+	{TOK_WRITE, 0x70004238, 0x9200},
+	{TOK_WRITE, 0x7000423A, 0x002A},
+	{TOK_WRITE, 0x7000423C, 0x3A10},
+	{TOK_WRITE, 0x7000423E, 0x4097},
+	{TOK_WRITE, 0x70004240, 0x2D10},
+	{TOK_WRITE, 0x70004242, 0xDA06},
+	{TOK_WRITE, 0x70004244, 0x4A1B},
+	{TOK_WRITE, 0x70004246, 0x9B00},
+	{TOK_WRITE, 0x70004248, 0x8812},
+	{TOK_WRITE, 0x7000424A, 0x439A},
+	{TOK_WRITE, 0x7000424C, 0x4B19},
+	{TOK_WRITE, 0x7000424E, 0x801A},
+	{TOK_WRITE, 0x70004250, 0xE003},
+	{TOK_WRITE, 0x70004252, 0x4B18},
+	{TOK_WRITE, 0x70004254, 0x885A},
+	{TOK_WRITE, 0x70004256, 0x43BA},
+	{TOK_WRITE, 0x70004258, 0x805A},
+	{TOK_WRITE, 0x7000425A, 0x0023},
+	{TOK_WRITE, 0x7000425C, 0x0032},
+	{TOK_WRITE, 0x7000425E, 0xF000},
+	{TOK_WRITE, 0x70004260, 0xF8D7},
+	{TOK_WRITE, 0x70004262, 0x2D10},
+	{TOK_WRITE, 0x70004264, 0xDA05},
+	{TOK_WRITE, 0x70004266, 0x4913},
+	{TOK_WRITE, 0x70004268, 0x9A00},
+	{TOK_WRITE, 0x7000426A, 0x8808},
+	{TOK_WRITE, 0x7000426C, 0x4310},
+	{TOK_WRITE, 0x7000426E, 0x8008},
+	{TOK_WRITE, 0x70004270, 0xE003},
+	{TOK_WRITE, 0x70004272, 0x4810},
+	{TOK_WRITE, 0x70004274, 0x8841},
+	{TOK_WRITE, 0x70004276, 0x4339},
+	{TOK_WRITE, 0x70004278, 0x8041},
+	{TOK_WRITE, 0x7000427A, 0x4D0D},
+	{TOK_WRITE, 0x7000427C, 0x2000},
+	{TOK_WRITE, 0x7000427E, 0x3580},
+	{TOK_WRITE, 0x70004280, 0x88AA},
+	{TOK_WRITE, 0x70004282, 0x5E30},
+	{TOK_WRITE, 0x70004284, 0x2100},
+	{TOK_WRITE, 0x70004286, 0xF000},
+	{TOK_WRITE, 0x70004288, 0xF8E3},
+	{TOK_WRITE, 0x7000428A, 0x8030},
+	{TOK_WRITE, 0x7000428C, 0x2000},
+	{TOK_WRITE, 0x7000428E, 0x88AA},
+	{TOK_WRITE, 0x70004290, 0x5E20},
+	{TOK_WRITE, 0x70004292, 0x2100},
+	{TOK_WRITE, 0x70004294, 0xF000},
+	{TOK_WRITE, 0x70004296, 0xF8DC},
+	{TOK_WRITE, 0x70004298, 0x8020},
+	{TOK_WRITE, 0x7000429A, 0xE587},
+	{TOK_WRITE, 0x7000429C, 0x2558},
+	{TOK_WRITE, 0x7000429E, 0x7000},
+	{TOK_WRITE, 0x700042A0, 0x2AB8},
+	{TOK_WRITE, 0x700042A2, 0x7000},
+	{TOK_WRITE, 0x700042A4, 0x145E},
+	{TOK_WRITE, 0x700042A6, 0x7000},
+	{TOK_WRITE, 0x700042A8, 0x2698},
+	{TOK_WRITE, 0x700042AA, 0x7000},
+	{TOK_WRITE, 0x700042AC, 0x2BB8},
+	{TOK_WRITE, 0x700042AE, 0x7000},
+	{TOK_WRITE, 0x700042B0, 0x2998},
+	{TOK_WRITE, 0x700042B2, 0x7000},
+	{TOK_WRITE, 0x700042B4, 0x1100},
+	{TOK_WRITE, 0x700042B6, 0xD000},
+	{TOK_WRITE, 0x700042B8, 0x4778},
+	{TOK_WRITE, 0x700042BA, 0x46C0},
+	{TOK_WRITE, 0x700042BC, 0xC000},
+	{TOK_WRITE, 0x700042BE, 0xE59F},
+	{TOK_WRITE, 0x700042C0, 0xFF1C},
+	{TOK_WRITE, 0x700042C2, 0xE12F},
+	{TOK_WRITE, 0x700042C4, 0x1789},
+	{TOK_WRITE, 0x700042C6, 0x0001},
+	{TOK_WRITE, 0x700042C8, 0x4778},
+	{TOK_WRITE, 0x700042CA, 0x46C0},
+	{TOK_WRITE, 0x700042CC, 0xC000},
+	{TOK_WRITE, 0x700042CE, 0xE59F},
+	{TOK_WRITE, 0x700042D0, 0xFF1C},
+	{TOK_WRITE, 0x700042D2, 0xE12F},
+	{TOK_WRITE, 0x700042D4, 0x16F1},
+	{TOK_WRITE, 0x700042D6, 0x0001},
+	{TOK_WRITE, 0x700042D8, 0x4778},
+	{TOK_WRITE, 0x700042DA, 0x46C0},
+	{TOK_WRITE, 0x700042DC, 0xC000},
+	{TOK_WRITE, 0x700042DE, 0xE59F},
+	{TOK_WRITE, 0x700042E0, 0xFF1C},
+	{TOK_WRITE, 0x700042E2, 0xE12F},
+	{TOK_WRITE, 0x700042E4, 0xC3B1},
+	{TOK_WRITE, 0x700042E6, 0x0000},
+	{TOK_WRITE, 0x700042E8, 0x4778},
+	{TOK_WRITE, 0x700042EA, 0x46C0},
+	{TOK_WRITE, 0x700042EC, 0xC000},
+	{TOK_WRITE, 0x700042EE, 0xE59F},
+	{TOK_WRITE, 0x700042F0, 0xFF1C},
+	{TOK_WRITE, 0x700042F2, 0xE12F},
+	{TOK_WRITE, 0x700042F4, 0xC36D},
+	{TOK_WRITE, 0x700042F6, 0x0000},
+	{TOK_WRITE, 0x700042F8, 0x4778},
+	{TOK_WRITE, 0x700042FA, 0x46C0},
+	{TOK_WRITE, 0x700042FC, 0xC000},
+	{TOK_WRITE, 0x700042FE, 0xE59F},
+	{TOK_WRITE, 0x70004300, 0xFF1C},
+	{TOK_WRITE, 0x70004302, 0xE12F},
+	{TOK_WRITE, 0x70004304, 0xF6D7},
+	{TOK_WRITE, 0x70004306, 0x0000},
+	{TOK_WRITE, 0x70004308, 0x4778},
+	{TOK_WRITE, 0x7000430A, 0x46C0},
+	{TOK_WRITE, 0x7000430C, 0xC000},
+	{TOK_WRITE, 0x7000430E, 0xE59F},
+	{TOK_WRITE, 0x70004310, 0xFF1C},
+	{TOK_WRITE, 0x70004312, 0xE12F},
+	{TOK_WRITE, 0x70004314, 0xB49D},
+	{TOK_WRITE, 0x70004316, 0x0000},
+	{TOK_WRITE, 0x70004318, 0x4778},
+	{TOK_WRITE, 0x7000431A, 0x46C0},
+	{TOK_WRITE, 0x7000431C, 0xC000},
+	{TOK_WRITE, 0x7000431E, 0xE59F},
+	{TOK_WRITE, 0x70004320, 0xFF1C},
+	{TOK_WRITE, 0x70004322, 0xE12F},
+	{TOK_WRITE, 0x70004324, 0x7EDF},
+	{TOK_WRITE, 0x70004326, 0x0000},
+	{TOK_WRITE, 0x70004328, 0x4778},
+	{TOK_WRITE, 0x7000432A, 0x46C0},
+	{TOK_WRITE, 0x7000432C, 0xC000},
+	{TOK_WRITE, 0x7000432E, 0xE59F},
+	{TOK_WRITE, 0x70004330, 0xFF1C},
+	{TOK_WRITE, 0x70004332, 0xE12F},
+	{TOK_WRITE, 0x70004334, 0x448D},
+	{TOK_WRITE, 0x70004336, 0x0000},
+	{TOK_WRITE, 0x70004338, 0x4778},
+	{TOK_WRITE, 0x7000433A, 0x46C0},
+	{TOK_WRITE, 0x7000433C, 0xF004},
+	{TOK_WRITE, 0x7000433E, 0xE51F},
+	{TOK_WRITE, 0x70004340, 0x29EC},
+	{TOK_WRITE, 0x70004342, 0x0001},
+	{TOK_WRITE, 0x70004344, 0x4778},
+	{TOK_WRITE, 0x70004346, 0x46C0},
+	{TOK_WRITE, 0x70004348, 0xC000},
+	{TOK_WRITE, 0x7000434A, 0xE59F},
+	{TOK_WRITE, 0x7000434C, 0xFF1C},
+	{TOK_WRITE, 0x7000434E, 0xE12F},
+	{TOK_WRITE, 0x70004350, 0x2EF1},
+	{TOK_WRITE, 0x70004352, 0x0000},
+	{TOK_WRITE, 0x70004354, 0x4778},
+	{TOK_WRITE, 0x70004356, 0x46C0},
+	{TOK_WRITE, 0x70004358, 0xC000},
+	{TOK_WRITE, 0x7000435A, 0xE59F},
+	{TOK_WRITE, 0x7000435C, 0xFF1C},
+	{TOK_WRITE, 0x7000435E, 0xE12F},
+	{TOK_WRITE, 0x70004360, 0xEE03},
+	{TOK_WRITE, 0x70004362, 0x0000},
+	{TOK_WRITE, 0x70004364, 0x4778},
+	{TOK_WRITE, 0x70004366, 0x46C0},
+	{TOK_WRITE, 0x70004368, 0xC000},
+	{TOK_WRITE, 0x7000436A, 0xE59F},
+	{TOK_WRITE, 0x7000436C, 0xFF1C},
+	{TOK_WRITE, 0x7000436E, 0xE12F},
+	{TOK_WRITE, 0x70004370, 0xA58B},
+	{TOK_WRITE, 0x70004372, 0x0000},
+	{TOK_WRITE, 0x70004374, 0x4778},
+	{TOK_WRITE, 0x70004376, 0x46C0},
+	{TOK_WRITE, 0x70004378, 0xC000},
+	{TOK_WRITE, 0x7000437A, 0xE59F},
+	{TOK_WRITE, 0x7000437C, 0xFF1C},
+	{TOK_WRITE, 0x7000437E, 0xE12F},
+	{TOK_WRITE, 0x70004380, 0x7C49},
+	{TOK_WRITE, 0x70004382, 0x0000},
+	{TOK_WRITE, 0x70004384, 0x4778},
+	{TOK_WRITE, 0x70004386, 0x46C0},
+	{TOK_WRITE, 0x70004388, 0xC000},
+	{TOK_WRITE, 0x7000438A, 0xE59F},
+	{TOK_WRITE, 0x7000438C, 0xFF1C},
+	{TOK_WRITE, 0x7000438E, 0xE12F},
+	{TOK_WRITE, 0x70004390, 0x7C63},
+	{TOK_WRITE, 0x70004392, 0x0000},
+	{TOK_WRITE, 0x70004394, 0x4778},
+	{TOK_WRITE, 0x70004396, 0x46C0},
+	{TOK_WRITE, 0x70004398, 0xC000},
+	{TOK_WRITE, 0x7000439A, 0xE59F},
+	{TOK_WRITE, 0x7000439C, 0xFF1C},
+	{TOK_WRITE, 0x7000439E, 0xE12F},
+	{TOK_WRITE, 0x700043A0, 0x2DB7},
+	{TOK_WRITE, 0x700043A2, 0x0000},
+	{TOK_WRITE, 0x700043A4, 0x4778},
+	{TOK_WRITE, 0x700043A6, 0x46C0},
+	{TOK_WRITE, 0x700043A8, 0xC000},
+	{TOK_WRITE, 0x700043AA, 0xE59F},
+	{TOK_WRITE, 0x700043AC, 0xFF1C},
+	{TOK_WRITE, 0x700043AE, 0xE12F},
+	{TOK_WRITE, 0x700043B0, 0xEB3D},
+	{TOK_WRITE, 0x700043B2, 0x0000},
+	{TOK_WRITE, 0x700043B4, 0x4778},
+	{TOK_WRITE, 0x700043B6, 0x46C0},
+	{TOK_WRITE, 0x700043B8, 0xC000},
+	{TOK_WRITE, 0x700043BA, 0xE59F},
+	{TOK_WRITE, 0x700043BC, 0xFF1C},
+	{TOK_WRITE, 0x700043BE, 0xE12F},
+	{TOK_WRITE, 0x700043C0, 0xF061},
+	{TOK_WRITE, 0x700043C2, 0x0000},
+	{TOK_WRITE, 0x700043C4, 0x4778},
+	{TOK_WRITE, 0x700043C6, 0x46C0},
+	{TOK_WRITE, 0x700043C8, 0xC000},
+	{TOK_WRITE, 0x700043CA, 0xE59F},
+	{TOK_WRITE, 0x700043CC, 0xFF1C},
+	{TOK_WRITE, 0x700043CE, 0xE12F},
+	{TOK_WRITE, 0x700043D0, 0xF0EF},
+	{TOK_WRITE, 0x700043D2, 0x0000},
+	{TOK_WRITE, 0x700043D4, 0x4778},
+	{TOK_WRITE, 0x700043D6, 0x46C0},
+	{TOK_WRITE, 0x700043D8, 0xF004},
+	{TOK_WRITE, 0x700043DA, 0xE51F},
+	{TOK_WRITE, 0x700043DC, 0x2824},
+	{TOK_WRITE, 0x700043DE, 0x0001},
+	{TOK_WRITE, 0x700043E0, 0x4778},
+	{TOK_WRITE, 0x700043E2, 0x46C0},
+	{TOK_WRITE, 0x700043E4, 0xC000},
+	{TOK_WRITE, 0x700043E6, 0xE59F},
+	{TOK_WRITE, 0x700043E8, 0xFF1C},
+	{TOK_WRITE, 0x700043EA, 0xE12F},
+	{TOK_WRITE, 0x700043EC, 0x8EDD},
+	{TOK_WRITE, 0x700043EE, 0x0000},
+	{TOK_WRITE, 0x700043F0, 0x4778},
+	{TOK_WRITE, 0x700043F2, 0x46C0},
+	{TOK_WRITE, 0x700043F4, 0xC000},
+	{TOK_WRITE, 0x700043F6, 0xE59F},
+	{TOK_WRITE, 0x700043F8, 0xFF1C},
+	{TOK_WRITE, 0x700043FA, 0xE12F},
+	{TOK_WRITE, 0x700043FC, 0x8DCB},
+	{TOK_WRITE, 0x700043FE, 0x0000},
+	{TOK_WRITE, 0x70004400, 0x4778},
+	{TOK_WRITE, 0x70004402, 0x46C0},
+	{TOK_WRITE, 0x70004404, 0xC000},
+	{TOK_WRITE, 0x70004406, 0xE59F},
+	{TOK_WRITE, 0x70004408, 0xFF1C},
+	{TOK_WRITE, 0x7000440A, 0xE12F},
+	{TOK_WRITE, 0x7000440C, 0x8E17},
+	{TOK_WRITE, 0x7000440E, 0x0000},
+	{TOK_WRITE, 0x70004410, 0x4778},
+	{TOK_WRITE, 0x70004412, 0x46C0},
+	{TOK_WRITE, 0x70004414, 0xC000},
+	{TOK_WRITE, 0x70004416, 0xE59F},
+	{TOK_WRITE, 0x70004418, 0xFF1C},
+	{TOK_WRITE, 0x7000441A, 0xE12F},
+	{TOK_WRITE, 0x7000441C, 0x98C5},
+	{TOK_WRITE, 0x7000441E, 0x0000},
+	{TOK_WRITE, 0x70004420, 0x4778},
+	{TOK_WRITE, 0x70004422, 0x46C0},
+	{TOK_WRITE, 0x70004424, 0xC000},
+	{TOK_WRITE, 0x70004426, 0xE59F},
+	{TOK_WRITE, 0x70004428, 0xFF1C},
+	{TOK_WRITE, 0x7000442A, 0xE12F},
+	{TOK_WRITE, 0x7000442C, 0x7C7D},
+	{TOK_WRITE, 0x7000442E, 0x0000},
+	{TOK_WRITE, 0x70004430, 0x4778},
+	{TOK_WRITE, 0x70004432, 0x46C0},
+	{TOK_WRITE, 0x70004434, 0xC000},
+	{TOK_WRITE, 0x70004436, 0xE59F},
+	{TOK_WRITE, 0x70004438, 0xFF1C},
+	{TOK_WRITE, 0x7000443A, 0xE12F},
+	{TOK_WRITE, 0x7000443C, 0x7E31},
+	{TOK_WRITE, 0x7000443E, 0x0000},
+	{TOK_WRITE, 0x70004440, 0x4778},
+	{TOK_WRITE, 0x70004442, 0x46C0},
+	{TOK_WRITE, 0x70004444, 0xC000},
+	{TOK_WRITE, 0x70004446, 0xE59F},
+	{TOK_WRITE, 0x70004448, 0xFF1C},
+	{TOK_WRITE, 0x7000444A, 0xE12F},
+	{TOK_WRITE, 0x7000444C, 0x7EAB},
+	{TOK_WRITE, 0x7000444E, 0x0000},
+	{TOK_WRITE, 0x70004450, 0x4778},
+	{TOK_WRITE, 0x70004452, 0x46C0},
+	{TOK_WRITE, 0x70004454, 0xC000},
+	{TOK_WRITE, 0x70004456, 0xE59F},
+	{TOK_WRITE, 0x70004458, 0xFF1C},
+	{TOK_WRITE, 0x7000445A, 0xE12F},
+	{TOK_WRITE, 0x7000445C, 0x7501},
+	{TOK_WRITE, 0x7000445E, 0x0000},
+	{TOK_WRITE, 0xD0001000, 0x0001},
+	{TOK_WRITE, 0x700001FC, 0x0001},
+	{TOK_WRITE, 0x700001FE, 0x0003},
+	{TOK_WRITE, 0x70000200, 0x0000},
+	{TOK_WRITE, 0x70000204, 0x0061},
+	{TOK_WRITE, 0x7000020C, 0x2F0C},
+	{TOK_WRITE, 0x7000020E, 0x0190},
+	{TOK_WRITE, 0x70000294, 0x0100},
+	{TOK_WRITE, 0x70000296, 0x00E3},
+	{TOK_WRITE, 0x70000298, 0x0200},
+	{TOK_WRITE, 0x7000029A, 0x0238},
+	{TOK_WRITE, 0x7000029C, 0x01C6},
+	{TOK_WRITE, 0x7000029E, 0x0166},
+	{TOK_WRITE, 0x700002A0, 0x0074},
+	{TOK_WRITE, 0x700002A2, 0x0132},
+	{TOK_WRITE, 0x700002A4, 0x0001},
+	{TOK_WRITE, 0x7000070E, 0x00FF},
+	{TOK_WRITE, 0x7000071E, 0x0001},
+	{TOK_WRITE, 0x7000163C, 0x0000},
+	{TOK_WRITE, 0x70001648, 0x9002},
+	{TOK_WRITE, 0x70001652, 0x0002},
+	{TOK_WRITE, 0x70001654, 0x0000},
+	{TOK_WRITE, 0x700015E0, 0x0801},
+	{TOK_WRITE, 0x7000164C, 0x0003},
+	{TOK_WRITE, 0x7000163E, 0x00E5},
+	{TOK_WRITE, 0x70001640, 0x00CC},
+	{TOK_WRITE, 0x700015D4, 0x0000},
+	{TOK_WRITE, 0x700015D6, 0xD000},
+	{TOK_WRITE, 0x7000169A, 0xFF95},
+	{TOK_WRITE, 0x7000166A, 0x0280},
+	{TOK_WRITE, 0x70001676, 0x03A0},
+	{TOK_WRITE, 0x70001678, 0x0320},
+	{TOK_WRITE, 0x700016BC, 0x0030},
+	{TOK_WRITE, 0x700016E0, 0x0060},
+	{TOK_WRITE, 0x700016D4, 0x0010},
+	{TOK_WRITE, 0x70001656, 0x0000},
+	{TOK_WRITE, 0x700015E6, 0x003C},
+	{TOK_WRITE, 0x700015E8, 0x0015},
+	{TOK_WRITE, 0x700015EA, 0x0032},
+	{TOK_WRITE, 0x700015EC, 0x0038},
+	{TOK_WRITE, 0x700015EE, 0x003E},
+	{TOK_WRITE, 0x700015F0, 0x0044},
+	{TOK_WRITE, 0x700015F2, 0x004A},
+	{TOK_WRITE, 0x700015F4, 0x0050},
+	{TOK_WRITE, 0x700015F6, 0x0056},
+	{TOK_WRITE, 0x700015F8, 0x005C},
+	{TOK_WRITE, 0x700015FA, 0x0062},
+	{TOK_WRITE, 0x700015FC, 0x0068},
+	{TOK_WRITE, 0x700015FE, 0x006E},
+	{TOK_WRITE, 0x70001600, 0x0074},
+	{TOK_WRITE, 0x70001602, 0x007A},
+	{TOK_WRITE, 0x70001604, 0x0080},
+	{TOK_WRITE, 0x70001606, 0x0086},
+	{TOK_WRITE, 0x70001608, 0x008C},
+	{TOK_WRITE, 0x7000160A, 0x0092},
+	{TOK_WRITE, 0x7000160C, 0x0098},
+	{TOK_WRITE, 0x7000160E, 0x009E},
+	{TOK_WRITE, 0x70001610, 0x00A4},
+	{TOK_WRITE, 0x70001612, 0x00AA},
+	{TOK_WRITE, 0x70001614, 0x00B0},
+	{TOK_WRITE, 0x70001722, 0x8000},
+	{TOK_WRITE, 0x70001724, 0x0006},
+	{TOK_WRITE, 0x70001726, 0x3FF0},
+	{TOK_WRITE, 0x70001728, 0x03E8},
+	{TOK_WRITE, 0x7000172A, 0x0000},
+	{TOK_WRITE, 0x7000172C, 0x0080},
+	{TOK_WRITE, 0x7000172E, 0x0009},
+	{TOK_WRITE, 0x70001730, 0x0020},
+	{TOK_WRITE, 0x70001732, 0x0040},
+	{TOK_WRITE, 0x70001734, 0x0080},
+	{TOK_WRITE, 0x70001736, 0x00C0},
+	{TOK_WRITE, 0x70001738, 0x00E0},
+	{TOK_WRITE, 0x7000028C, 0x0003},
+	{TOK_WRITE, 0x700008B4, 0x0001},
+	{TOK_WRITE, 0x700008BC, 0x00C0},
+	{TOK_WRITE, 0x700008BE, 0x00DF},
+	{TOK_WRITE, 0x700008C0, 0x0100},
+	{TOK_WRITE, 0x700008C2, 0x0125},
+	{TOK_WRITE, 0x700008C4, 0x015F},
+	{TOK_WRITE, 0x700008C6, 0x017C},
+	{TOK_WRITE, 0x700008C8, 0x0194},
+	{TOK_WRITE, 0x700008F6, 0x4000},
+	{TOK_WRITE, 0x700008F8, 0x4000},
+	{TOK_WRITE, 0x700008FA, 0x4000},
+	{TOK_WRITE, 0x700008FC, 0x4000},
+	{TOK_WRITE, 0x700008FE, 0x4000},
+	{TOK_WRITE, 0x70000900, 0x4000},
+	{TOK_WRITE, 0x70000902, 0x4000},
+	{TOK_WRITE, 0x70000904, 0x4000},
+	{TOK_WRITE, 0x70000906, 0x4000},
+	{TOK_WRITE, 0x70000908, 0x4000},
+	{TOK_WRITE, 0x7000090A, 0x4000},
+	{TOK_WRITE, 0x7000090C, 0x4000},
+	{TOK_WRITE, 0x7000090E, 0x3800},
+	{TOK_WRITE, 0x70000910, 0x4000},
+	{TOK_WRITE, 0x70000912, 0x4000},
+	{TOK_WRITE, 0x70000914, 0x4000},
+	{TOK_WRITE, 0x70000916, 0x3B00},
+	{TOK_WRITE, 0x70000918, 0x4000},
+	{TOK_WRITE, 0x7000091A, 0x4000},
+	{TOK_WRITE, 0x7000091C, 0x4000},
+	{TOK_WRITE, 0x7000091E, 0x4300},
+	{TOK_WRITE, 0x70000920, 0x4000},
+	{TOK_WRITE, 0x70000922, 0x4000},
+	{TOK_WRITE, 0x70000924, 0x4000},
+	{TOK_WRITE, 0x70000926, 0x4300},
+	{TOK_WRITE, 0x70000928, 0x4000},
+	{TOK_WRITE, 0x7000092A, 0x4000},
+	{TOK_WRITE, 0x7000092C, 0x4000},
+	{TOK_WRITE, 0x7000092E, 0x4500},
+	{TOK_WRITE, 0x70000930, 0x4000},
+	{TOK_WRITE, 0x70000932, 0x4000},
+	{TOK_WRITE, 0x70000934, 0x4000},
+	{TOK_WRITE, 0x700008F4, 0x0001},
+	{TOK_WRITE, 0x70001492, 0x0100},
+	{TOK_WRITE, 0x70001494, 0x0101},
+	{TOK_WRITE, 0x70001496, 0x0101},
+	{TOK_WRITE, 0x70001498, 0x0001},
+	{TOK_WRITE, 0x7000149A, 0x0101},
+	{TOK_WRITE, 0x7000149C, 0x0201},
+	{TOK_WRITE, 0x7000149E, 0x0102},
+	{TOK_WRITE, 0x700014A0, 0x0101},
+	{TOK_WRITE, 0x700014A2, 0x0101},
+	{TOK_WRITE, 0x700014A4, 0x0202},
+	{TOK_WRITE, 0x700014A6, 0x0202},
+	{TOK_WRITE, 0x700014A8, 0x0101},
+	{TOK_WRITE, 0x700014AA, 0x0201},
+	{TOK_WRITE, 0x700014AC, 0x0302},
+	{TOK_WRITE, 0x700014AE, 0x0203},
+	{TOK_WRITE, 0x700014B0, 0x0102},
+	{TOK_WRITE, 0x700014B2, 0x0201},
+	{TOK_WRITE, 0x700014B4, 0x0302},
+	{TOK_WRITE, 0x700014B6, 0x0203},
+	{TOK_WRITE, 0x700014B8, 0x0102},
+	{TOK_WRITE, 0x700014BA, 0x0201},
+	{TOK_WRITE, 0x700014BC, 0x0202},
+	{TOK_WRITE, 0x700014BE, 0x0202},
+	{TOK_WRITE, 0x700014C0, 0x0102},
+	{TOK_WRITE, 0x700014C2, 0x0101},
+	{TOK_WRITE, 0x700014C4, 0x0202},
+	{TOK_WRITE, 0x700014C6, 0x0202},
+	{TOK_WRITE, 0x700014C8, 0x0101},
+	{TOK_WRITE, 0x700014CA, 0x0101},
+	{TOK_WRITE, 0x700014CC, 0x0101},
+	{TOK_WRITE, 0x700014CE, 0x0101},
+	{TOK_WRITE, 0x700014D0, 0x0101},
+	{TOK_WRITE, 0x70001484, 0x003C},
+	{TOK_WRITE, 0x7000148A, 0x000F},
+	{TOK_WRITE, 0x7000058C, 0x3520},
+	{TOK_WRITE, 0x7000058E, 0x0000},
+	{TOK_WRITE, 0x70000590, 0xC350},
+	{TOK_WRITE, 0x70000592, 0x0000},
+	{TOK_WRITE, 0x70000594, 0x3520},
+	{TOK_WRITE, 0x70000596, 0x0000},
+	{TOK_WRITE, 0x70000598, 0xC350},
+	{TOK_WRITE, 0x7000059A, 0x0000},
+	{TOK_WRITE, 0x7000059C, 0x0470},
+	{TOK_WRITE, 0x7000059E, 0x0C00},
+	{TOK_WRITE, 0x700005A0, 0x0100},
+	{TOK_WRITE, 0x700005A2, 0x1000},
+	{TOK_WRITE, 0x70000544, 0x0111},
+	{TOK_WRITE, 0x70000546, 0x00EF},
+	{TOK_WRITE, 0x70000F2A, 0x0000},
+	{TOK_WRITE, 0x700004E6, 0x077F},
+	{TOK_WRITE, 0x70000F30, 0x0001},
+	{TOK_WRITE, 0x70000608, 0x0001},
+	{TOK_WRITE, 0x7000060A, 0x0001},
+	{TOK_WRITE, 0x7000060C, 0x0800},
+	{TOK_WRITE, 0x7000060E, 0x0100},
+	{TOK_WRITE, 0x70000610, 0x0001},
+	{TOK_WRITE, 0x70000612, 0x0000},
+	{TOK_WRITE, 0x70000614, 0x0A3C},
+	{TOK_WRITE, 0x70000616, 0x0000},
+	{TOK_WRITE, 0x70000618, 0x0D05},
+	{TOK_WRITE, 0x7000061A, 0x0000},
+	{TOK_WRITE, 0x7000061C, 0x4008},
+	{TOK_WRITE, 0x7000061E, 0x0000},
+	{TOK_WRITE, 0x70000620, 0x7000},
+	{TOK_WRITE, 0x70000622, 0x0000},
+	{TOK_WRITE, 0x70000624, 0x9C00},
+	{TOK_WRITE, 0x70000626, 0x0000},
+	{TOK_WRITE, 0x70000628, 0xAD00},
+	{TOK_WRITE, 0x7000062A, 0x0001},
+	{TOK_WRITE, 0x7000062C, 0xF1D4},
+	{TOK_WRITE, 0x7000062E, 0x0002},
+	{TOK_WRITE, 0x70000630, 0xDC00},
+	{TOK_WRITE, 0x70000632, 0x0005},
+	{TOK_WRITE, 0x70000634, 0xDC00},
+	{TOK_WRITE, 0x70000636, 0x0005},
+	{TOK_WRITE, 0x70000638, 0x0001},
+	{TOK_WRITE, 0x7000063A, 0x0000},
+	{TOK_WRITE, 0x7000063C, 0x0A3C},
+	{TOK_WRITE, 0x7000063E, 0x0000},
+	{TOK_WRITE, 0x70000640, 0x0D05},
+	{TOK_WRITE, 0x70000642, 0x0000},
+	{TOK_WRITE, 0x70000644, 0x3408},
+	{TOK_WRITE, 0x70000646, 0x0000},
+	{TOK_WRITE, 0x70000648, 0x3408},
+	{TOK_WRITE, 0x7000064A, 0x0000},
+	{TOK_WRITE, 0x7000064C, 0x6810},
+	{TOK_WRITE, 0x7000064E, 0x0000},
+	{TOK_WRITE, 0x70000650, 0x8214},
+	{TOK_WRITE, 0x70000652, 0x0000},
+	{TOK_WRITE, 0x70000654, 0xC350},
+	{TOK_WRITE, 0x70000656, 0x0000},
+	{TOK_WRITE, 0x70000658, 0xC350},
+	{TOK_WRITE, 0x7000065A, 0x0000},
+	{TOK_WRITE, 0x7000065C, 0xC350},
+	{TOK_WRITE, 0x7000065E, 0x0000},
+	{TOK_WRITE, 0x70000660, 0x0650},
+	{TOK_WRITE, 0x70000662, 0x0100},
+	{TOK_WRITE, 0x700006B8, 0x452C},
+	{TOK_WRITE, 0x700006BA, 0x0005},
+	{TOK_WRITE, 0x700005D0, 0x0000},
+	{TOK_WRITE, 0x7000145E, 0x0580},
+	{TOK_WRITE, 0x70001460, 0x0428},
+	{TOK_WRITE, 0x70001462, 0x07B0},
+	{TOK_WRITE, 0x700011F0, 0x0120},
+	{TOK_WRITE, 0x700011F2, 0x0121},
+	{TOK_WRITE, 0x7000101C, 0x037C},
+	{TOK_WRITE, 0x7000101E, 0x038E},
+	{TOK_WRITE, 0x70001020, 0x033C},
+	{TOK_WRITE, 0x70001022, 0x0384},
+	{TOK_WRITE, 0x70001024, 0x02FE},
+	{TOK_WRITE, 0x70001026, 0x036C},
+	{TOK_WRITE, 0x70001028, 0x02BA},
+	{TOK_WRITE, 0x7000102A, 0x0352},
+	{TOK_WRITE, 0x7000102C, 0x028E},
+	{TOK_WRITE, 0x7000102E, 0x0300},
+	{TOK_WRITE, 0x70001030, 0x026A},
+	{TOK_WRITE, 0x70001032, 0x02C8},
+	{TOK_WRITE, 0x70001034, 0x0254},
+	{TOK_WRITE, 0x70001036, 0x02A8},
+	{TOK_WRITE, 0x70001038, 0x0242},
+	{TOK_WRITE, 0x7000103A, 0x02A0},
+	{TOK_WRITE, 0x7000103C, 0x021A},
+	{TOK_WRITE, 0x7000103E, 0x02A0},
+	{TOK_WRITE, 0x70001040, 0x01F4},
+	{TOK_WRITE, 0x70001042, 0x0298},
+	{TOK_WRITE, 0x70001044, 0x01D4},
+	{TOK_WRITE, 0x70001046, 0x0290},
+	{TOK_WRITE, 0x70001048, 0x01CC},
+	{TOK_WRITE, 0x7000104A, 0x0276},
+	{TOK_WRITE, 0x7000104C, 0x01D2},
+	{TOK_WRITE, 0x7000104E, 0x0260},
+	{TOK_WRITE, 0x70001050, 0x01F6},
+	{TOK_WRITE, 0x70001052, 0x023A},
+	{TOK_WRITE, 0x70001054, 0x0000},
+	{TOK_WRITE, 0x70001056, 0x0000},
+	{TOK_WRITE, 0x70001058, 0x0000},
+	{TOK_WRITE, 0x7000105A, 0x0000},
+	{TOK_WRITE, 0x7000105C, 0x0000},
+	{TOK_WRITE, 0x7000105E, 0x0000},
+	{TOK_WRITE, 0x70001060, 0x0000},
+	{TOK_WRITE, 0x70001062, 0x0000},
+	{TOK_WRITE, 0x70001064, 0x0000},
+	{TOK_WRITE, 0x70001066, 0x0000},
+	{TOK_WRITE, 0x70001068, 0x0000},
+	{TOK_WRITE, 0x7000106A, 0x0000},
+	{TOK_WRITE, 0x7000106C, 0x0005},
+	{TOK_WRITE, 0x70001070, 0x000E},
+	{TOK_WRITE, 0x70001074, 0x0126},
+	{TOK_WRITE, 0x70001078, 0x0272},
+	{TOK_WRITE, 0x7000107A, 0x02A0},
+	{TOK_WRITE, 0x7000107C, 0x025A},
+	{TOK_WRITE, 0x7000107E, 0x02BC},
+	{TOK_WRITE, 0x70001080, 0x024A},
+	{TOK_WRITE, 0x70001082, 0x02C0},
+	{TOK_WRITE, 0x70001084, 0x023C},
+	{TOK_WRITE, 0x70001086, 0x02BE},
+	{TOK_WRITE, 0x70001088, 0x022E},
+	{TOK_WRITE, 0x7000108A, 0x02BC},
+	{TOK_WRITE, 0x7000108C, 0x0224},
+	{TOK_WRITE, 0x7000108E, 0x02B6},
+	{TOK_WRITE, 0x70001090, 0x0218},
+	{TOK_WRITE, 0x70001092, 0x02AA},
+	{TOK_WRITE, 0x70001094, 0x0210},
+	{TOK_WRITE, 0x70001096, 0x02A0},
+	{TOK_WRITE, 0x70001098, 0x020C},
+	{TOK_WRITE, 0x7000109A, 0x0296},
+	{TOK_WRITE, 0x7000109C, 0x020A},
+	{TOK_WRITE, 0x7000109E, 0x028C},
+	{TOK_WRITE, 0x700010A0, 0x0212},
+	{TOK_WRITE, 0x700010A2, 0x027E},
+	{TOK_WRITE, 0x700010A4, 0x0234},
+	{TOK_WRITE, 0x700010A6, 0x0256},
+	{TOK_WRITE, 0x700010A8, 0x0004},
+	{TOK_WRITE, 0x700010AC, 0x000C},
+	{TOK_WRITE, 0x700010B0, 0x01D8},
+	{TOK_WRITE, 0x700010B4, 0x0350},
+	{TOK_WRITE, 0x700010B6, 0x0422},
+	{TOK_WRITE, 0x700010B8, 0x02C4},
+	{TOK_WRITE, 0x700010BA, 0x0452},
+	{TOK_WRITE, 0x700010BC, 0x0278},
+	{TOK_WRITE, 0x700010BE, 0x041C},
+	{TOK_WRITE, 0x700010C0, 0x0230},
+	{TOK_WRITE, 0x700010C2, 0x03EE},
+	{TOK_WRITE, 0x700010C4, 0x01F0},
+	{TOK_WRITE, 0x700010C6, 0x0392},
+	{TOK_WRITE, 0x700010C8, 0x01C0},
+	{TOK_WRITE, 0x700010CA, 0x0340},
+	{TOK_WRITE, 0x700010CC, 0x0194},
+	{TOK_WRITE, 0x700010CE, 0x0302},
+	{TOK_WRITE, 0x700010D0, 0x016E},
+	{TOK_WRITE, 0x700010D2, 0x02C2},
+	{TOK_WRITE, 0x700010D4, 0x0148},
+	{TOK_WRITE, 0x700010D6, 0x0286},
+	{TOK_WRITE, 0x700010D8, 0x018A},
+	{TOK_WRITE, 0x700010DA, 0x0242},
+	{TOK_WRITE, 0x700010DC, 0x0000},
+	{TOK_WRITE, 0x700010DE, 0x0000},
+	{TOK_WRITE, 0x700010E0, 0x0000},
+	{TOK_WRITE, 0x700010E2, 0x0000},
+	{TOK_WRITE, 0x700010E4, 0x0006},
+	{TOK_WRITE, 0x700010E8, 0x000A},
+	{TOK_WRITE, 0x700010EC, 0x0106},
+	{TOK_WRITE, 0x700010F0, 0x0380},
+	{TOK_WRITE, 0x700010F2, 0x0000},
+	{TOK_WRITE, 0x700010F4, 0x0168},
+	{TOK_WRITE, 0x700010F6, 0x0000},
+	{TOK_WRITE, 0x700010F8, 0x2D90},
+	{TOK_WRITE, 0x700010FA, 0x0000},
+	{TOK_WRITE, 0x70001464, 0x0008},
+	{TOK_WRITE, 0x70001466, 0x0190},
+	{TOK_WRITE, 0x70001468, 0x00A0},
+	{TOK_WRITE, 0x70001228, 0x00C0},
+	{TOK_WRITE, 0x7000122C, 0x0010},
+	{TOK_WRITE, 0x7000122A, 0x0010},
+	{TOK_WRITE, 0x7000120A, 0x05D5},
+	{TOK_WRITE, 0x7000120E, 0x0000},
+	{TOK_WRITE, 0x70001210, 0x0771},
+	{TOK_WRITE, 0x70001212, 0x03A4},
+	{TOK_WRITE, 0x70001214, 0x0036},
+	{TOK_WRITE, 0x70001216, 0x002A},
+	{TOK_WRITE, 0x70001278, 0xFEF7},
+	{TOK_WRITE, 0x7000127A, 0x0021},
+	{TOK_WRITE, 0x7000127C, 0x0AF0},
+	{TOK_WRITE, 0x7000127E, 0x0AF0},
+	{TOK_WRITE, 0x70001280, 0x018F},
+	{TOK_WRITE, 0x70001282, 0x0096},
+	{TOK_WRITE, 0x70001284, 0x000E},
+	{TOK_WRITE, 0x70001224, 0x0032},
+	{TOK_WRITE, 0x70001226, 0x001E},
+	{TOK_WRITE, 0x70001228, 0x00C0},
+	{TOK_WRITE, 0x7000122A, 0x0010},
+	{TOK_WRITE, 0x7000122C, 0x0002},
+	{TOK_WRITE, 0x70002BA4, 0x0006},
+	{TOK_WRITE, 0x7000146C, 0x0002},
+	{TOK_WRITE, 0x70001434, 0x02CE},
+	{TOK_WRITE, 0x70001436, 0x0347},
+	{TOK_WRITE, 0x70001438, 0x03C2},
+	{TOK_WRITE, 0x7000143A, 0x10A0},
+	{TOK_WRITE, 0x7000143C, 0x10A1},
+	{TOK_WRITE, 0x7000143E, 0x1185},
+	{TOK_WRITE, 0x70001440, 0x1186},
+	{TOK_WRITE, 0x70001442, 0x11E5},
+	{TOK_WRITE, 0x70001444, 0x11E6},
+	{TOK_WRITE, 0x70001446, 0x00AB},
+	{TOK_WRITE, 0x70001448, 0x00BF},
+	{TOK_WRITE, 0x7000144A, 0x00D2},
+	{TOK_WRITE, 0x7000144C, 0x0093},
+	{TOK_WRITE, 0x700013A4, 0xFFF6},
+	{TOK_WRITE, 0x700013A6, 0xFFD8},
+	{TOK_WRITE, 0x700013A8, 0xFFD8},
+	{TOK_WRITE, 0x700013AA, 0xFFD8},
+	{TOK_WRITE, 0x700013AC, 0xFFD8},
+	{TOK_WRITE, 0x700013AE, 0xFFD0},
+	{TOK_WRITE, 0x700013B0, 0xFFF6},
+	{TOK_WRITE, 0x700013B2, 0xFFD8},
+	{TOK_WRITE, 0x700013B4, 0xFFD8},
+	{TOK_WRITE, 0x700013B6, 0xFFD8},
+	{TOK_WRITE, 0x700013B8, 0xFFD8},
+	{TOK_WRITE, 0x700013BA, 0xFFD0},
+	{TOK_WRITE, 0x700013BC, 0xFFF6},
+	{TOK_WRITE, 0x700013BE, 0xFFD8},
+	{TOK_WRITE, 0x700013C0, 0xFFD8},
+	{TOK_WRITE, 0x700013C2, 0xFFD8},
+	{TOK_WRITE, 0x700013C4, 0xFFD8},
+	{TOK_WRITE, 0x700013C6, 0xFFD0},
+	{TOK_WRITE, 0x700013C8, 0xFFEC},
+	{TOK_WRITE, 0x700013CA, 0x000A},
+	{TOK_WRITE, 0x700013CC, 0x000A},
+	{TOK_WRITE, 0x700013CE, 0x0050},
+	{TOK_WRITE, 0x700013D0, 0x0050},
+	{TOK_WRITE, 0x700013D2, 0x0078},
+	{TOK_WRITE, 0x700013D4, 0xFFEC},
+	{TOK_WRITE, 0x700013D6, 0x000A},
+	{TOK_WRITE, 0x700013D8, 0x000A},
+	{TOK_WRITE, 0x700013DA, 0x0050},
+	{TOK_WRITE, 0x700013DC, 0x0050},
+	{TOK_WRITE, 0x700013DE, 0x0078},
+	{TOK_WRITE, 0x700013E0, 0xFFEC},
+	{TOK_WRITE, 0x700013E2, 0x000A},
+	{TOK_WRITE, 0x700013E4, 0x000A},
+	{TOK_WRITE, 0x700013E6, 0x0050},
+	{TOK_WRITE, 0x700013E8, 0x0050},
+	{TOK_WRITE, 0x700013EA, 0x0078},
+	{TOK_WRITE, 0x700013EC, 0x0000},
+	{TOK_WRITE, 0x700013EE, 0x0000},
+	{TOK_WRITE, 0x700013F0, 0x0000},
+	{TOK_WRITE, 0x700013F2, 0x0000},
+	{TOK_WRITE, 0x700013F4, 0x0000},
+	{TOK_WRITE, 0x700013F6, 0x0000},
+	{TOK_WRITE, 0x700013F8, 0x0000},
+	{TOK_WRITE, 0x700013FA, 0x0000},
+	{TOK_WRITE, 0x700013FC, 0x0000},
+	{TOK_WRITE, 0x700013FE, 0x0000},
+	{TOK_WRITE, 0x70001400, 0x0000},
+	{TOK_WRITE, 0x70001402, 0x0000},
+	{TOK_WRITE, 0x70001404, 0x0000},
+	{TOK_WRITE, 0x70001406, 0x0000},
+	{TOK_WRITE, 0x70001408, 0x0000},
+	{TOK_WRITE, 0x7000140A, 0x0000},
+	{TOK_WRITE, 0x7000140C, 0x0000},
+	{TOK_WRITE, 0x7000140E, 0x0000},
+	{TOK_WRITE, 0x70001410, 0xFFC0},
+	{TOK_WRITE, 0x70001412, 0xFFC0},
+	{TOK_WRITE, 0x70001414, 0xFFC0},
+	{TOK_WRITE, 0x70001416, 0x0000},
+	{TOK_WRITE, 0x70001418, 0x0000},
+	{TOK_WRITE, 0x7000141A, 0x0000},
+	{TOK_WRITE, 0x7000141C, 0xFFC0},
+	{TOK_WRITE, 0x7000141E, 0xFFC0},
+	{TOK_WRITE, 0x70001420, 0xFFC0},
+	{TOK_WRITE, 0x70001422, 0x0000},
+	{TOK_WRITE, 0x70001424, 0x0000},
+	{TOK_WRITE, 0x70001426, 0x0000},
+	{TOK_WRITE, 0x70001428, 0xFFC0},
+	{TOK_WRITE, 0x7000142A, 0xFFC0},
+	{TOK_WRITE, 0x7000142C, 0xFFC0},
+	{TOK_WRITE, 0x7000142E, 0x0000},
+	{TOK_WRITE, 0x70001430, 0x0000},
+	{TOK_WRITE, 0x70001432, 0x0000},
+	{TOK_WRITE, 0x70001208, 0x0020},
+	{TOK_WRITE, 0x7000144E, 0x0000},
+	{TOK_WRITE, 0x70001450, 0xFFE0},
+	{TOK_WRITE, 0x70001452, 0x0000},
+	{TOK_WRITE, 0x70000734, 0x0000},
+	{TOK_WRITE, 0x70000736, 0x000A},
+	{TOK_WRITE, 0x70000738, 0x0016},
+	{TOK_WRITE, 0x7000073A, 0x0030},
+	{TOK_WRITE, 0x7000073C, 0x0066},
+	{TOK_WRITE, 0x7000073E, 0x00D5},
+	{TOK_WRITE, 0x70000740, 0x0138},
+	{TOK_WRITE, 0x70000742, 0x0163},
+	{TOK_WRITE, 0x70000744, 0x0189},
+	{TOK_WRITE, 0x70000746, 0x01C6},
+	{TOK_WRITE, 0x70000748, 0x01F8},
+	{TOK_WRITE, 0x7000074A, 0x0222},
+	{TOK_WRITE, 0x7000074C, 0x0247},
+	{TOK_WRITE, 0x7000074E, 0x0282},
+	{TOK_WRITE, 0x70000750, 0x02B5},
+	{TOK_WRITE, 0x70000752, 0x030F},
+	{TOK_WRITE, 0x70000754, 0x035F},
+	{TOK_WRITE, 0x70000756, 0x03A2},
+	{TOK_WRITE, 0x70000758, 0x03D8},
+	{TOK_WRITE, 0x7000075A, 0x03FF},
+	{TOK_WRITE, 0x7000075C, 0x0000},
+	{TOK_WRITE, 0x7000075E, 0x000A},
+	{TOK_WRITE, 0x70000760, 0x0016},
+	{TOK_WRITE, 0x70000762, 0x0030},
+	{TOK_WRITE, 0x70000764, 0x0066},
+	{TOK_WRITE, 0x70000766, 0x00D5},
+	{TOK_WRITE, 0x70000768, 0x0138},
+	{TOK_WRITE, 0x7000076A, 0x0163},
+	{TOK_WRITE, 0x7000076C, 0x0189},
+	{TOK_WRITE, 0x7000076E, 0x01C6},
+	{TOK_WRITE, 0x70000770, 0x01F8},
+	{TOK_WRITE, 0x70000772, 0x0222},
+	{TOK_WRITE, 0x70000774, 0x0247},
+	{TOK_WRITE, 0x70000776, 0x0282},
+	{TOK_WRITE, 0x70000778, 0x02B5},
+	{TOK_WRITE, 0x7000077A, 0x030F},
+	{TOK_WRITE, 0x7000077C, 0x035F},
+	{TOK_WRITE, 0x7000077E, 0x03A2},
+	{TOK_WRITE, 0x70000780, 0x03D8},
+	{TOK_WRITE, 0x70000782, 0x03FF},
+	{TOK_WRITE, 0x70000784, 0x0000},
+	{TOK_WRITE, 0x70000786, 0x000A},
+	{TOK_WRITE, 0x70000788, 0x0016},
+	{TOK_WRITE, 0x7000078A, 0x0030},
+	{TOK_WRITE, 0x7000078C, 0x0066},
+	{TOK_WRITE, 0x7000078E, 0x00D5},
+	{TOK_WRITE, 0x70000790, 0x0138},
+	{TOK_WRITE, 0x70000792, 0x0163},
+	{TOK_WRITE, 0x70000794, 0x0189},
+	{TOK_WRITE, 0x70000796, 0x01C6},
+	{TOK_WRITE, 0x70000798, 0x01F8},
+	{TOK_WRITE, 0x7000079A, 0x0222},
+	{TOK_WRITE, 0x7000079C, 0x0247},
+	{TOK_WRITE, 0x7000079E, 0x0282},
+	{TOK_WRITE, 0x700007A0, 0x02B5},
+	{TOK_WRITE, 0x700007A2, 0x030F},
+	{TOK_WRITE, 0x700007A4, 0x035F},
+	{TOK_WRITE, 0x700007A6, 0x03A2},
+	{TOK_WRITE, 0x700007A8, 0x03D8},
+	{TOK_WRITE, 0x700007AA, 0x03FF},
+	{TOK_WRITE, 0x700007AC, 0x0000},
+	{TOK_WRITE, 0x700007AE, 0x000B},
+	{TOK_WRITE, 0x700007B0, 0x0019},
+	{TOK_WRITE, 0x700007B2, 0x0036},
+	{TOK_WRITE, 0x700007B4, 0x006F},
+	{TOK_WRITE, 0x700007B6, 0x00D8},
+	{TOK_WRITE, 0x700007B8, 0x0135},
+	{TOK_WRITE, 0x700007BA, 0x015F},
+	{TOK_WRITE, 0x700007BC, 0x0185},
+	{TOK_WRITE, 0x700007BE, 0x01C1},
+	{TOK_WRITE, 0x700007C0, 0x01F3},
+	{TOK_WRITE, 0x700007C2, 0x0220},
+	{TOK_WRITE, 0x700007C4, 0x024A},
+	{TOK_WRITE, 0x700007C6, 0x0291},
+	{TOK_WRITE, 0x700007C8, 0x02D0},
+	{TOK_WRITE, 0x700007CA, 0x032A},
+	{TOK_WRITE, 0x700007CC, 0x036A},
+	{TOK_WRITE, 0x700007CE, 0x039F},
+	{TOK_WRITE, 0x700007D0, 0x03CC},
+	{TOK_WRITE, 0x700007D2, 0x03F9},
+	{TOK_WRITE, 0x700007D4, 0x0000},
+	{TOK_WRITE, 0x700007D6, 0x000B},
+	{TOK_WRITE, 0x700007D8, 0x0019},
+	{TOK_WRITE, 0x700007DA, 0x0036},
+	{TOK_WRITE, 0x700007DC, 0x006F},
+	{TOK_WRITE, 0x700007DE, 0x00D8},
+	{TOK_WRITE, 0x700007E0, 0x0135},
+	{TOK_WRITE, 0x700007E2, 0x015F},
+	{TOK_WRITE, 0x700007E4, 0x0185},
+	{TOK_WRITE, 0x700007E6, 0x01C1},
+	{TOK_WRITE, 0x700007E8, 0x01F3},
+	{TOK_WRITE, 0x700007EA, 0x0220},
+	{TOK_WRITE, 0x700007EC, 0x024A},
+	{TOK_WRITE, 0x700007EE, 0x0291},
+	{TOK_WRITE, 0x700007F0, 0x02D0},
+	{TOK_WRITE, 0x700007F2, 0x032A},
+	{TOK_WRITE, 0x700007F4, 0x036A},
+	{TOK_WRITE, 0x700007F6, 0x039F},
+	{TOK_WRITE, 0x700007F8, 0x03CC},
+	{TOK_WRITE, 0x700007FA, 0x03F9},
+	{TOK_WRITE, 0x700007FC, 0x0000},
+	{TOK_WRITE, 0x700007FE, 0x000B},
+	{TOK_WRITE, 0x70000800, 0x0019},
+	{TOK_WRITE, 0x70000802, 0x0036},
+	{TOK_WRITE, 0x70000804, 0x006F},
+	{TOK_WRITE, 0x70000806, 0x00D8},
+	{TOK_WRITE, 0x70000808, 0x0135},
+	{TOK_WRITE, 0x7000080A, 0x015F},
+	{TOK_WRITE, 0x7000080C, 0x0185},
+	{TOK_WRITE, 0x7000080E, 0x01C1},
+	{TOK_WRITE, 0x70000810, 0x01F3},
+	{TOK_WRITE, 0x70000812, 0x0220},
+	{TOK_WRITE, 0x70000814, 0x024A},
+	{TOK_WRITE, 0x70000816, 0x0291},
+	{TOK_WRITE, 0x70000818, 0x02D0},
+	{TOK_WRITE, 0x7000081A, 0x032A},
+	{TOK_WRITE, 0x7000081C, 0x036A},
+	{TOK_WRITE, 0x7000081E, 0x039F},
+	{TOK_WRITE, 0x70000820, 0x03CC},
+	{TOK_WRITE, 0x70000822, 0x03F9},
+	{TOK_WRITE, 0x700008A6, 0x00C0},
+	{TOK_WRITE, 0x700008A8, 0x0100},
+	{TOK_WRITE, 0x700008AA, 0x0125},
+	{TOK_WRITE, 0x700008AC, 0x015F},
+	{TOK_WRITE, 0x700008AE, 0x017C},
+	{TOK_WRITE, 0x700008B0, 0x0194},
+	{TOK_WRITE, 0x700008B2, 0x0001},
+	{TOK_WRITE, 0x70000898, 0x4800},
+	{TOK_WRITE, 0x7000089A, 0x7000},
+	{TOK_WRITE, 0x700008A0, 0x48D8},
+	{TOK_WRITE, 0x700008A2, 0x7000},
+	{TOK_WRITE, 0x70004800, 0x024C},
+	{TOK_WRITE, 0x70004802, 0xFF5E},
+	{TOK_WRITE, 0x70004804, 0xFF9D},
+	{TOK_WRITE, 0x70004806, 0xFEC9},
+	{TOK_WRITE, 0x70004808, 0x0203},
+	{TOK_WRITE, 0x7000480A, 0xFF08},
+	{TOK_WRITE, 0x7000480C, 0xFFDB},
+	{TOK_WRITE, 0x7000480E, 0xFF8F},
+	{TOK_WRITE, 0x70004810, 0x0206},
+	{TOK_WRITE, 0x70004812, 0x00E0},
+	{TOK_WRITE, 0x70004814, 0x009F},
+	{TOK_WRITE, 0x70004816, 0xFE7B},
+	{TOK_WRITE, 0x70004818, 0x0227},
+	{TOK_WRITE, 0x7000481A, 0xFEFE},
+	{TOK_WRITE, 0x7000481C, 0x0194},
+	{TOK_WRITE, 0x7000481E, 0xFE86},
+	{TOK_WRITE, 0x70004820, 0x01E0},
+	{TOK_WRITE, 0x70004822, 0x0104},
+	{TOK_WRITE, 0x70004824, 0x024C},
+	{TOK_WRITE, 0x70004826, 0xFF5E},
+	{TOK_WRITE, 0x70004828, 0xFF9D},
+	{TOK_WRITE, 0x7000482A, 0xFEC9},
+	{TOK_WRITE, 0x7000482C, 0x0203},
+	{TOK_WRITE, 0x7000482E, 0xFF08},
+	{TOK_WRITE, 0x70004830, 0xFFDB},
+	{TOK_WRITE, 0x70004832, 0xFF8F},
+	{TOK_WRITE, 0x70004834, 0x0206},
+	{TOK_WRITE, 0x70004836, 0x00E0},
+	{TOK_WRITE, 0x70004838, 0x009F},
+	{TOK_WRITE, 0x7000483A, 0xFE7B},
+	{TOK_WRITE, 0x7000483C, 0x0227},
+	{TOK_WRITE, 0x7000483E, 0xFEFE},
+	{TOK_WRITE, 0x70004840, 0x0194},
+	{TOK_WRITE, 0x70004842, 0xFE86},
+	{TOK_WRITE, 0x70004844, 0x01E0},
+	{TOK_WRITE, 0x70004846, 0x0104},
+	{TOK_WRITE, 0x70004848, 0x0208},
+	{TOK_WRITE, 0x7000484A, 0xFFB5},
+	{TOK_WRITE, 0x7000484C, 0xFFE8},
+	{TOK_WRITE, 0x7000484E, 0xFF20},
+	{TOK_WRITE, 0x70004850, 0x01BF},
+	{TOK_WRITE, 0x70004852, 0xFF53},
+	{TOK_WRITE, 0x70004854, 0x0022},
+	{TOK_WRITE, 0x70004856, 0xFFEA},
+	{TOK_WRITE, 0x70004858, 0x01C2},
+	{TOK_WRITE, 0x7000485A, 0x00C6},
+	{TOK_WRITE, 0x7000485C, 0x0095},
+	{TOK_WRITE, 0x7000485E, 0xFEFD},
+	{TOK_WRITE, 0x70004860, 0x0206},
+	{TOK_WRITE, 0x70004862, 0xFF7F},
+	{TOK_WRITE, 0x70004864, 0x0191},
+	{TOK_WRITE, 0x70004866, 0xFF06},
+	{TOK_WRITE, 0x70004868, 0x01BA},
+	{TOK_WRITE, 0x7000486A, 0x0108},
+	{TOK_WRITE, 0x7000486C, 0x0204},
+	{TOK_WRITE, 0x7000486E, 0xFFB2},
+	{TOK_WRITE, 0x70004870, 0xFFF5},
+	{TOK_WRITE, 0x70004872, 0xFEF1},
+	{TOK_WRITE, 0x70004874, 0x014E},
+	{TOK_WRITE, 0x70004876, 0xFF18},
+	{TOK_WRITE, 0x70004878, 0xFFE6},
+	{TOK_WRITE, 0x7000487A, 0xFFDD},
+	{TOK_WRITE, 0x7000487C, 0x01B2},
+	{TOK_WRITE, 0x7000487E, 0x00F2},
+	{TOK_WRITE, 0x70004880, 0x00CA},
+	{TOK_WRITE, 0x70004882, 0xFF48},
+	{TOK_WRITE, 0x70004884, 0x0151},
+	{TOK_WRITE, 0x70004886, 0xFF50},
+	{TOK_WRITE, 0x70004888, 0x0147},
+	{TOK_WRITE, 0x7000488A, 0xFF75},
+	{TOK_WRITE, 0x7000488C, 0x0187},
+	{TOK_WRITE, 0x7000488E, 0x01BF},
+	{TOK_WRITE, 0x70004890, 0x0204},
+	{TOK_WRITE, 0x70004892, 0xFFB2},
+	{TOK_WRITE, 0x70004894, 0xFFF5},
+	{TOK_WRITE, 0x70004896, 0xFEF1},
+	{TOK_WRITE, 0x70004898, 0x014E},
+	{TOK_WRITE, 0x7000489A, 0xFF18},
+	{TOK_WRITE, 0x7000489C, 0xFFE6},
+	{TOK_WRITE, 0x7000489E, 0xFFDD},
+	{TOK_WRITE, 0x700048A0, 0x01B2},
+	{TOK_WRITE, 0x700048A2, 0x00F2},
+	{TOK_WRITE, 0x700048A4, 0x00CA},
+	{TOK_WRITE, 0x700048A6, 0xFF48},
+	{TOK_WRITE, 0x700048A8, 0x0151},
+	{TOK_WRITE, 0x700048AA, 0xFF50},
+	{TOK_WRITE, 0x700048AC, 0x0147},
+	{TOK_WRITE, 0x700048AE, 0xFF75},
+	{TOK_WRITE, 0x700048B0, 0x0187},
+	{TOK_WRITE, 0x700048B2, 0x01BF},
+	{TOK_WRITE, 0x700048B4, 0x0204},
+	{TOK_WRITE, 0x700048B6, 0xFFB2},
+	{TOK_WRITE, 0x700048B8, 0xFFF5},
+	{TOK_WRITE, 0x700048BA, 0xFEF1},
+	{TOK_WRITE, 0x700048BC, 0x014E},
+	{TOK_WRITE, 0x700048BE, 0xFF18},
+	{TOK_WRITE, 0x700048C0, 0xFFE6},
+	{TOK_WRITE, 0x700048C2, 0xFFDD},
+	{TOK_WRITE, 0x700048C4, 0x01B2},
+	{TOK_WRITE, 0x700048C6, 0x00F2},
+	{TOK_WRITE, 0x700048C8, 0x00CA},
+	{TOK_WRITE, 0x700048CA, 0xFF48},
+	{TOK_WRITE, 0x700048CC, 0x0151},
+	{TOK_WRITE, 0x700048CE, 0xFF50},
+	{TOK_WRITE, 0x700048D0, 0x0147},
+	{TOK_WRITE, 0x700048D2, 0xFF75},
+	{TOK_WRITE, 0x700048D4, 0x0187},
+	{TOK_WRITE, 0x700048D6, 0x01BF},
+	{TOK_WRITE, 0x700048D8, 0x01E5},
+	{TOK_WRITE, 0x700048DA, 0xFFA4},
+	{TOK_WRITE, 0x700048DC, 0xFFDC},
+	{TOK_WRITE, 0x700048DE, 0xFE90},
+	{TOK_WRITE, 0x700048E0, 0x013F},
+	{TOK_WRITE, 0x700048E2, 0xFF1B},
+	{TOK_WRITE, 0x700048E4, 0xFFD2},
+	{TOK_WRITE, 0x700048E6, 0xFFDF},
+	{TOK_WRITE, 0x700048E8, 0x0236},
+	{TOK_WRITE, 0x700048EA, 0x00EC},
+	{TOK_WRITE, 0x700048EC, 0x00F8},
+	{TOK_WRITE, 0x700048EE, 0xFF34},
+	{TOK_WRITE, 0x700048F0, 0x01CE},
+	{TOK_WRITE, 0x700048F2, 0xFF83},
+	{TOK_WRITE, 0x700048F4, 0x0195},
+	{TOK_WRITE, 0x700048F6, 0xFEF3},
+	{TOK_WRITE, 0x700048F8, 0x0126},
+	{TOK_WRITE, 0x700048FA, 0x0162},
+	{TOK_WRITE, 0x70000944, 0x0050},
+	{TOK_WRITE, 0x70000946, 0x00B0},
+	{TOK_WRITE, 0x70000948, 0x0196},
+	{TOK_WRITE, 0x7000094A, 0x0245},
+	{TOK_WRITE, 0x7000094C, 0x0300},
+	{TOK_WRITE, 0x7000097A, 0x0000},
+	{TOK_WRITE, 0x7000097C, 0x01CC},
+	{TOK_WRITE, 0x7000097E, 0x01CC},
+	{TOK_WRITE, 0x70000980, 0x01CC},
+	{TOK_WRITE, 0x70000982, 0x01CC},
+	{TOK_WRITE, 0x70000984, 0x01CC},
+	{TOK_WRITE, 0x70000986, 0x0180},
+	{TOK_WRITE, 0x70000988, 0x0196},
+	{TOK_WRITE, 0x70000976, 0x0070},
+	{TOK_WRITE, 0x70000978, 0x0005},
+	{TOK_WRITE, 0x70000938, 0x0000},
+	{TOK_WRITE, 0x7000093A, 0x0014},
+	{TOK_WRITE, 0x7000093C, 0x00D2},
+	{TOK_WRITE, 0x7000093E, 0x0384},
+	{TOK_WRITE, 0x70000940, 0x07D0},
+	{TOK_WRITE, 0x70000942, 0x1388},
+	{TOK_WRITE, 0x7000098C, 0x0000},
+	{TOK_WRITE, 0x7000098E, 0x0000},
+	{TOK_WRITE, 0x70000990, 0x0000},
+	{TOK_WRITE, 0x70000992, 0x0000},
+	{TOK_WRITE, 0x70000994, 0x0000},
+	{TOK_WRITE, 0x70000996, 0x00C0},
+	{TOK_WRITE, 0x70000998, 0x0064},
+	{TOK_WRITE, 0x7000099A, 0x0384},
+	{TOK_WRITE, 0x7000099C, 0x005F},
+	{TOK_WRITE, 0x7000099E, 0x01F4},
+	{TOK_WRITE, 0x700009A0, 0x0070},
+	{TOK_WRITE, 0x700009A2, 0x0040},
+	{TOK_WRITE, 0x700009A4, 0x00A0},
+	{TOK_WRITE, 0x700009A6, 0x0100},
+	{TOK_WRITE, 0x700009A8, 0x0010},
+	{TOK_WRITE, 0x700009AA, 0x0040},
+	{TOK_WRITE, 0x700009AC, 0x00A0},
+	{TOK_WRITE, 0x700009AE, 0x1430},
+	{TOK_WRITE, 0x700009B0, 0x0201},
+	{TOK_WRITE, 0x700009B2, 0x0204},
+	{TOK_WRITE, 0x700009B4, 0x3604},
+	{TOK_WRITE, 0x700009B6, 0x032A},
+	{TOK_WRITE, 0x700009B8, 0x0403},
+	{TOK_WRITE, 0x700009BA, 0x1B06},
+	{TOK_WRITE, 0x700009BC, 0x6015},
+	{TOK_WRITE, 0x700009BE, 0x00C0},
+	{TOK_WRITE, 0x700009C0, 0x6080},
+	{TOK_WRITE, 0x700009C2, 0x4080},
+	{TOK_WRITE, 0x700009C4, 0x0640},
+	{TOK_WRITE, 0x700009C6, 0x0306},
+	{TOK_WRITE, 0x700009C8, 0x2003},
+	{TOK_WRITE, 0x700009CA, 0xFF01},
+	{TOK_WRITE, 0x700009CC, 0x0000},
+	{TOK_WRITE, 0x700009CE, 0x0400},
+	{TOK_WRITE, 0x700009D0, 0x365A},
+	{TOK_WRITE, 0x700009D2, 0x102A},
+	{TOK_WRITE, 0x700009D4, 0x000B},
+	{TOK_WRITE, 0x700009D6, 0x0600},
+	{TOK_WRITE, 0x700009D8, 0x5A0F},
+	{TOK_WRITE, 0x700009DA, 0x0505},
+	{TOK_WRITE, 0x700009DC, 0x1802},
+	{TOK_WRITE, 0x700009DE, 0x0000},
+	{TOK_WRITE, 0x700009E0, 0x2006},
+	{TOK_WRITE, 0x700009E2, 0x3028},
+	{TOK_WRITE, 0x700009E4, 0x0418},
+	{TOK_WRITE, 0x700009E6, 0x0101},
+	{TOK_WRITE, 0x700009E8, 0x0800},
+	{TOK_WRITE, 0x700009EA, 0x1804},
+	{TOK_WRITE, 0x700009EC, 0x4008},
+	{TOK_WRITE, 0x700009EE, 0x0540},
+	{TOK_WRITE, 0x700009F0, 0x8006},
+	{TOK_WRITE, 0x700009F2, 0x0020},
+	{TOK_WRITE, 0x700009F4, 0x0000},
+	{TOK_WRITE, 0x700009F6, 0x1800},
+	{TOK_WRITE, 0x700009F8, 0x0000},
+	{TOK_WRITE, 0x700009FA, 0x1E10},
+	{TOK_WRITE, 0x700009FC, 0x000B},
+	{TOK_WRITE, 0x700009FE, 0x0607},
+	{TOK_WRITE, 0x70000A00, 0x0005},
+	{TOK_WRITE, 0x70000A02, 0x0607},
+	{TOK_WRITE, 0x70000A04, 0x0405},
+	{TOK_WRITE, 0x70000A06, 0x0205},
+	{TOK_WRITE, 0x70000A08, 0x0304},
+	{TOK_WRITE, 0x70000A0A, 0x0409},
+	{TOK_WRITE, 0x70000A0C, 0x0306},
+	{TOK_WRITE, 0x70000A0E, 0x0407},
+	{TOK_WRITE, 0x70000A10, 0x1C04},
+	{TOK_WRITE, 0x70000A12, 0x0214},
+	{TOK_WRITE, 0x70000A14, 0x1002},
+	{TOK_WRITE, 0x70000A16, 0x0610},
+	{TOK_WRITE, 0x70000A18, 0x1A02},
+	{TOK_WRITE, 0x70000A1A, 0x4A18},
+	{TOK_WRITE, 0x70000A1C, 0x0080},
+	{TOK_WRITE, 0x70000A1E, 0x0348},
+	{TOK_WRITE, 0x70000A20, 0x0180},
+	{TOK_WRITE, 0x70000A22, 0x0A0A},
+	{TOK_WRITE, 0x70000A24, 0x0101},
+	{TOK_WRITE, 0x70000A26, 0x2A36},
+	{TOK_WRITE, 0x70000A28, 0x6024},
+	{TOK_WRITE, 0x70000A2A, 0x2A36},
+	{TOK_WRITE, 0x70000A2C, 0xFFFF},
+	{TOK_WRITE, 0x70000A2E, 0x0808},
+	{TOK_WRITE, 0x70000A30, 0x0A01},
+	{TOK_WRITE, 0x70000A32, 0x010A},
+	{TOK_WRITE, 0x70000A34, 0x3601},
+	{TOK_WRITE, 0x70000A36, 0x242A},
+	{TOK_WRITE, 0x70000A38, 0x3660},
+	{TOK_WRITE, 0x70000A3A, 0xFF2A},
+	{TOK_WRITE, 0x70000A3C, 0x08FF},
+	{TOK_WRITE, 0x70000A3E, 0x0008},
+	{TOK_WRITE, 0x70000A40, 0x0001},
+	{TOK_WRITE, 0x70000A42, 0x0000},
+	{TOK_WRITE, 0x70000A44, 0x0000},
+	{TOK_WRITE, 0x70000A46, 0x0010},
+	{TOK_WRITE, 0x70000A48, 0x0000},
+	{TOK_WRITE, 0x70000A4A, 0x0000},
+	{TOK_WRITE, 0x70000A4C, 0x00C0},
+	{TOK_WRITE, 0x70000A4E, 0x0064},
+	{TOK_WRITE, 0x70000A50, 0x0384},
+	{TOK_WRITE, 0x70000A52, 0x0051},
+	{TOK_WRITE, 0x70000A54, 0x01F4},
+	{TOK_WRITE, 0x70000A56, 0x0070},
+	{TOK_WRITE, 0x70000A58, 0x0040},
+	{TOK_WRITE, 0x70000A5A, 0x00A0},
+	{TOK_WRITE, 0x70000A5C, 0x0100},
+	{TOK_WRITE, 0x70000A5E, 0x0010},
+	{TOK_WRITE, 0x70000A60, 0x0060},
+	{TOK_WRITE, 0x70000A62, 0x0100},
+	{TOK_WRITE, 0x70000A64, 0x1430},
+	{TOK_WRITE, 0x70000A66, 0x0201},
+	{TOK_WRITE, 0x70000A68, 0x0204},
+	{TOK_WRITE, 0x70000A6A, 0x2404},
+	{TOK_WRITE, 0x70000A6C, 0x031B},
+	{TOK_WRITE, 0x70000A6E, 0x0103},
+	{TOK_WRITE, 0x70000A70, 0x1205},
+	{TOK_WRITE, 0x70000A72, 0x400D},
+	{TOK_WRITE, 0x70000A74, 0x0080},
+	{TOK_WRITE, 0x70000A76, 0x2080},
+	{TOK_WRITE, 0x70000A78, 0x3040},
+	{TOK_WRITE, 0x70000A7A, 0x0630},
+	{TOK_WRITE, 0x70000A7C, 0x0306},
+	{TOK_WRITE, 0x70000A7E, 0x2003},
+	{TOK_WRITE, 0x70000A80, 0xFF01},
+	{TOK_WRITE, 0x70000A82, 0x0404},
+	{TOK_WRITE, 0x70000A84, 0x0300},
+	{TOK_WRITE, 0x70000A86, 0x245A},
+	{TOK_WRITE, 0x70000A88, 0x1018},
+	{TOK_WRITE, 0x70000A8A, 0x000B},
+	{TOK_WRITE, 0x70000A8C, 0x0B00},
+	{TOK_WRITE, 0x70000A8E, 0x5A0F},
+	{TOK_WRITE, 0x70000A90, 0x0505},
+	{TOK_WRITE, 0x70000A92, 0x1802},
+	{TOK_WRITE, 0x70000A94, 0x0000},
+	{TOK_WRITE, 0x70000A96, 0x2006},
+	{TOK_WRITE, 0x70000A98, 0x3428},
+	{TOK_WRITE, 0x70000A9A, 0x041C},
+	{TOK_WRITE, 0x70000A9C, 0x0101},
+	{TOK_WRITE, 0x70000A9E, 0x0800},
+	{TOK_WRITE, 0x70000AA0, 0x1004},
+	{TOK_WRITE, 0x70000AA2, 0x4008},
+	{TOK_WRITE, 0x70000AA4, 0x0540},
+	{TOK_WRITE, 0x70000AA6, 0x8006},
+	{TOK_WRITE, 0x70000AA8, 0x0020},
+	{TOK_WRITE, 0x70000AAA, 0x0000},
+	{TOK_WRITE, 0x70000AAC, 0x1800},
+	{TOK_WRITE, 0x70000AAE, 0x0000},
+	{TOK_WRITE, 0x70000AB0, 0x1E10},
+	{TOK_WRITE, 0x70000AB2, 0x000B},
+	{TOK_WRITE, 0x70000AB4, 0x0607},
+	{TOK_WRITE, 0x70000AB6, 0x0005},
+	{TOK_WRITE, 0x70000AB8, 0x0607},
+	{TOK_WRITE, 0x70000ABA, 0x0405},
+	{TOK_WRITE, 0x70000ABC, 0x0205},
+	{TOK_WRITE, 0x70000ABE, 0x0304},
+	{TOK_WRITE, 0x70000AC0, 0x0409},
+	{TOK_WRITE, 0x70000AC2, 0x0306},
+	{TOK_WRITE, 0x70000AC4, 0x0407},
+	{TOK_WRITE, 0x70000AC6, 0x1F04},
+	{TOK_WRITE, 0x70000AC8, 0x0218},
+	{TOK_WRITE, 0x70000ACA, 0x1102},
+	{TOK_WRITE, 0x70000ACC, 0x0611},
+	{TOK_WRITE, 0x70000ACE, 0x1A02},
+	{TOK_WRITE, 0x70000AD0, 0x8018},
+	{TOK_WRITE, 0x70000AD2, 0x0080},
+	{TOK_WRITE, 0x70000AD4, 0x0380},
+	{TOK_WRITE, 0x70000AD6, 0x0180},
+	{TOK_WRITE, 0x70000AD8, 0x0A0A},
+	{TOK_WRITE, 0x70000ADA, 0x0101},
+	{TOK_WRITE, 0x70000ADC, 0x1B24},
+	{TOK_WRITE, 0x70000ADE, 0x6024},
+	{TOK_WRITE, 0x70000AE0, 0x1D22},
+	{TOK_WRITE, 0x70000AE2, 0xFFFF},
+	{TOK_WRITE, 0x70000AE4, 0x0808},
+	{TOK_WRITE, 0x70000AE6, 0x0A01},
+	{TOK_WRITE, 0x70000AE8, 0x010A},
+	{TOK_WRITE, 0x70000AEA, 0x2401},
+	{TOK_WRITE, 0x70000AEC, 0x241B},
+	{TOK_WRITE, 0x70000AEE, 0x1E60},
+	{TOK_WRITE, 0x70000AF0, 0xFF18},
+	{TOK_WRITE, 0x70000AF2, 0x08FF},
+	{TOK_WRITE, 0x70000AF4, 0x0008},
+	{TOK_WRITE, 0x70000AF6, 0x0001},
+	{TOK_WRITE, 0x70000AF8, 0x0000},
+	{TOK_WRITE, 0x70000AFA, 0x0000},
+	{TOK_WRITE, 0x70000AFC, 0x0010},
+	{TOK_WRITE, 0x70000AFE, 0x0000},
+	{TOK_WRITE, 0x70000B00, 0x0000},
+	{TOK_WRITE, 0x70000B02, 0x00C0},
+	{TOK_WRITE, 0x70000B04, 0x0064},
+	{TOK_WRITE, 0x70000B06, 0x0384},
+	{TOK_WRITE, 0x70000B08, 0x0043},
+	{TOK_WRITE, 0x70000B0A, 0x01F4},
+	{TOK_WRITE, 0x70000B0C, 0x0070},
+	{TOK_WRITE, 0x70000B0E, 0x0040},
+	{TOK_WRITE, 0x70000B10, 0x00A0},
+	{TOK_WRITE, 0x70000B12, 0x0100},
+	{TOK_WRITE, 0x70000B14, 0x0010},
+	{TOK_WRITE, 0x70000B16, 0x0060},
+	{TOK_WRITE, 0x70000B18, 0x0100},
+	{TOK_WRITE, 0x70000B1A, 0x1430},
+	{TOK_WRITE, 0x70000B1C, 0x0201},
+	{TOK_WRITE, 0x70000B1E, 0x0204},
+	{TOK_WRITE, 0x70000B20, 0x1B04},
+	{TOK_WRITE, 0x70000B22, 0x0312},
+	{TOK_WRITE, 0x70000B24, 0x0003},
+	{TOK_WRITE, 0x70000B26, 0x0C03},
+	{TOK_WRITE, 0x70000B28, 0x2806},
+	{TOK_WRITE, 0x70000B2A, 0x0060},
+	{TOK_WRITE, 0x70000B2C, 0x1580},
+	{TOK_WRITE, 0x70000B2E, 0x2020},
+	{TOK_WRITE, 0x70000B30, 0x0620},
+	{TOK_WRITE, 0x70000B32, 0x0306},
+	{TOK_WRITE, 0x70000B34, 0x2003},
+	{TOK_WRITE, 0x70000B36, 0xFF01},
+	{TOK_WRITE, 0x70000B38, 0x0404},
+	{TOK_WRITE, 0x70000B3A, 0x0300},
+	{TOK_WRITE, 0x70000B3C, 0x145A},
+	{TOK_WRITE, 0x70000B3E, 0x1010},
+	{TOK_WRITE, 0x70000B40, 0x000B},
+	{TOK_WRITE, 0x70000B42, 0x0E00},
+	{TOK_WRITE, 0x70000B44, 0x5A0F},
+	{TOK_WRITE, 0x70000B46, 0x0504},
+	{TOK_WRITE, 0x70000B48, 0x1802},
+	{TOK_WRITE, 0x70000B4A, 0x0000},
+	{TOK_WRITE, 0x70000B4C, 0x2006},
+	{TOK_WRITE, 0x70000B4E, 0x3828},
+	{TOK_WRITE, 0x70000B50, 0x0428},
+	{TOK_WRITE, 0x70000B52, 0x0101},
+	{TOK_WRITE, 0x70000B54, 0x8000},
+	{TOK_WRITE, 0x70000B56, 0x0A04},
+	{TOK_WRITE, 0x70000B58, 0x4008},
+	{TOK_WRITE, 0x70000B5A, 0x0540},
+	{TOK_WRITE, 0x70000B5C, 0x8006},
+	{TOK_WRITE, 0x70000B5E, 0x0020},
+	{TOK_WRITE, 0x70000B60, 0x0000},
+	{TOK_WRITE, 0x70000B62, 0x1800},
+	{TOK_WRITE, 0x70000B64, 0x0000},
+	{TOK_WRITE, 0x70000B66, 0x1E10},
+	{TOK_WRITE, 0x70000B68, 0x000B},
+	{TOK_WRITE, 0x70000B6A, 0x0607},
+	{TOK_WRITE, 0x70000B6C, 0x0005},
+	{TOK_WRITE, 0x70000B6E, 0x0607},
+	{TOK_WRITE, 0x70000B70, 0x0405},
+	{TOK_WRITE, 0x70000B72, 0x0207},
+	{TOK_WRITE, 0x70000B74, 0x0304},
+	{TOK_WRITE, 0x70000B76, 0x0409},
+	{TOK_WRITE, 0x70000B78, 0x0306},
+	{TOK_WRITE, 0x70000B7A, 0x0407},
+	{TOK_WRITE, 0x70000B7C, 0x2404},
+	{TOK_WRITE, 0x70000B7E, 0x0221},
+	{TOK_WRITE, 0x70000B80, 0x1202},
+	{TOK_WRITE, 0x70000B82, 0x0613},
+	{TOK_WRITE, 0x70000B84, 0x1A02},
+	{TOK_WRITE, 0x70000B86, 0x8018},
+	{TOK_WRITE, 0x70000B88, 0x0080},
+	{TOK_WRITE, 0x70000B8A, 0x0080},
+	{TOK_WRITE, 0x70000B8C, 0x0180},
+	{TOK_WRITE, 0x70000B8E, 0x0A0A},
+	{TOK_WRITE, 0x70000B90, 0x0101},
+	{TOK_WRITE, 0x70000B92, 0x141D},
+	{TOK_WRITE, 0x70000B94, 0x6024},
+	{TOK_WRITE, 0x70000B96, 0x0C0C},
+	{TOK_WRITE, 0x70000B98, 0xFFFF},
+	{TOK_WRITE, 0x70000B9A, 0x0808},
+	{TOK_WRITE, 0x70000B9C, 0x0A01},
+	{TOK_WRITE, 0x70000B9E, 0x010A},
+	{TOK_WRITE, 0x70000BA0, 0x1B01},
+	{TOK_WRITE, 0x70000BA2, 0x2412},
+	{TOK_WRITE, 0x70000BA4, 0x0C60},
+	{TOK_WRITE, 0x70000BA6, 0xFF0C},
+	{TOK_WRITE, 0x70000BA8, 0x08FF},
+	{TOK_WRITE, 0x70000BAA, 0x0008},
+	{TOK_WRITE, 0x70000BAC, 0x0001},
+	{TOK_WRITE, 0x70000BAE, 0x0000},
+	{TOK_WRITE, 0x70000BB0, 0x0000},
+	{TOK_WRITE, 0x70000BB2, 0x000A},
+	{TOK_WRITE, 0x70000BB4, 0x0000},
+	{TOK_WRITE, 0x70000BB6, 0x0000},
+	{TOK_WRITE, 0x70000BB8, 0x00C0},
+	{TOK_WRITE, 0x70000BBA, 0x0064},
+	{TOK_WRITE, 0x70000BBC, 0x0384},
+	{TOK_WRITE, 0x70000BBE, 0x0032},
+	{TOK_WRITE, 0x70000BC0, 0x01F4},
+	{TOK_WRITE, 0x70000BC2, 0x0070},
+	{TOK_WRITE, 0x70000BC4, 0x0040},
+	{TOK_WRITE, 0x70000BC6, 0x00A0},
+	{TOK_WRITE, 0x70000BC8, 0x0100},
+	{TOK_WRITE, 0x70000BCA, 0x0010},
+	{TOK_WRITE, 0x70000BCC, 0x0060},
+	{TOK_WRITE, 0x70000BCE, 0x0100},
+	{TOK_WRITE, 0x70000BD0, 0x1430},
+	{TOK_WRITE, 0x70000BD2, 0x0201},
+	{TOK_WRITE, 0x70000BD4, 0x0204},
+	{TOK_WRITE, 0x70000BD6, 0x1504},
+	{TOK_WRITE, 0x70000BD8, 0x030F},
+	{TOK_WRITE, 0x70000BDA, 0x0003},
+	{TOK_WRITE, 0x70000BDC, 0x0902},
+	{TOK_WRITE, 0x70000BDE, 0x2004},
+	{TOK_WRITE, 0x70000BE0, 0x0050},
+	{TOK_WRITE, 0x70000BE2, 0x1140},
+	{TOK_WRITE, 0x70000BE4, 0x201C},
+	{TOK_WRITE, 0x70000BE6, 0x0620},
+	{TOK_WRITE, 0x70000BE8, 0x0306},
+	{TOK_WRITE, 0x70000BEA, 0x2003},
+	{TOK_WRITE, 0x70000BEC, 0xFF01},
+	{TOK_WRITE, 0x70000BEE, 0x0404},
+	{TOK_WRITE, 0x70000BF0, 0x0300},
+	{TOK_WRITE, 0x70000BF2, 0x145A},
+	{TOK_WRITE, 0x70000BF4, 0x1010},
+	{TOK_WRITE, 0x70000BF6, 0x000B},
+	{TOK_WRITE, 0x70000BF8, 0x1000},
+	{TOK_WRITE, 0x70000BFA, 0x5A0F},
+	{TOK_WRITE, 0x70000BFC, 0x0503},
+	{TOK_WRITE, 0x70000BFE, 0x1802},
+	{TOK_WRITE, 0x70000C00, 0x0000},
+	{TOK_WRITE, 0x70000C02, 0x2006},
+	{TOK_WRITE, 0x70000C04, 0x3C28},
+	{TOK_WRITE, 0x70000C06, 0x042C},
+	{TOK_WRITE, 0x70000C08, 0x0101},
+	{TOK_WRITE, 0x70000C0A, 0xFF00},
+	{TOK_WRITE, 0x70000C0C, 0x0904},
+	{TOK_WRITE, 0x70000C0E, 0x4008},
+	{TOK_WRITE, 0x70000C10, 0x0540},
+	{TOK_WRITE, 0x70000C12, 0x8006},
+	{TOK_WRITE, 0x70000C14, 0x0020},
+	{TOK_WRITE, 0x70000C16, 0x0000},
+	{TOK_WRITE, 0x70000C18, 0x1800},
+	{TOK_WRITE, 0x70000C1A, 0x0000},
+	{TOK_WRITE, 0x70000C1C, 0x1E10},
+	{TOK_WRITE, 0x70000C1E, 0x000B},
+	{TOK_WRITE, 0x70000C20, 0x0607},
+	{TOK_WRITE, 0x70000C22, 0x0005},
+	{TOK_WRITE, 0x70000C24, 0x0607},
+	{TOK_WRITE, 0x70000C26, 0x0405},
+	{TOK_WRITE, 0x70000C28, 0x0206},
+	{TOK_WRITE, 0x70000C2A, 0x0304},
+	{TOK_WRITE, 0x70000C2C, 0x0409},
+	{TOK_WRITE, 0x70000C2E, 0x0305},
+	{TOK_WRITE, 0x70000C30, 0x0406},
+	{TOK_WRITE, 0x70000C32, 0x2804},
+	{TOK_WRITE, 0x70000C34, 0x0228},
+	{TOK_WRITE, 0x70000C36, 0x1402},
+	{TOK_WRITE, 0x70000C38, 0x0618},
+	{TOK_WRITE, 0x70000C3A, 0x1A02},
+	{TOK_WRITE, 0x70000C3C, 0x8018},
+	{TOK_WRITE, 0x70000C3E, 0x0080},
+	{TOK_WRITE, 0x70000C40, 0x0080},
+	{TOK_WRITE, 0x70000C42, 0x0180},
+	{TOK_WRITE, 0x70000C44, 0x0A0A},
+	{TOK_WRITE, 0x70000C46, 0x0101},
+	{TOK_WRITE, 0x70000C48, 0x1117},
+	{TOK_WRITE, 0x70000C4A, 0x6024},
+	{TOK_WRITE, 0x70000C4C, 0x0A0A},
+	{TOK_WRITE, 0x70000C4E, 0xFFFF},
+	{TOK_WRITE, 0x70000C50, 0x0808},
+	{TOK_WRITE, 0x70000C52, 0x0A01},
+	{TOK_WRITE, 0x70000C54, 0x010A},
+	{TOK_WRITE, 0x70000C56, 0x1501},
+	{TOK_WRITE, 0x70000C58, 0x240F},
+	{TOK_WRITE, 0x70000C5A, 0x0A60},
+	{TOK_WRITE, 0x70000C5C, 0xFF0A},
+	{TOK_WRITE, 0x70000C5E, 0x08FF},
+	{TOK_WRITE, 0x70000C60, 0x0008},
+	{TOK_WRITE, 0x70000C62, 0x0001},
+	{TOK_WRITE, 0x70000C64, 0x0000},
+	{TOK_WRITE, 0x70000C66, 0x0000},
+	{TOK_WRITE, 0x70000C68, 0x0000},
+	{TOK_WRITE, 0x70000C6A, 0x0000},
+	{TOK_WRITE, 0x70000C6C, 0x0000},
+	{TOK_WRITE, 0x70000C6E, 0x00C0},
+	{TOK_WRITE, 0x70000C70, 0x0064},
+	{TOK_WRITE, 0x70000C72, 0x0384},
+	{TOK_WRITE, 0x70000C74, 0x0032},
+	{TOK_WRITE, 0x70000C76, 0x01F4},
+	{TOK_WRITE, 0x70000C78, 0x0070},
+	{TOK_WRITE, 0x70000C7A, 0x0040},
+	{TOK_WRITE, 0x70000C7C, 0x00A0},
+	{TOK_WRITE, 0x70000C7E, 0x0100},
+	{TOK_WRITE, 0x70000C80, 0x0010},
+	{TOK_WRITE, 0x70000C82, 0x0060},
+	{TOK_WRITE, 0x70000C84, 0x0100},
+	{TOK_WRITE, 0x70000C86, 0x1430},
+	{TOK_WRITE, 0x70000C88, 0x0201},
+	{TOK_WRITE, 0x70000C8A, 0x0204},
+	{TOK_WRITE, 0x70000C8C, 0x0F04},
+	{TOK_WRITE, 0x70000C8E, 0x030C},
+	{TOK_WRITE, 0x70000C90, 0x0003},
+	{TOK_WRITE, 0x70000C92, 0x0602},
+	{TOK_WRITE, 0x70000C94, 0x1803},
+	{TOK_WRITE, 0x70000C96, 0x0040},
+	{TOK_WRITE, 0x70000C98, 0x0E20},
+	{TOK_WRITE, 0x70000C9A, 0x2018},
+	{TOK_WRITE, 0x70000C9C, 0x0620},
+	{TOK_WRITE, 0x70000C9E, 0x0306},
+	{TOK_WRITE, 0x70000CA0, 0x2003},
+	{TOK_WRITE, 0x70000CA2, 0xFF01},
+	{TOK_WRITE, 0x70000CA4, 0x0404},
+	{TOK_WRITE, 0x70000CA6, 0x0200},
+	{TOK_WRITE, 0x70000CA8, 0x145A},
+	{TOK_WRITE, 0x70000CAA, 0x1010},
+	{TOK_WRITE, 0x70000CAC, 0x000B},
+	{TOK_WRITE, 0x70000CAE, 0x1200},
+	{TOK_WRITE, 0x70000CB0, 0x5A0F},
+	{TOK_WRITE, 0x70000CB2, 0x0502},
+	{TOK_WRITE, 0x70000CB4, 0x1802},
+	{TOK_WRITE, 0x70000CB6, 0x0000},
+	{TOK_WRITE, 0x70000CB8, 0x2006},
+	{TOK_WRITE, 0x70000CBA, 0x4028},
+	{TOK_WRITE, 0x70000CBC, 0x0430},
+	{TOK_WRITE, 0x70000CBE, 0x0101},
+	{TOK_WRITE, 0x70000CC0, 0xFF00},
+	{TOK_WRITE, 0x70000CC2, 0x0804},
+	{TOK_WRITE, 0x70000CC4, 0x4008},
+	{TOK_WRITE, 0x70000CC6, 0x0540},
+	{TOK_WRITE, 0x70000CC8, 0x8006},
+	{TOK_WRITE, 0x70000CCA, 0x0020},
+	{TOK_WRITE, 0x70000CCC, 0x0000},
+	{TOK_WRITE, 0x70000CCE, 0x1800},
+	{TOK_WRITE, 0x70000CD0, 0x0000},
+	{TOK_WRITE, 0x70000CD2, 0x1E10},
+	{TOK_WRITE, 0x70000CD4, 0x000B},
+	{TOK_WRITE, 0x70000CD6, 0x0607},
+	{TOK_WRITE, 0x70000CD8, 0x0005},
+	{TOK_WRITE, 0x70000CDA, 0x0607},
+	{TOK_WRITE, 0x70000CDC, 0x0405},
+	{TOK_WRITE, 0x70000CDE, 0x0205},
+	{TOK_WRITE, 0x70000CE0, 0x0304},
+	{TOK_WRITE, 0x70000CE2, 0x0409},
+	{TOK_WRITE, 0x70000CE4, 0x0306},
+	{TOK_WRITE, 0x70000CE6, 0x0407},
+	{TOK_WRITE, 0x70000CE8, 0x2C04},
+	{TOK_WRITE, 0x70000CEA, 0x022C},
+	{TOK_WRITE, 0x70000CEC, 0x1402},
+	{TOK_WRITE, 0x70000CEE, 0x0618},
+	{TOK_WRITE, 0x70000CF0, 0x1A02},
+	{TOK_WRITE, 0x70000CF2, 0x8018},
+	{TOK_WRITE, 0x70000CF4, 0x0080},
+	{TOK_WRITE, 0x70000CF6, 0x0080},
+	{TOK_WRITE, 0x70000CF8, 0x0180},
+	{TOK_WRITE, 0x70000CFA, 0x0A0A},
+	{TOK_WRITE, 0x70000CFC, 0x0101},
+	{TOK_WRITE, 0x70000CFE, 0x0C0F},
+	{TOK_WRITE, 0x70000D00, 0x6024},
+	{TOK_WRITE, 0x70000D02, 0x0808},
+	{TOK_WRITE, 0x70000D04, 0xFFFF},
+	{TOK_WRITE, 0x70000D06, 0x0808},
+	{TOK_WRITE, 0x70000D08, 0x0A01},
+	{TOK_WRITE, 0x70000D0A, 0x010A},
+	{TOK_WRITE, 0x70000D0C, 0x0F01},
+	{TOK_WRITE, 0x70000D0E, 0x240C},
+	{TOK_WRITE, 0x70000D10, 0x0860},
+	{TOK_WRITE, 0x70000D12, 0xFF08},
+	{TOK_WRITE, 0x70000D14, 0x08FF},
+	{TOK_WRITE, 0x70000D16, 0x0008},
+	{TOK_WRITE, 0x70000D18, 0x0001},
+	{TOK_WRITE, 0x70000D1A, 0x23CE},
+	{TOK_WRITE, 0x70000D1C, 0xFDC8},
+	{TOK_WRITE, 0x70000D1E, 0x112E},
+	{TOK_WRITE, 0x70000D20, 0x93A5},
+	{TOK_WRITE, 0x70000D22, 0xFE67},
+	{TOK_WRITE, 0x70000D24, 0x0000},
+	{TOK_WRITE, 0x700001F8, 0x5DC0},
+	{TOK_WRITE, 0x70000212, 0x0002},
+	{TOK_WRITE, 0x70000214, 0x0000},
+	{TOK_WRITE, 0x70000216, 0x0000},
+	{TOK_WRITE, 0x7000021A, 0x3A98},
+	{TOK_WRITE, 0x7000021C, 0x4F1A},
+	{TOK_WRITE, 0x7000021E, 0x4F1A},
+	{TOK_WRITE, 0x70000220, 0x4F1A},
+	{TOK_WRITE, 0x70000222, 0x4F1A},
+	{TOK_WRITE, 0x70000224, 0x4F1A},
+	{TOK_WRITE, 0x7000022C, 0x0001},
+	{TOK_WRITE, 0x70000478, 0x005F},
+	{TOK_WRITE, 0x7000047A, 0x005F},
+	{TOK_WRITE, 0x7000047C, 0x0001},
+	{TOK_WRITE, 0x7000047E, 0x0280},
+	{TOK_WRITE, 0x70000480, 0x01E0},
+	{TOK_WRITE, 0x70000482, 0x0005},
+	{TOK_WRITE, 0x700017DC, 0x0054},
+	{TOK_WRITE, 0x70001AE4, 0x001C},
+	{TOK_WRITE, 0x70000284, 0x0001},
+	{TOK_WRITE, 0x7000028A, 0x0000},
+	{TOK_WRITE, 0x700002A6, 0x0288},
+	{TOK_WRITE, 0x700002A8, 0x01E8},
+	{TOK_WRITE, 0x700002AA, 0x0005},
+	{TOK_WRITE, 0x700002AC, 0x4F1A},
+	{TOK_WRITE, 0x700002AE, 0x4F1A},
+	{TOK_WRITE, 0x700002B0, 0x0100},
+	{TOK_WRITE, 0x700002B2, 0x0300},
+	{TOK_WRITE, 0x700002B4, 0x0042},
+	{TOK_WRITE, 0x700002B6, 0x0000},
+	{TOK_WRITE, 0x700002B8, 0x01E0},
+	{TOK_WRITE, 0x700002BA, 0x0000},
+	{TOK_WRITE, 0x700002BC, 0x0000},
+	{TOK_WRITE, 0x700002BE, 0x0000},
+	{TOK_WRITE, 0x700002C0, 0x0002},
+	{TOK_WRITE, 0x700002C2, 0x03E8},
+	{TOK_WRITE, 0x700002C4, 0x014A},
+	{TOK_WRITE, 0x700002D0, 0x0000},
+	{TOK_WRITE, 0x700002D2, 0x0000},
+	{TOK_WRITE, 0x700002D4, 0x0000},
+	{TOK_WRITE, 0x70000396, 0x0000},
+	{TOK_WRITE, 0x70000398, 0x0A00},
+	{TOK_WRITE, 0x7000039A, 0x0780},
+	{TOK_WRITE, 0x7000039C, 0x0005},
+	{TOK_WRITE, 0x7000039E, 0x4F1A},
+	{TOK_WRITE, 0x700003A0, 0x4F1A},
+	{TOK_WRITE, 0x700003A2, 0x0100},
+	{TOK_WRITE, 0x700003A4, 0x0300},
+	{TOK_WRITE, 0x700003A6, 0x0042},
+	{TOK_WRITE, 0x700003A8, 0x0070},
+	{TOK_WRITE, 0x700003AA, 0x0810},
+	{TOK_WRITE, 0x700003AC, 0x0900},
+	{TOK_WRITE, 0x700003AE, 0x0001},
+	{TOK_WRITE, 0x700003B0, 0x0000},
+	{TOK_WRITE, 0x700003B2, 0x0002},
+	{TOK_WRITE, 0x700003B4, 0x0535},
+	{TOK_WRITE, 0x700003B6, 0x029A},
+	{TOK_WRITE, 0x70000250, 0x0A00},
+	{TOK_WRITE, 0x70000252, 0x0780},
+	{TOK_WRITE, 0x70000254, 0x0010},
+	{TOK_WRITE, 0x70000256, 0x000C},
+	{TOK_WRITE, 0x70000258, 0x0A00},
+	{TOK_WRITE, 0x7000025A, 0x0780},
+	{TOK_WRITE, 0x7000025C, 0x0010},
+	{TOK_WRITE, 0x7000025E, 0x000C},
+	{TOK_WRITE, 0x70000494, 0x0A00},
+	{TOK_WRITE, 0x70000496, 0x0780},
+	{TOK_WRITE, 0x70000498, 0x0000},
+	{TOK_WRITE, 0x7000049A, 0x0000},
+	{TOK_WRITE, 0x7000049C, 0x0A00},
+	{TOK_WRITE, 0x7000049E, 0x0780},
+	{TOK_WRITE, 0x700004A0, 0x0000},
+	{TOK_WRITE, 0x700004A2, 0x0000},
+	{TOK_WRITE, 0x70000262, 0x0001},
+	{TOK_WRITE, 0x70000264, 0x0001},
+	{TOK_WRITE, 0x70001CC2, 0x0100},
+	{TOK_WRITE, 0x70001CC4, 0x0100},
+	{TOK_WRITE, 0x70001CC6, 0x0100},
+	{TOK_WRITE, 0x70001CC8, 0x0100},
+	{TOK_WRITE, 0x700001A8, 0x0A0A},
+	{TOK_WRITE, 0x7000147C, 0x0170},
+	{TOK_WRITE, 0x70001482, 0x01E0},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_WRITE, 0x70000270, 0x0001},
+	{TOK_WRITE, 0x7000023E, 0x0001},
+	{TOK_WRITE, 0x70000240, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+
+/* Configure 30 FPS */
+struct regval_list s5k4ecgx_fps_30[] = {
+	{TOK_WRITE, 0x700002B4, 0x0052},
+	{TOK_WRITE, 0x700002BE, 0x0000},
+	{TOK_WRITE, 0x700002C0, 0x0001},
+	{TOK_WRITE, 0x700002C2, 0x014D},
+	{TOK_WRITE, 0x700002C4, 0x014D},
+	{TOK_WRITE, 0x700002D0, 0x0000},
+	{TOK_WRITE, 0x700002D2, 0x0000},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+struct regval_list s5k4ecgx_effect_normal[] = {
+	{TOK_WRITE, 0x7000023C, 0x0000},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+struct regval_list s5k4ecgx_wb_auto[] = {
+	{TOK_WRITE, 0x700004E6, 0x077F},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+struct regval_list s5k4ecgx_iso_auto[] = {
+	{TOK_WRITE, 0x70000938, 0x0000},
+	{TOK_WRITE, 0x70000F2A, 0x0001},
+	{TOK_WRITE, 0x700004E6, 0x077F},
+	{TOK_WRITE, 0x700004D0, 0x0000},
+	{TOK_WRITE, 0x700004D2, 0x0000},
+	{TOK_WRITE, 0x700004D4, 0x0001},
+	{TOK_WRITE, 0x700006C2, 0x0200},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+struct regval_list s5k4ecgx_contrast_default[] = {
+	{TOK_WRITE, 0x70000232, 0x0000},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+struct regval_list s5k4ecgx_scene_default[] = {
+	{TOK_WRITE, 0x70001492, 0x0000},
+	{TOK_WRITE, 0x70001494, 0x0101},
+	{TOK_WRITE, 0x70001496, 0x0101},
+	{TOK_WRITE, 0x70001498, 0x0000},
+	{TOK_WRITE, 0x7000149A, 0x0101},
+	{TOK_WRITE, 0x7000149C, 0x0101},
+	{TOK_WRITE, 0x7000149E, 0x0101},
+	{TOK_WRITE, 0x700014A0, 0x0101},
+	{TOK_WRITE, 0x700014A2, 0x0201},
+	{TOK_WRITE, 0x700014A4, 0x0303},
+	{TOK_WRITE, 0x700014A6, 0x0303},
+	{TOK_WRITE, 0x700014A8, 0x0102},
+	{TOK_WRITE, 0x700014AA, 0x0201},
+	{TOK_WRITE, 0x700014AC, 0x0403},
+	{TOK_WRITE, 0x700014AE, 0x0304},
+	{TOK_WRITE, 0x700014B0, 0x0102},
+	{TOK_WRITE, 0x700014B2, 0x0201},
+	{TOK_WRITE, 0x700014B4, 0x0403},
+	{TOK_WRITE, 0x700014B6, 0x0304},
+	{TOK_WRITE, 0x700014B8, 0x0102},
+	{TOK_WRITE, 0x700014BA, 0x0201},
+	{TOK_WRITE, 0x700014BC, 0x0403},
+	{TOK_WRITE, 0x700014BE, 0x0304},
+	{TOK_WRITE, 0x700014C0, 0x0102},
+	{TOK_WRITE, 0x700014C2, 0x0201},
+	{TOK_WRITE, 0x700014C4, 0x0303},
+	{TOK_WRITE, 0x700014C6, 0x0303},
+	{TOK_WRITE, 0x700014C8, 0x0102},
+	{TOK_WRITE, 0x700014CA, 0x0201},
+	{TOK_WRITE, 0x700014CC, 0x0202},
+	{TOK_WRITE, 0x700014CE, 0x0202},
+	{TOK_WRITE, 0x700014D0, 0x0102},
+	{TOK_WRITE, 0x70000938, 0x0000},
+	{TOK_WRITE, 0x700006B8, 0x452C},
+	{TOK_WRITE, 0x700006BA, 0x000C},
+	{TOK_WRITE, 0x70000F2A, 0x0001},
+	{TOK_WRITE, 0x70000F30, 0x0001},
+	{TOK_WRITE, 0x700004E6, 0x077F},
+	{TOK_WRITE, 0x700004D0, 0x0000},
+	{TOK_WRITE, 0x700004D2, 0x0000},
+	{TOK_WRITE, 0x700004D4, 0x0001},
+	{TOK_WRITE, 0x700006C2, 0x0200},
+	{TOK_WRITE, 0x70002C66, 0x0001},
+	{TOK_WRITE, 0x70001484, 0x003C},
+	{TOK_WRITE, 0x7000148A, 0x000F},
+	{TOK_WRITE, 0x7000058C, 0x3520},
+	{TOK_WRITE, 0x7000058E, 0x0000},
+	{TOK_WRITE, 0x70000590, 0xC350},
+	{TOK_WRITE, 0x70000592, 0x0000},
+	{TOK_WRITE, 0x70000594, 0x3520},
+	{TOK_WRITE, 0x70000596, 0x0000},
+	{TOK_WRITE, 0x70000598, 0xC350},
+	{TOK_WRITE, 0x7000059A, 0x0000},
+	{TOK_WRITE, 0x7000059C, 0x0470},
+	{TOK_WRITE, 0x7000059E, 0x0C00},
+	{TOK_WRITE, 0x700005A0, 0x0100},
+	{TOK_WRITE, 0x700005A2, 0x1000},
+	{TOK_WRITE, 0x70000544, 0x0111},
+	{TOK_WRITE, 0x70000546, 0x00EF},
+	{TOK_WRITE, 0x70000608, 0x0001},
+	{TOK_WRITE, 0x7000060A, 0x0001},
+	{TOK_WRITE, 0x70000A28, 0x6024},
+	{TOK_WRITE, 0x70000ADE, 0x6024},
+	{TOK_WRITE, 0x70000B94, 0x6024},
+	{TOK_WRITE, 0x70000C4A, 0x6024},
+	{TOK_WRITE, 0x70000D00, 0x6024},
+	{TOK_WRITE, 0x70000234, 0x0000},
+	{TOK_WRITE, 0x70000638, 0x0001},
+	{TOK_WRITE, 0x7000063A, 0x0000},
+	{TOK_WRITE, 0x7000063C, 0x0A3C},
+	{TOK_WRITE, 0x7000063E, 0x0000},
+	{TOK_WRITE, 0x70000640, 0x0D05},
+	{TOK_WRITE, 0x70000642, 0x0000},
+	{TOK_WRITE, 0x70000644, 0x3408},
+	{TOK_WRITE, 0x70000646, 0x0000},
+	{TOK_WRITE, 0x70000648, 0x3408},
+	{TOK_WRITE, 0x7000064A, 0x0000},
+	{TOK_WRITE, 0x7000064C, 0x6810},
+	{TOK_WRITE, 0x7000064E, 0x0000},
+	{TOK_WRITE, 0x70000650, 0x8214},
+	{TOK_WRITE, 0x70000652, 0x0000},
+	{TOK_WRITE, 0x70000654, 0xC350},
+	{TOK_WRITE, 0x70000656, 0x0000},
+	{TOK_WRITE, 0x70000658, 0xC350},
+	{TOK_WRITE, 0x7000065A, 0x0000},
+	{TOK_WRITE, 0x7000065C, 0xC350},
+	{TOK_WRITE, 0x7000065E, 0x0000},
+	{TOK_WRITE, 0x700002C2, 0x029A},
+	/* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 */
+	{TOK_WRITE, 0x700002C4, 0x014A},
+	/* #REG_0TC_PCFG_usMinFrTimeMsecMult10 */
+	{TOK_WRITE, 0x700003B4, 0x0535},
+	{TOK_WRITE, 0x700003B6, 0x029A},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_WRITE, 0x70000270, 0x0001},
+	{TOK_WRITE, 0x7000023E, 0x0001},
+	{TOK_WRITE, 0x70000240, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Configure 720x480 preview size */
+struct regval_list s5k4ecgx_720_preview[] = {
+	{TOK_WRITE, 0x70000250, 0x0A00},
+	{TOK_WRITE, 0x70000252, 0x06A8},
+	{TOK_WRITE, 0x70000254, 0x0010},
+	{TOK_WRITE, 0x70000256, 0x0078},
+	{TOK_WRITE, 0x70000258, 0x0A00},
+	{TOK_WRITE, 0x7000025A, 0x06A8},
+	{TOK_WRITE, 0x7000025C, 0x0010},
+	{TOK_WRITE, 0x7000025E, 0x0078},
+	{TOK_WRITE, 0x70000494, 0x0A00},
+	{TOK_WRITE, 0x70000496, 0x06A8},
+	{TOK_WRITE, 0x70000498, 0x0000},
+	{TOK_WRITE, 0x7000049A, 0x0000},
+	{TOK_WRITE, 0x7000049C, 0x0A00},
+	{TOK_WRITE, 0x7000049E, 0x06A8},
+	{TOK_WRITE, 0x700004A0, 0x0000},
+	{TOK_WRITE, 0x700004A2, 0x0000},
+	{TOK_WRITE, 0x70000262, 0x0001},
+	/* #REG_TC_GP_bUseReqInputInPre */
+	{TOK_WRITE, 0x70000A1E, 0x0028},
+	{TOK_WRITE, 0x70000AD4, 0x003C},
+	{TOK_WRITE, 0x700002A6, 0x02D0},
+	{TOK_WRITE, 0x700002A8, 0x01E0},
+	{TOK_WRITE, 0x700002AA, 0x0005},
+	{TOK_WRITE, 0x700002B4, 0x0052},
+	{TOK_WRITE, 0x700002BE, 0x0000},
+	{TOK_WRITE, 0x700002C0, 0x0001},
+	{TOK_WRITE, 0x700002C2, 0x029A},
+	{TOK_WRITE, 0x700002C4, 0x014D},
+	{TOK_WRITE, 0x700002D0, 0x0000},
+	{TOK_WRITE, 0x700002D2, 0x0000},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Configure 640x480 preview size */
+struct regval_list s5k4ecgx_640_preview[] = {
+	{TOK_WRITE, 0x70000250, 0x0A00},
+	{TOK_WRITE, 0x70000252, 0x0780},
+	{TOK_WRITE, 0x70000254, 0x0010},
+	{TOK_WRITE, 0x70000256, 0x000C},
+	{TOK_WRITE, 0x70000258, 0x0A00},
+	{TOK_WRITE, 0x7000025A, 0x0780},
+	{TOK_WRITE, 0x7000025C, 0x0010},
+	{TOK_WRITE, 0x7000025E, 0x000C},
+	{TOK_WRITE, 0x70000494, 0x0A00},
+	{TOK_WRITE, 0x70000496, 0x0780},
+	{TOK_WRITE, 0x70000498, 0x0000},
+	{TOK_WRITE, 0x7000049A, 0x0000},
+	{TOK_WRITE, 0x7000049C, 0x0A00},
+	{TOK_WRITE, 0x7000049E, 0x0780},
+	{TOK_WRITE, 0x700004A0, 0x0000},
+	{TOK_WRITE, 0x700004A2, 0x0000},
+	{TOK_WRITE, 0x70000262, 0x0001},
+	{TOK_WRITE, 0x70000A1E, 0x0028},
+	{TOK_WRITE, 0x70000AD4, 0x003C},
+	{TOK_WRITE, 0x700002A6, 0x0280},
+	{TOK_WRITE, 0x700002A8, 0x01E0},
+	{TOK_WRITE, 0x700002AA, 0x0005},
+	{TOK_WRITE, 0x700002B4, 0x0052},
+	{TOK_WRITE, 0x700002BE, 0x0000},
+	{TOK_WRITE, 0x700002C0, 0x0001},
+	{TOK_WRITE, 0x700002C2, 0x029A},
+	{TOK_WRITE, 0x700002C4, 0x014A},
+	{TOK_WRITE, 0x700002D0, 0x0000},
+	{TOK_WRITE, 0x700002D2, 0x0000},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Configure 352x288 preview size */
+struct regval_list s5k4ecgx_352_preview[] = {
+	{TOK_WRITE, 0x70000250, 0x0928},
+	{TOK_WRITE, 0x70000252, 0x0780},
+	{TOK_WRITE, 0x70000254, 0x007C},
+	{TOK_WRITE, 0x70000256, 0x000C},
+	{TOK_WRITE, 0x70000258, 0x0928},
+	{TOK_WRITE, 0x7000025A, 0x0780},
+	{TOK_WRITE, 0x7000025C, 0x007C},
+	{TOK_WRITE, 0x7000025E, 0x000C},
+	{TOK_WRITE, 0x70000494, 0x0928},
+	{TOK_WRITE, 0x70000496, 0x0780},
+	{TOK_WRITE, 0x70000498, 0x0000},
+	{TOK_WRITE, 0x7000049A, 0x0000},
+	{TOK_WRITE, 0x7000049C, 0x0928},
+	{TOK_WRITE, 0x7000049E, 0x0780},
+	{TOK_WRITE, 0x700004A0, 0x0000},
+	{TOK_WRITE, 0x700004A2, 0x0000},
+	{TOK_WRITE, 0x70000262, 0x0001},
+	{TOK_WRITE, 0x70000A1E, 0x0028},
+	{TOK_WRITE, 0x70000AD4, 0x003C},
+	{TOK_WRITE, 0x700002A6, 0x0160},
+	{TOK_WRITE, 0x700002A8, 0x0120},
+	{TOK_WRITE, 0x700002AA, 0x0005},
+	{TOK_WRITE, 0x700002B4, 0x0052},
+	{TOK_WRITE, 0x700002BE, 0x0000},
+	{TOK_WRITE, 0x700002C0, 0x0001},
+	{TOK_WRITE, 0x700002C2, 0x029A},
+	{TOK_WRITE, 0x700002C4, 0x014D},
+	{TOK_WRITE, 0x700002D0, 0x0000},
+	{TOK_WRITE, 0x700002D2, 0x0000},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Configure 176x144 preview size */
+struct regval_list s5k4ecgx_176_preview[] = {
+	{TOK_WRITE, 0x70000250, 0x0928},
+	{TOK_WRITE, 0x70000252, 0x0780},
+	{TOK_WRITE, 0x70000254, 0x007C},
+	{TOK_WRITE, 0x70000256, 0x000C},
+	{TOK_WRITE, 0x70000258, 0x0928},
+	{TOK_WRITE, 0x7000025A, 0x0780},
+	{TOK_WRITE, 0x7000025C, 0x007C},
+	{TOK_WRITE, 0x7000025E, 0x000C},
+	{TOK_WRITE, 0x70000494, 0x0928},
+	{TOK_WRITE, 0x70000496, 0x0780},
+	{TOK_WRITE, 0x70000498, 0x0000},
+	{TOK_WRITE, 0x7000049A, 0x0000},
+	{TOK_WRITE, 0x7000049C, 0x0928},
+	{TOK_WRITE, 0x7000049E, 0x0780},
+	{TOK_WRITE, 0x700004A0, 0x0000},
+	{TOK_WRITE, 0x700004A2, 0x0000},
+	{TOK_WRITE, 0x70000262, 0x0001},
+	{TOK_WRITE, 0x70000A1E, 0x0028},
+	{TOK_WRITE, 0x70000AD4, 0x003C},
+	{TOK_WRITE, 0x700002A6, 0x00B0},
+	{TOK_WRITE, 0x700002A8, 0x0090},
+	{TOK_WRITE, 0x700002AA, 0x0005},
+	{TOK_WRITE, 0x700002B4, 0x0052},
+	{TOK_WRITE, 0x700002BE, 0x0000},
+	{TOK_WRITE, 0x700002C0, 0x0001},
+	{TOK_WRITE, 0x700002C2, 0x029A},
+	{TOK_WRITE, 0x700002C4, 0x014D},
+	{TOK_WRITE, 0x700002D0, 0x0000},
+	{TOK_WRITE, 0x700002D2, 0x0000},
+	{TOK_WRITE, 0x70000266, 0x0000},
+	{TOK_WRITE, 0x7000026A, 0x0001},
+	{TOK_WRITE, 0x7000024E, 0x0001},
+	{TOK_WRITE, 0x70000268, 0x0001},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Default value for brightness */
+struct regval_list s5k4ecgx_ev_default[] = {
+	{TOK_WRITE, 0x70000230, 0x0000},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Default value for saturation */
+struct regval_list s5k4ecgx_saturation_default[] = {
+	{TOK_WRITE, 0x70000234, 0x0000},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+/* Default value for sharpness */
+struct regval_list s5k4ecgx_sharpness_default[] = {
+	{TOK_WRITE, 0x70000A28, 0x6024},
+	{TOK_WRITE, 0x70000ADE, 0x6024},
+	{TOK_WRITE, 0x70000B94, 0x6024},
+	{TOK_WRITE, 0x70000C4A, 0x6024},
+	{TOK_WRITE, 0x70000D00, 0x6024},
+	{TOK_TERM, 0xFFFFFFFF, 0x0},
+};
+
+#endif	/* __DRIVERS_MEDIA_VIDEO_S5K4ECGX_H__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor
  2012-07-19 12:14 [PATCH v2 0/2] Add v4l2 subdev driver for S5K4ECGX sensor with embedded SoC ISP Sangwook Lee
  2012-07-19 12:14 ` [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor Sangwook Lee
@ 2012-07-19 12:14 ` Sangwook Lee
  2012-07-19 21:40   ` Sylwester Nawrocki
  1 sibling, 1 reply; 8+ messages in thread
From: Sangwook Lee @ 2012-07-19 12:14 UTC (permalink / raw)
  To: linux-media
  Cc: mchehab, laurent.pinchart, sakari.ailus, suapapa, quartz.jang,
	linaro-dev, patches, usman.ahmad, david.a.cohen, Sangwook Lee

This dirver implements preview mode of the S5K4ECGX sensor.
capture (snapshot) operation, face detection are missing now.

Following controls are supported:
contrast/saturation/birghtness/sharpness

Signed-off-by: Sangwook Lee <sangwook.lee@linaro.org>
---
 drivers/media/video/Kconfig    |    7 +
 drivers/media/video/Makefile   |    1 +
 drivers/media/video/s5k4ecgx.c |  881 ++++++++++++++++++++++++++++++++++++++++
 include/media/s5k4ecgx.h       |   29 ++
 4 files changed, 918 insertions(+)
 create mode 100644 drivers/media/video/s5k4ecgx.c
 create mode 100644 include/media/s5k4ecgx.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 99937c9..45d7f99 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -559,6 +559,13 @@ config VIDEO_S5K6AA
 	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
 	  camera sensor with an embedded SoC image signal processor.
 
+config VIDEO_S5K4ECGX
+        tristate "Samsung S5K4ECGX sensor support"
+        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+        ---help---
+          This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
+          camera sensor with an embedded SoC image signal processor.
+
 source "drivers/media/video/smiapp/Kconfig"
 
 comment "Flash devices"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index d209de0..605bf35 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_VIDEO_SR030PC30)	+= sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
 obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
 obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
+obj-$(CONFIG_VIDEO_S5K4ECGX)    += s5k4ecgx.o
 obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp/
 obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
 obj-$(CONFIG_VIDEO_AS3645A)	+= as3645a.o
diff --git a/drivers/media/video/s5k4ecgx.c b/drivers/media/video/s5k4ecgx.c
new file mode 100644
index 0000000..e277d71
--- /dev/null
+++ b/drivers/media/video/s5k4ecgx.c
@@ -0,0 +1,881 @@
+/*
+ * Driver for s5k4ecgx (5MP Camera) from SAMSUNG
+ * a quarter-inch optical format 1.4 micron 5 megapixel (Mp)
+ * CMOS image sensor, as reffering to s5k6aa.c
+ *
+ * Copyright (C) 2012, Linaro, Sangwook Lee <sangwook.lee@linaro.org>
+ * Copyright (C) 2012, Insignal Co,. Ltd,  Homin Lee <suapapa@insignal.co.kr>
+ * Copyright (C) 2011, SAMSUNG ELECTRONICS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5k4ecgx.h>
+
+#include "s5k4ecgx_regs.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define S5K4ECGX_DRIVER_NAME		"s5k4ecgx"
+
+/* Basic windows sizes */
+#define S5K4ECGX_OUT_WIDTH_DEF		640
+#define S5K4ECGX_OUT_HEIGHT_DEF		480
+#define S5K4ECGX_WIN_WIDTH_MAX		1024
+#define S5K4ECGX_WIN_HEIGHT_MAX		600
+#define S5K4ECGX_WIN_WIDTH_MIN		176
+#define S5K4ECGX_WIN_HEIGHT_MIN		144
+
+/* Firmware revision information */
+#define S5K4ECGX_REVISION_1_1		0x11
+#define S5K4ECGX_FW_VERSION		0x4EC0
+#define REG_FW_VERSION			0x700001A4
+#define REG_FW_REVISION			0x700001A6
+
+/* For now we use only one user configuration register set */
+#define S5K4ECGX_MAX_PRESETS		1
+
+/* Review this depending on system */
+#define S5K4ECGX_POLL_TIME		1 /* ms */
+
+/* General purpose parameters */
+#define REG_USER_BRIGHTNESS		0x7000022C /* Brigthness */
+#define REG_USER_CONTRAST		0x7000022E /* Contrast */
+#define REG_USER_SATURATION		0x70000230 /* Saturation */
+
+/* FIXME: No information availble about these register from the datasheet */
+#define REG_USER_SHARP1			0x70000A28
+#define REG_USER_SHARP2			0x70000ADE
+#define REG_USER_SHARP3			0x70000B94
+#define REG_USER_SHARP4			0x70000C4A
+#define REG_USER_SHARP5			0x70000D00
+
+#define LSB(X) (((X) & 0xFF))
+#define MSB(Y) (((Y) >> 8) & 0xFF)
+
+/*
+ * Preview size lists supported by sensor
+ */
+struct regval_list *pview_size[] = {
+	s5k4ecgx_176_preview,
+	s5k4ecgx_352_preview,
+	s5k4ecgx_640_preview,
+	s5k4ecgx_720_preview,
+};
+
+struct s5k4ecgx_framesize {
+	u32 idx; /* Should indicate index of pview_size */
+	u32 width;
+	u32 height;
+};
+
+/*
+ * TODO: currently only preview is supported and snapshopt(capture)
+ * is not implemented yet
+ */
+static struct s5k4ecgx_framesize p_sets[] = {
+	{0, 176, 144},
+	{1, 352, 288},
+	{2, 640, 480},
+	{3, 720, 480},
+};
+
+#define S5K4ECGX_NUM_PREV ARRAY_SIZE(p_sets)
+struct s5k4ecgx_pixfmt {
+	enum v4l2_mbus_pixelcode code;
+	u32 colorspace;
+};
+
+/* By defaut value, output from sensor will be YUV422 0-255 */
+static const struct s5k4ecgx_pixfmt s5k4ecgx_formats[] = {
+	{ V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+struct s5k4ecgx_preset {
+		/* output pixel format and resolution */
+		struct v4l2_mbus_framefmt mbus_fmt;
+		u8 clk_id;
+		u8 index;
+};
+
+struct s5k4ecgx {
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+	struct v4l2_ctrl_handler handler;
+
+	struct s5k4ecgx_platform_data *pdata;
+	struct s5k4ecgx_preset presets[S5K4ECGX_MAX_PRESETS];
+	struct s5k4ecgx_preset *preset;
+	struct s5k4ecgx_framesize *p_now;	/* Current frame size */
+	struct v4l2_fract timeperframe;
+
+       /* protects the struct members below */
+	struct mutex lock;
+	int streaming;
+
+	/* Token for I2C burst write */
+	enum token_type reg_type;
+	u16 reg_addr_high;
+	u16 reg_addr_low;
+
+	/* Platform specific field */
+	int (*set_power)(int);
+	int mdelay;
+};
+
+static inline struct s5k4ecgx *to_s5k4ecgx(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct s5k4ecgx, sd);
+}
+
+static int s5k4ecgx_write_i2c(struct i2c_client *client, u8 *data, u16 len)
+{
+	struct i2c_msg msg = {client->addr, 0, len, (u8 *)data};
+	int ret;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	mdelay(S5K4ECGX_POLL_TIME);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to write I2C err\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int s5k4ecgx_write32(struct i2c_client *client,
+				       u16 addr, u16 data)
+{
+	u8 buf[4];
+
+	buf[0] = MSB(addr); /* SWAP 16 bit */
+	buf[1] = LSB(addr);
+	buf[2] = MSB(data);
+	buf[3] = LSB(data);
+
+	return s5k4ecgx_write_i2c(client, buf, 4);
+}
+
+static int s5k4ecgx_read_setup(struct v4l2_subdev *sd, u32 addr)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	u16 high = addr >> 16, low =  addr & 0xFFFF;
+	int ret = 0;
+
+	if (priv->reg_type != TOK_READ) {
+		priv->reg_addr_high = 0;
+		priv->reg_type = TOK_READ;
+	}
+	if (priv->reg_addr_high != high) {
+		ret = s5k4ecgx_write32(client, 0x002C, high);
+		priv->reg_addr_high = high;
+	}
+	ret |= s5k4ecgx_write32(client, 0x002E, low);
+
+	return ret;
+}
+
+static int s5k4ecgx_read16(struct i2c_client *client, u16 *val)
+{
+	struct i2c_msg msg[2];
+	u16 subaddr = 0x0F12;
+	u8 buf[2];
+	int err;
+
+	subaddr = swab16(subaddr);
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 2;
+	msg[0].buf = (u8 *)&subaddr;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 2;
+	msg[1].buf = buf;
+
+	err = i2c_transfer(client->adapter, msg, 2);
+	if (unlikely(err != 2)) {
+		dev_err(&client->dev, "Failed to read register 0x%02x!\n",
+			subaddr);
+		return -EIO;
+	}
+
+	*val = ((buf[0] << 8) | buf[1]);
+
+	return 0;
+}
+
+/*
+ * Access address will be remapped inside sensor (ARM7 core)
+ */
+static int s5k4ecgx_write_setup(struct v4l2_subdev *sd, u16 high, u16 low)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	int ret = 0;
+
+	if (priv->reg_type != TOK_WRITE) {
+		priv->reg_addr_high = 0;
+		priv->reg_addr_low = 0;
+		priv->reg_type = TOK_WRITE;
+	}
+
+	/* FIXME: no information about 0x0028 in the datasheet */
+	if (priv->reg_addr_high != high) {
+		ret = s5k4ecgx_write32(client, 0x0028, high);
+		priv->reg_addr_high = high;
+		priv->reg_addr_low = 0;
+	}
+
+	/* FIXME: no information about 0x002A in the datasheet */
+	if (priv->reg_addr_low != low) {
+		ret |= s5k4ecgx_write32(client, 0x002A, low);
+		priv->reg_addr_low = low;
+	}
+
+	return ret;
+}
+
+static int s5k4ecgx_write_ctrl(struct v4l2_subdev *sd, u32 addr, u16 data)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret;
+
+	v4l2_dbg(1, debug, sd, "Ctrl register val 0x%4x\n", data);
+	s5k4ecgx_write_setup(sd, addr >> 16, addr & 0xffff);
+	ret = s5k4ecgx_write32(client, 0x0F12, data);
+
+	return ret;
+}
+
+static u8 *s5k4ecgx_prep_buffer(int *cnt, struct regval_list **pos)
+{
+	struct regval_list *p_cur = *pos;
+	int burst_len = 0, len;
+	u8 *p_buf;
+
+	while (p_cur->type != TOK_TERM) {
+		/*
+		 * Make sure two bytes data are used and address is continous
+		 * to write them in a block
+		 */
+		burst_len += 2;
+		if (TOK_WRITE != (p_cur + 1)->type)
+			break;
+		if ((p_cur->addr + 2) != (p_cur + 1)->addr)
+			break;
+		p_cur += 1;
+	}
+	p_buf = vmalloc(burst_len + 2);
+	if (!p_buf)
+		return NULL;
+
+	p_buf[0] = 0x0F; /* FIXME: no information in the datasheet */
+	p_buf[1] = 0x12;
+	p_cur = *pos;
+	len = 2;
+	burst_len += 2; /* Add two bytes */
+	while (1) {
+		p_buf[len] = MSB(p_cur->val);
+		p_buf[len + 1] = LSB(p_cur->val);
+		len += 2;
+		if (len < burst_len)
+			p_cur++;
+		else
+			break;
+	}
+	*pos = p_cur;
+	*cnt = burst_len ;
+
+	return p_buf;
+}
+
+static int s5k4ecgx_write_burst(struct v4l2_subdev *sd,
+					struct regval_list **pos)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct regval_list *p_cur = *pos;
+	int burst_len, ret = 0;
+	u8 *p_buf;
+
+	/* Select starting address of burst data */
+	s5k4ecgx_write_setup(sd, p_cur->addr >> 16, p_cur->addr & 0xffff);
+
+	/* Make buffer and then copy data into it */
+	p_buf = s5k4ecgx_prep_buffer(&burst_len, pos);
+	if (!p_buf)
+		return -ENOMEM;
+	ret = s5k4ecgx_write_i2c(client, p_buf, burst_len);
+	vfree(p_buf);
+	priv->reg_addr_low = 0;
+
+	return ret;
+}
+
+static int s5k4ecgx_write_array(struct v4l2_subdev *sd,
+					struct regval_list *vals)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int err = 0;
+
+	while (vals->type != TOK_TERM && !err) {
+		switch (vals->type) {
+		case TOK_WRITE:
+			/*
+			 * This function continues to check the
+			 * following addresses, then update the address of vals
+			 */
+			err = s5k4ecgx_write_burst(sd, &vals);
+			break;
+		case TOK_CMD:
+			err = s5k4ecgx_write32(client, vals->addr, vals->val);
+			break;
+		case TOK_DELAY:
+			msleep(vals->val);
+			break;
+		default:
+			v4l2_err(sd, "Failed to detect i2c type!\n");
+			err = -EINVAL;
+			break;
+		}
+		vals++;
+	}
+
+	if (unlikely(vals->type != TOK_TERM) || err)
+		v4l2_err(sd, "Failed to write array!\n");
+
+	return err;
+}
+
+static void s5k4ecgx_init_parameters(struct v4l2_subdev *sd)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	int err = 0;
+
+	priv->streaming = 0;
+	/* brigthness default */
+	err = s5k4ecgx_write_array(sd, s5k4ecgx_ev_default);
+	/* no image effect */
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_effect_normal);
+	/* white blance auto */
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_wb_auto);
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_contrast_default);
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_iso_auto);
+	/* default 30 FPS */
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_fps_30);
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_scene_default);
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_saturation_default);
+	err |= s5k4ecgx_write_array(sd, s5k4ecgx_sharpness_default);
+
+	if (err)
+		v4l2_err(sd, "Failed to write init params!\n");
+}
+
+static void s5k4ecgx_set_framesize(struct v4l2_subdev *sd,
+					struct v4l2_mbus_framefmt *in)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	struct s5k4ecgx_framesize *a = p_sets;
+	struct s5k4ecgx_framesize *z = p_sets + S5K4ECGX_NUM_PREV - 1;
+
+	/* If not match, assign the biggest size  */
+	while (a != z) {
+		if (a->width == in->width && a->height == in->height)
+			break;
+		a++;
+	}
+	priv->p_now = a;
+}
+
+static int s5k4ecgx_get_pixfmt_index(struct s5k4ecgx *priv,
+				   struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(s5k4ecgx_formats); i++)
+		if (mf->colorspace == s5k4ecgx_formats[i].colorspace &&
+		    mf->code == s5k4ecgx_formats[i].code)
+			return i;
+
+	return 0;
+}
+
+static void s5k4ecgx_try_fmt(struct s5k4ecgx *priv,
+			     struct v4l2_mbus_framefmt *mf)
+{
+	unsigned int index;
+
+	v4l_bound_align_image(&mf->width, S5K4ECGX_WIN_WIDTH_MIN,
+			S5K4ECGX_WIN_WIDTH_MAX, 1, &mf->height,
+			S5K4ECGX_WIN_HEIGHT_MIN, S5K4ECGX_WIN_HEIGHT_MAX, 1, 0);
+
+	if (mf->colorspace != V4L2_COLORSPACE_JPEG)
+		mf->colorspace = V4L2_COLORSPACE_JPEG;
+	index = s5k4ecgx_get_pixfmt_index(priv, mf);
+	mf->colorspace	= s5k4ecgx_formats[0].colorspace;
+	mf->code		= s5k4ecgx_formats[0].code;
+	mf->field		= V4L2_FIELD_NONE;
+}
+
+static int s5k4ecgx_read_fw_ver(struct v4l2_subdev *sd)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	u16 fw_ver = 0, hw_rev = 0;
+
+	s5k4ecgx_read_setup(sd, REG_FW_VERSION);
+	s5k4ecgx_read16(client, &fw_ver);
+	if (fw_ver != S5K4ECGX_FW_VERSION) {
+		v4l2_err(sd, "FW version check failed!");
+		return -ENODEV;
+	}
+	s5k4ecgx_read_setup(sd, REG_FW_REVISION);
+	s5k4ecgx_read16(client, &hw_rev);
+
+	if (hw_rev == S5K4ECGX_REVISION_1_1) {
+		v4l2_info(sd, "chip found FW ver: 0x%X, HW rev: 0x%X\n",
+						fw_ver, hw_rev);
+	} else {
+		v4l2_err(sd, "chip found but it has unknown revision 0x%x\n",
+							hw_rev);
+		return -ENODEV;
+	};
+
+	return 0;
+}
+
+static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(s5k4ecgx_formats))
+		return -EINVAL;
+	code->code = s5k4ecgx_formats[code->index].code;
+
+	return 0;
+}
+
+static int s5k4ecgx_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	int i = ARRAY_SIZE(s5k4ecgx_formats);
+
+	if (fse->index > 0)
+		return -EINVAL;
+
+	while (--i)
+		if (fse->code == s5k4ecgx_formats[i].code)
+			break;
+
+	fse->code = s5k4ecgx_formats[i].code;
+	fse->min_width	= S5K4ECGX_WIN_WIDTH_MIN;
+	fse->max_width	= S5K4ECGX_WIN_WIDTH_MAX;
+	fse->max_height = S5K4ECGX_WIN_HEIGHT_MIN;
+	fse->min_height = S5K4ECGX_WIN_HEIGHT_MAX;
+
+	return 0;
+}
+
+static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_format *fmt)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	memset(fmt->reserved, 0, sizeof(fmt->reserved));
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, 0);
+		fmt->format = *mf;
+		return 0;
+	}
+	mutex_lock(&priv->lock);
+	fmt->format.width = priv->p_now->width;
+	fmt->format.height = priv->p_now->height;
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+			    struct v4l2_subdev_format *fmt)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	struct s5k4ecgx_preset *preset = priv->preset;
+	struct v4l2_mbus_framefmt *mf;
+	struct v4l2_rect *crop;
+	int ret = 0;
+
+	mutex_lock(&priv->lock);
+	s5k4ecgx_try_fmt(priv, &fmt->format);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		crop = v4l2_subdev_get_try_crop(fh, 0);
+	} else {
+		if (priv->streaming)
+			ret = -EBUSY;
+		else
+			mf = &preset->mbus_fmt;
+	}
+	if (ret == 0) {
+		*mf = fmt->format;
+		s5k4ecgx_set_framesize(sd, &fmt->format);
+	}
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_pad_ops s5k4ecgx_pad_ops = {
+	.enum_mbus_code		= s5k4ecgx_enum_mbus_code,
+	.enum_frame_size	= s5k4ecgx_enum_frame_size,
+	.get_fmt	= s5k4ecgx_get_fmt,
+	.set_fmt	= s5k4ecgx_set_fmt,
+};
+
+/*
+ * V4L2 subdev controls
+ */
+static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+	struct v4l2_subdev *sd = &container_of(ctrl->handler, struct s5k4ecgx,
+						handler)->sd;
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	int err = 0;
+
+	v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
+	mutex_lock(&priv->lock);
+
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+		err = s5k4ecgx_write_ctrl(sd, REG_USER_CONTRAST, ctrl->val);
+		break;
+
+	case V4L2_CID_SATURATION:
+		err = s5k4ecgx_write_ctrl(sd, REG_USER_SATURATION, ctrl->val);
+		break;
+
+	case V4L2_CID_SHARPNESS:
+		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP1, ctrl->val);
+		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP2, ctrl->val);
+		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP3, ctrl->val);
+		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP4, ctrl->val);
+		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP5, ctrl->val);
+		break;
+
+	case V4L2_CID_BRIGHTNESS:
+		err = s5k4ecgx_write_ctrl(sd, REG_USER_BRIGHTNESS, ctrl->val);
+		break;
+	default:
+		v4l2_dbg(1, debug, sd, "unknown set ctrl id 0x%x\n", ctrl->id);
+		err = -ENOIOCTLCMD;
+		break;
+	}
+
+	/* Review this */
+	priv->reg_type = TOK_TERM;
+
+	mutex_unlock(&priv->lock);
+
+	if (err < 0)
+		v4l2_err(sd, "Failed to write videoc_s_ctrl err %d\n", err);
+
+	return err;
+}
+
+static const struct v4l2_ctrl_ops s5k4ecgx_ctrl_ops = {
+	.s_ctrl = s5k4ecgx_s_ctrl,
+};
+
+/*
+ * Reading s5k4ecgx version information
+ */
+static int s5k4ecgx_registered(struct v4l2_subdev *sd)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	int ret;
+
+	if (!priv->set_power) {
+		v4l2_err(sd, "Error: power callback undefined!\n");
+		return -EIO;
+	}
+
+	mutex_lock(&priv->lock);
+	priv->set_power(true);
+	/* Time to stablize sensor */
+	mdelay(priv->mdelay);
+	ret = s5k4ecgx_read_fw_ver(sd);
+	priv->set_power(false);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+/*
+ *  V4L2 subdev internal operations
+ */
+static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+
+	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
+
+	format->colorspace = s5k4ecgx_formats[0].colorspace;
+	format->code = s5k4ecgx_formats[0].code;
+	format->width = S5K4ECGX_OUT_WIDTH_DEF;
+	format->height = S5K4ECGX_OUT_HEIGHT_DEF;
+	format->field = V4L2_FIELD_NONE;
+
+	crop->width = S5K4ECGX_WIN_WIDTH_MAX;
+	crop->height = S5K4ECGX_WIN_HEIGHT_MAX;
+	crop->left = 0;
+	crop->top = 0;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops s5k4ecgx_subdev_internal_ops = {
+	.registered = s5k4ecgx_registered,
+	.open = s5k4ecgx_open,
+};
+
+static int s5k4ecgx_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+
+	if (!priv->set_power)
+		return -EIO;
+
+	v4l2_dbg(1, debug, sd, "Switching %s\n", on ? "on" : "off");
+
+	if (on) {
+		priv->set_power(on);
+		/* Time to stablize sensor */
+		mdelay(priv->mdelay);
+		/* Loading firmware into ARM7 core of sensor */
+		if (s5k4ecgx_write_array(sd, s5k4ecgx_init_regs) < 0) {
+			priv->set_power(0); /* Turn off power */
+			return -EIO;
+		}
+		s5k4ecgx_init_parameters(sd);
+	} else {
+		priv->set_power(0);
+	}
+
+	return 0;
+}
+
+static int s5k4ecgx_log_status(struct v4l2_subdev *sd)
+{
+	v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_core_ops s5k4ecgx_core_ops = {
+	.s_power = s5k4ecgx_s_power,
+	.log_status	= s5k4ecgx_log_status,
+};
+
+static int __s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	int err = 0;
+
+	if (on)
+		err = s5k4ecgx_write_array(sd, pview_size[priv->p_now->idx]);
+
+	return err;
+}
+
+static int s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+	int ret = 0;
+
+	v4l2_dbg(1, debug, sd, "Turn streaming %s\n", on ? "on" : "off");
+	mutex_lock(&priv->lock);
+
+	if (on) {
+		/* Ignore if s_stream is called twice */
+		if (!priv->streaming) {
+			ret = __s5k4ecgx_s_stream(sd, on);
+			if (!ret)
+				priv->streaming = on;
+		}
+	} else {
+		priv->streaming = 0;
+	}
+
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_video_ops s5k4ecgx_video_ops = {
+	.s_stream = s5k4ecgx_s_stream,
+};
+
+static const struct v4l2_subdev_ops s5k4ecgx_ops = {
+	.core = &s5k4ecgx_core_ops,
+	.pad = &s5k4ecgx_pad_ops,
+	.video = &s5k4ecgx_video_ops,
+};
+
+static int s5k4ecgx_initialize_ctrls(struct s5k4ecgx *priv)
+{
+	const struct v4l2_ctrl_ops *ops = &s5k4ecgx_ctrl_ops;
+	struct v4l2_ctrl_handler *hdl = &priv->handler;
+	int ret;
+
+	ret =  v4l2_ctrl_handler_init(hdl, 16);
+	if (ret)
+		return ret;
+
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -208, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
+
+	/* For sharpness, 0x6024 is default value */
+	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704, 24612, 8208,
+			  24612);
+	if (hdl->error) {
+		ret = hdl->error;
+		v4l2_ctrl_handler_free(hdl);
+		return ret;
+	}
+	priv->sd.ctrl_handler = hdl;
+
+	return 0;
+};
+
+/*
+ * Set initial values for all preview presets
+ */
+static void s5k4ecgx_presets_data_init(struct s5k4ecgx *priv)
+{
+	struct s5k4ecgx_preset *preset = &priv->presets[0];
+	int i;
+
+	for (i = 0; i < S5K4ECGX_MAX_PRESETS; i++) {
+		preset->mbus_fmt.width	= S5K4ECGX_OUT_WIDTH_DEF;
+		preset->mbus_fmt.height	= S5K4ECGX_OUT_HEIGHT_DEF;
+		preset->mbus_fmt.code	= s5k4ecgx_formats[0].code;
+		preset->index		= i;
+		preset->clk_id		= 0;
+		preset++;
+	}
+	priv->preset = &priv->presets[0];
+}
+
+/*
+  * Fetching platform data is being done with s_config subdev call.
+  * In probe routine, we just register subdev device
+  */
+static int s5k4ecgx_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct v4l2_subdev *sd;
+	struct s5k4ecgx *priv;
+	struct s5k4ecgx_platform_data *pdata = client->dev.platform_data;
+	int	ret;
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "platform data is missing!\n");
+		return -EINVAL;
+	}
+	priv = kzalloc(sizeof(struct s5k4ecgx), GFP_KERNEL);
+
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+
+	priv->set_power = pdata->set_power;
+	priv->mdelay = pdata->mdelay;
+
+	sd = &priv->sd;
+	/* Registering subdev */
+	v4l2_i2c_subdev_init(sd, client, &s5k4ecgx_ops);
+	strlcpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
+
+	sd->internal_ops = &s5k4ecgx_subdev_internal_ops;
+	/* Support v4l2 sub-device userspace API */
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+	ret = media_entity_init(&sd->entity, 1, &priv->pad, 0);
+	if (ret)
+		goto out_err;
+
+	ret = s5k4ecgx_initialize_ctrls(priv);
+	s5k4ecgx_presets_data_init(priv);
+
+	if (ret)
+		goto out_err;
+
+	return 0;
+
+ out_err:
+	media_entity_cleanup(&priv->sd.entity);
+	kfree(priv);
+
+	return ret;
+}
+
+static int s5k4ecgx_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
+
+	mutex_destroy(&priv->lock);
+	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&priv->handler);
+	media_entity_cleanup(&sd->entity);
+	kfree(priv);
+
+	return 0;
+}
+
+static const struct i2c_device_id s5k4ecgx_id[] = {
+	{ S5K4ECGX_DRIVER_NAME, 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id);
+
+static struct i2c_driver v4l2_i2c_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name = S5K4ECGX_DRIVER_NAME,
+	},
+	.probe = s5k4ecgx_probe,
+	.remove = s5k4ecgx_remove,
+	.id_table = s5k4ecgx_id,
+};
+
+module_i2c_driver(v4l2_i2c_driver);
+
+MODULE_DESCRIPTION("Samsung S5K4ECGX 5MP SOC camera");
+MODULE_AUTHOR("Sangwook Lee <sangwook.lee@linaro.org>");
+MODULE_AUTHOR("Seok-Young Jang <quartz.jang@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/media/s5k4ecgx.h b/include/media/s5k4ecgx.h
new file mode 100644
index 0000000..e041761
--- /dev/null
+++ b/include/media/s5k4ecgx.h
@@ -0,0 +1,29 @@
+/*
+ * S5K4ECGX Platform data header
+ *
+ * Copyright (C) 2012, Linaro
+ *
+ * Copyright (C) 2010, SAMSUNG ELECTRONICS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef S5K4ECGX_H
+#define S5K4ECGX_H
+
+/**
+ * struct ss5k4ecgx_platform_data- s5k4ecgx driver platform data
+ * @set_power: an callback to give the chance to turn off/on
+ *		 camera which is depending on the board code
+ * @mdelay   : delay (ms) needed after enabling power
+ */
+
+struct s5k4ecgx_platform_data {
+	int (*set_power)(int);
+	int mdelay;
+};
+
+#endif /* S5K4ECGX_H */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor
  2012-07-19 12:14 ` [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor Sangwook Lee
@ 2012-07-19 19:40   ` Sylwester Nawrocki
       [not found]     ` <CADPsn1bniYQQ-pefrX+XdbLk1n-Na_dSYWspORkGCwo5+XBtrw@mail.gmail.com>
  0 siblings, 1 reply; 8+ messages in thread
From: Sylwester Nawrocki @ 2012-07-19 19:40 UTC (permalink / raw)
  To: Sangwook Lee
  Cc: linux-media, mchehab, laurent.pinchart, sakari.ailus, suapapa,
	quartz.jang, linaro-dev, patches, usman.ahmad, david.a.cohen

Hi Sangwook,

On 07/19/2012 02:14 PM, Sangwook Lee wrote:
> Add factory default settings for S5K4ECGX sensor registers.
> I copied them from the reference code of Samsung S.LSI.

I'm pretty sure we can do better than that. I've started S5K6AAFX sensor 
driver development with similar set of write-only register address/value
arrays, that stored mainly register default values after the device reset,
or were configuring presets that were never used.

If you lok at the s5k6aa driver, you'll find only one relatively small
array of register values for the analog processing block settings.
It's true that I had to reverse engineer a couple of things, but I also
had a relatively good datasheet for the sensor.
 
> According to comments from the reference code, they do not
> recommend any changes of these settings.

Yes, but it doesn't mean cannot convert, at least part of, those ugly
tables into function calls.

Have you tried to contact Samsung S.LSI for a datasheet that would 
contain better registers' description ?

--

Thanks,
Sylwester

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor
  2012-07-19 12:14 ` [PATCH v2 2/2] v4l: Add v4l2 subdev driver for " Sangwook Lee
@ 2012-07-19 21:40   ` Sylwester Nawrocki
  2012-07-20 15:36     ` Sangwook Lee
  0 siblings, 1 reply; 8+ messages in thread
From: Sylwester Nawrocki @ 2012-07-19 21:40 UTC (permalink / raw)
  To: Sangwook Lee
  Cc: linux-media, mchehab, laurent.pinchart, sakari.ailus, suapapa,
	quartz.jang, linaro-dev, patches, usman.ahmad, david.a.cohen

Hi Sangwook,

A few review comments for you below...

On 07/19/2012 02:14 PM, Sangwook Lee wrote:
> This dirver implements preview mode of the S5K4ECGX sensor.

dirver -> driver

> capture (snapshot) operation, face detection are missing now.
> 
> Following controls are supported:
> contrast/saturation/birghtness/sharpness

birghtness -> brightness
 
> Signed-off-by: Sangwook Lee<sangwook.lee@linaro.org>
> ---
>   drivers/media/video/Kconfig    |    7 +
>   drivers/media/video/Makefile   |    1 +
>   drivers/media/video/s5k4ecgx.c |  881 ++++++++++++++++++++++++++++++++++++++++
>   include/media/s5k4ecgx.h       |   29 ++
>   4 files changed, 918 insertions(+)
>   create mode 100644 drivers/media/video/s5k4ecgx.c
>   create mode 100644 include/media/s5k4ecgx.h
> 
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 99937c9..45d7f99 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -559,6 +559,13 @@ config VIDEO_S5K6AA
>   	  This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
>   	  camera sensor with an embedded SoC image signal processor.
> 
> +config VIDEO_S5K4ECGX
> +        tristate "Samsung S5K4ECGX sensor support"
> +        depends on I2C&&  VIDEO_V4L2&&  VIDEO_V4L2_SUBDEV_API
> +        ---help---
> +          This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
> +          camera sensor with an embedded SoC image signal processor.
> +
>   source "drivers/media/video/smiapp/Kconfig"
> 
>   comment "Flash devices"
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index d209de0..605bf35 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -79,6 +79,7 @@ obj-$(CONFIG_VIDEO_SR030PC30)	+= sr030pc30.o
>   obj-$(CONFIG_VIDEO_NOON010PC30)	+= noon010pc30.o
>   obj-$(CONFIG_VIDEO_M5MOLS)	+= m5mols/
>   obj-$(CONFIG_VIDEO_S5K6AA)	+= s5k6aa.o
> +obj-$(CONFIG_VIDEO_S5K4ECGX)    += s5k4ecgx.o
>   obj-$(CONFIG_VIDEO_SMIAPP)	+= smiapp/
>   obj-$(CONFIG_VIDEO_ADP1653)	+= adp1653.o
>   obj-$(CONFIG_VIDEO_AS3645A)	+= as3645a.o
> diff --git a/drivers/media/video/s5k4ecgx.c b/drivers/media/video/s5k4ecgx.c
> new file mode 100644
> index 0000000..e277d71
> --- /dev/null
> +++ b/drivers/media/video/s5k4ecgx.c
> @@ -0,0 +1,881 @@
> +/*
> + * Driver for s5k4ecgx (5MP Camera) from SAMSUNG
> + * a quarter-inch optical format 1.4 micron 5 megapixel (Mp)
> + * CMOS image sensor, as reffering to s5k6aa.c

I think this should be mentioned after your own copyright notice,
e.g. in form of:

Based on s5k6aa driver,
Copyright (C) 2011, Samsung Electronics Co., Ltd.

> + *
> + * Copyright (C) 2012, Linaro, Sangwook Lee<sangwook.lee@linaro.org>
> + * Copyright (C) 2012, Insignal Co,. Ltd,  Homin Lee<suapapa@insignal.co.kr>
> + * Copyright (C) 2011, SAMSUNG ELECTRONICS

No need to shout, "Samsung Electronics Co., Ltd." would be just enough.

> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include<linux/module.h>
> +#include<linux/i2c.h>
> +#include<linux/delay.h>
> +#include<linux/vmalloc.h>
> +#include<linux/slab.h>
> +
> +#include<media/v4l2-device.h>
> +#include<media/v4l2-subdev.h>
> +#include<media/media-entity.h>
> +#include<media/v4l2-ctrls.h>
> +#include<media/v4l2-mediabus.h>
> +#include<media/s5k4ecgx.h>

Can we, please, have these sorted alphabetically ?

> +#include "s5k4ecgx_regs.h"
> +
> +static int debug;
> +module_param(debug, int, 0644);
> +
> +#define S5K4ECGX_DRIVER_NAME		"s5k4ecgx"
> +
> +/* Basic windows sizes */
> +#define S5K4ECGX_OUT_WIDTH_DEF		640
> +#define S5K4ECGX_OUT_HEIGHT_DEF		480
> +#define S5K4ECGX_WIN_WIDTH_MAX		1024
> +#define S5K4ECGX_WIN_HEIGHT_MAX		600
> +#define S5K4ECGX_WIN_WIDTH_MIN		176
> +#define S5K4ECGX_WIN_HEIGHT_MIN		144
> +
> +/* Firmware revision information */
> +#define S5K4ECGX_REVISION_1_1		0x11
> +#define S5K4ECGX_FW_VERSION		0x4EC0
> +#define REG_FW_VERSION			0x700001A4
> +#define REG_FW_REVISION			0x700001A6
> +
> +/* For now we use only one user configuration register set */
> +#define S5K4ECGX_MAX_PRESETS		1
> +
> +/* Review this depending on system */
> +#define S5K4ECGX_POLL_TIME		1 /* ms */
> +
> +/* General purpose parameters */
> +#define REG_USER_BRIGHTNESS		0x7000022C /* Brigthness */
> +#define REG_USER_CONTRAST		0x7000022E /* Contrast */
> +#define REG_USER_SATURATION		0x70000230 /* Saturation */
> +
> +/* FIXME: No information availble about these register from the datasheet */

availble -> available

> +#define REG_USER_SHARP1			0x70000A28
> +#define REG_USER_SHARP2			0x70000ADE
> +#define REG_USER_SHARP3			0x70000B94
> +#define REG_USER_SHARP4			0x70000C4A
> +#define REG_USER_SHARP5			0x70000D00
> +
> +#define LSB(X) (((X)&  0xFF))
> +#define MSB(Y) (((Y)>>  8)&  0xFF)

Lower case for hex numbers is preferred.

> +
> +/*
> + * Preview size lists supported by sensor
> + */
> +struct regval_list *pview_size[] = {
> +	s5k4ecgx_176_preview,
> +	s5k4ecgx_352_preview,
> +	s5k4ecgx_640_preview,
> +	s5k4ecgx_720_preview,
> +};
> +
> +struct s5k4ecgx_framesize {
> +	u32 idx; /* Should indicate index of pview_size */
> +	u32 width;
> +	u32 height;
> +};
> +
> +/*
> + * TODO: currently only preview is supported and snapshopt(capture)
> + * is not implemented yet
> + */
> +static struct s5k4ecgx_framesize p_sets[] = {

p_sets -> s5k4ecgx_framesizes ?

> +	{0, 176, 144},
> +	{1, 352, 288},
> +	{2, 640, 480},
> +	{3, 720, 480},

I believe we can do without presets for just the preview operation mode.
Then, the number of registers to configure when device is powered on
should then decrease significantly.
Those presets are meant to speed up switching the device context, e.g.
from preview to capture, but they just slow down initialization, because
you have to configure all presets beforehand.

> +};
> +
> +#define S5K4ECGX_NUM_PREV ARRAY_SIZE(p_sets)
> +struct s5k4ecgx_pixfmt {
> +	enum v4l2_mbus_pixelcode code;
> +	u32 colorspace;
> +};
> +
> +/* By defaut value, output from sensor will be YUV422 0-255 */
> +static const struct s5k4ecgx_pixfmt s5k4ecgx_formats[] = {
> +	{ V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},

Nit: missing whitespace before }.

> +};
> +
> +struct s5k4ecgx_preset {
> +		/* output pixel format and resolution */
> +		struct v4l2_mbus_framefmt mbus_fmt;
> +		u8 clk_id;
> +		u8 index;
> +};
> +
> +struct s5k4ecgx {
> +	struct v4l2_subdev sd;
> +	struct media_pad pad;
> +	struct v4l2_ctrl_handler handler;
> +
> +	struct s5k4ecgx_platform_data *pdata;
> +	struct s5k4ecgx_preset presets[S5K4ECGX_MAX_PRESETS];
> +	struct s5k4ecgx_preset *preset;
> +	struct s5k4ecgx_framesize *p_now;	/* Current frame size */
> +	struct v4l2_fract timeperframe;
> +
> +       /* protects the struct members below */
> +	struct mutex lock;
> +	int streaming;
> +
> +	/* Token for I2C burst write */
> +	enum token_type reg_type;
> +	u16 reg_addr_high;
> +	u16 reg_addr_low;
> +
> +	/* Platform specific field */
> +	int (*set_power)(int);

This need to be replaced with regulator/GPIO API, if possible.
Platform data callbacks cannot be supported on device tree platforms,
hence we really need to avoid such callbacks.

> +	int mdelay;
> +};
> +
> +static inline struct s5k4ecgx *to_s5k4ecgx(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct s5k4ecgx, sd);
> +}
> +
> +static int s5k4ecgx_write_i2c(struct i2c_client *client, u8 *data, u16 len)
> +{
> +	struct i2c_msg msg = {client->addr, 0, len, (u8 *)data};
> +	int ret;
> +
> +	ret = i2c_transfer(client->adapter,&msg, 1);
> +	mdelay(S5K4ECGX_POLL_TIME);

Argh, why is this needed ? If it can't be avoided, please replace it
with usleep_range().

> +	if (ret<  0) {
> +		dev_err(&client->dev, "Failed to write I2C err\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int s5k4ecgx_write32(struct i2c_client *client,
> +				       u16 addr, u16 data)
> +{
> +	u8 buf[4];
> +
> +	buf[0] = MSB(addr); /* SWAP 16 bit */
> +	buf[1] = LSB(addr);
> +	buf[2] = MSB(data);
> +	buf[3] = LSB(data);
> +
> +	return s5k4ecgx_write_i2c(client, buf, 4);
> +}
> +
> +static int s5k4ecgx_read_setup(struct v4l2_subdev *sd, u32 addr)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	u16 high = addr>>  16, low =  addr&  0xFFFF;
> +	int ret = 0;
> +
> +	if (priv->reg_type != TOK_READ) {
> +		priv->reg_addr_high = 0;
> +		priv->reg_type = TOK_READ;
> +	}
> +	if (priv->reg_addr_high != high) {
> +		ret = s5k4ecgx_write32(client, 0x002C, high);
> +		priv->reg_addr_high = high;
> +	}
> +	ret |= s5k4ecgx_write32(client, 0x002E, low);
> +
> +	return ret;
> +}
> +
> +static int s5k4ecgx_read16(struct i2c_client *client, u16 *val)
> +{
> +	struct i2c_msg msg[2];
> +	u16 subaddr = 0x0F12;
> +	u8 buf[2];
> +	int err;
> +
> +	subaddr = swab16(subaddr);
> +
> +	msg[0].addr = client->addr;
> +	msg[0].flags = 0;
> +	msg[0].len = 2;
> +	msg[0].buf = (u8 *)&subaddr;
> +
> +	msg[1].addr = client->addr;
> +	msg[1].flags = I2C_M_RD;
> +	msg[1].len = 2;
> +	msg[1].buf = buf;
> +
> +	err = i2c_transfer(client->adapter, msg, 2);
> +	if (unlikely(err != 2)) {

"unlikely" doesn't make much sense here, it's not a fast path.

> +		dev_err(&client->dev, "Failed to read register 0x%02x!\n",
> +			subaddr);
> +		return -EIO;
> +	}
> +
> +	*val = ((buf[0]<<  8) | buf[1]);
> +
> +	return 0;
> +}
> +
> +/*
> + * Access address will be remapped inside sensor (ARM7 core)
> + */
> +static int s5k4ecgx_write_setup(struct v4l2_subdev *sd, u16 high, u16 low)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	int ret = 0;
> +
> +	if (priv->reg_type != TOK_WRITE) {
> +		priv->reg_addr_high = 0;
> +		priv->reg_addr_low = 0;
> +		priv->reg_type = TOK_WRITE;
> +	}
> +
> +	/* FIXME: no information about 0x0028 in the datasheet */

Hint: have a look at the S5K6AAFX sensor documentation.

> +	if (priv->reg_addr_high != high) {
> +		ret = s5k4ecgx_write32(client, 0x0028, high);
> +		priv->reg_addr_high = high;
> +		priv->reg_addr_low = 0;
> +	}
> +
> +	/* FIXME: no information about 0x002A in the datasheet */

Ditto.

> +	if (priv->reg_addr_low != low) {
> +		ret |= s5k4ecgx_write32(client, 0x002A, low);
> +		priv->reg_addr_low = low;
> +	}
> +
> +	return ret;
> +}
> +
> +static int s5k4ecgx_write_ctrl(struct v4l2_subdev *sd, u32 addr, u16 data)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	int ret;
> +
> +	v4l2_dbg(1, debug, sd, "Ctrl register val 0x%4x\n", data);
> +	s5k4ecgx_write_setup(sd, addr>>  16, addr&  0xffff);
> +	ret = s5k4ecgx_write32(client, 0x0F12, data);

Just do:
	return s5k4ecgx_write32(client, 0x0f12, data);
> +
> +	return ret;
> +}
> +
> +static u8 *s5k4ecgx_prep_buffer(int *cnt, struct regval_list **pos)
> +{
> +	struct regval_list *p_cur = *pos;
> +	int burst_len = 0, len;
> +	u8 *p_buf;
> +
> +	while (p_cur->type != TOK_TERM) {
> +		/*
> +		 * Make sure two bytes data are used and address is continous

continous -> continuous

> +		 * to write them in a block
> +		 */
> +		burst_len += 2;
> +		if (TOK_WRITE != (p_cur + 1)->type)
> +			break;
> +		if ((p_cur->addr + 2) != (p_cur + 1)->addr)
> +			break;
> +		p_cur += 1;
> +	}
> +	p_buf = vmalloc(burst_len + 2);

what ? why ? Is it just to append 2 bytes at the beginning of
a register address/value array, or just to swap regiter value 
bytes ?

> +	if (!p_buf)
> +		return NULL;
> +
> +	p_buf[0] = 0x0F; /* FIXME: no information in the datasheet */
> +	p_buf[1] = 0x12;

This may be some command write buffer I2C sub-address.

> +	p_cur = *pos;
> +	len = 2;
> +	burst_len += 2; /* Add two bytes */
> +	while (1) {
> +		p_buf[len] = MSB(p_cur->val);
> +		p_buf[len + 1] = LSB(p_cur->val);
> +		len += 2;
> +		if (len<  burst_len)
> +			p_cur++;
> +		else
> +			break;
> +	}
> +	*pos = p_cur;
> +	*cnt = burst_len ;

This looks really suspicious to me. I guess the purpose of this
function is similar to what s5k6aa_write_array() does.
It looks like a helper for writing an array of registers with
contiguous addresses. This shouldn't be needed as long as you update
the I2C register write pointer as you go, when a difference of two
subsequent addresses does not equal some constant value.

Can you shed some light on why this function is needed ?

> +
> +	return p_buf;
> +}
> +
> +static int s5k4ecgx_write_burst(struct v4l2_subdev *sd,
> +					struct regval_list **pos)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	struct regval_list *p_cur = *pos;
> +	int burst_len, ret = 0;
> +	u8 *p_buf;
> +
> +	/* Select starting address of burst data */
> +	s5k4ecgx_write_setup(sd, p_cur->addr>>  16, p_cur->addr&  0xffff);
> +
> +	/* Make buffer and then copy data into it */
> +	p_buf = s5k4ecgx_prep_buffer(&burst_len, pos);
> +	if (!p_buf)
> +		return -ENOMEM;
> +	ret = s5k4ecgx_write_i2c(client, p_buf, burst_len);
> +	vfree(p_buf);
> +	priv->reg_addr_low = 0;
> +
> +	return ret;
> +}
> +
> +static int s5k4ecgx_write_array(struct v4l2_subdev *sd,
> +					struct regval_list *vals)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	int err = 0;
> +
> +	while (vals->type != TOK_TERM&&  !err) {
> +		switch (vals->type) {
> +		case TOK_WRITE:
> +			/*
> +			 * This function continues to check the
> +			 * following addresses, then update the address of vals
> +			 */
> +			err = s5k4ecgx_write_burst(sd,&vals);
> +			break;
> +		case TOK_CMD:
> +			err = s5k4ecgx_write32(client, vals->addr, vals->val);
> +			break;
> +		case TOK_DELAY:
> +			msleep(vals->val);
> +			break;
> +		default:
> +			v4l2_err(sd, "Failed to detect i2c type!\n");
> +			err = -EINVAL;
> +			break;
> +		}
> +		vals++;
> +	}
> +
> +	if (unlikely(vals->type != TOK_TERM) || err)
> +		v4l2_err(sd, "Failed to write array!\n");
> +
> +	return err;
> +}
> +
> +static void s5k4ecgx_init_parameters(struct v4l2_subdev *sd)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	int err = 0;
> +
> +	priv->streaming = 0;
> +	/* brigthness default */
> +	err = s5k4ecgx_write_array(sd, s5k4ecgx_ev_default);
> +	/* no image effect */
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_effect_normal);
> +	/* white blance auto */
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_wb_auto);
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_contrast_default);
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_iso_auto);
> +	/* default 30 FPS */
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_fps_30);
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_scene_default);
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_saturation_default);
> +	err |= s5k4ecgx_write_array(sd, s5k4ecgx_sharpness_default);

I hope most of these go away, when we're done ;)

> +	if (err)
> +		v4l2_err(sd, "Failed to write init params!\n");
> +}
> +
> +static void s5k4ecgx_set_framesize(struct v4l2_subdev *sd,
> +					struct v4l2_mbus_framefmt *in)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	struct s5k4ecgx_framesize *a = p_sets;
> +	struct s5k4ecgx_framesize *z = p_sets + S5K4ECGX_NUM_PREV - 1;
> +
> +	/* If not match, assign the biggest size  */
> +	while (a != z) {
> +		if (a->width == in->width&&  a->height == in->height)
> +			break;
> +		a++;
> +	}
> +	priv->p_now = a;
> +}
> +
> +static int s5k4ecgx_get_pixfmt_index(struct s5k4ecgx *priv,
> +				   struct v4l2_mbus_framefmt *mf)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i<  ARRAY_SIZE(s5k4ecgx_formats); i++)
> +		if (mf->colorspace == s5k4ecgx_formats[i].colorspace&&
> +		    mf->code == s5k4ecgx_formats[i].code)
> +			return i;
> +
> +	return 0;
> +}
> +
> +static void s5k4ecgx_try_fmt(struct s5k4ecgx *priv,
> +			     struct v4l2_mbus_framefmt *mf)
> +{
> +	unsigned int index;
> +
> +	v4l_bound_align_image(&mf->width, S5K4ECGX_WIN_WIDTH_MIN,
> +			S5K4ECGX_WIN_WIDTH_MAX, 1,&mf->height,
> +			S5K4ECGX_WIN_HEIGHT_MIN, S5K4ECGX_WIN_HEIGHT_MAX, 1, 0);

You should return just 1 of 4 discrete resolutions here, according to 
p_sets[] array. Now the user is juts fooled that we support any resolution
in range from S5K4ECGX_WIN_WIDTH_MIN x S5K4ECGX_WIN_HEIGHT_MIN to
S5K4ECGX_WIN_WIDTH_MAX x S5K4ECGX_WIN_HEIGHT_MAX, with 2 pixel increments.

Please see noon010pc30.c driver for a reference.

> +	if (mf->colorspace != V4L2_COLORSPACE_JPEG)
> +		mf->colorspace = V4L2_COLORSPACE_JPEG;
> +	index = s5k4ecgx_get_pixfmt_index(priv, mf);
> +	mf->colorspace	= s5k4ecgx_formats[0].colorspace;
> +	mf->code		= s5k4ecgx_formats[0].code;
> +	mf->field		= V4L2_FIELD_NONE;
> +}
> +
> +static int s5k4ecgx_read_fw_ver(struct v4l2_subdev *sd)
> +{
> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
> +	u16 fw_ver = 0, hw_rev = 0;
> +
> +	s5k4ecgx_read_setup(sd, REG_FW_VERSION);
> +	s5k4ecgx_read16(client,&fw_ver);
> +	if (fw_ver != S5K4ECGX_FW_VERSION) {
> +		v4l2_err(sd, "FW version check failed!");
> +		return -ENODEV;
> +	}
> +	s5k4ecgx_read_setup(sd, REG_FW_REVISION);
> +	s5k4ecgx_read16(client,&hw_rev);
> +
> +	if (hw_rev == S5K4ECGX_REVISION_1_1) {
> +		v4l2_info(sd, "chip found FW ver: 0x%X, HW rev: 0x%X\n",
> +						fw_ver, hw_rev);
> +	} else {
> +		v4l2_err(sd, "chip found but it has unknown revision 0x%x\n",

How about just making it:
		v4l2_err(sd, "Unknown H/W revision: %#x\n", hw_rev);

> +		return -ENODEV;
> +	};
> +
> +	return 0;
> +}
> +
> +static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_fh *fh,
> +				   struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->index>= ARRAY_SIZE(s5k4ecgx_formats))
> +		return -EINVAL;
> +	code->code = s5k4ecgx_formats[code->index].code;
> +
> +	return 0;
> +}
> +
> +static int s5k4ecgx_enum_frame_size(struct v4l2_subdev *sd,
> +				  struct v4l2_subdev_fh *fh,
> +				  struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	int i = ARRAY_SIZE(s5k4ecgx_formats);
> +
> +	if (fse->index>  0)

No, if you support 4 resolutions, fse->index = 0..3 are valid.

> +		return -EINVAL;
> +
> +	while (--i)
> +		if (fse->code == s5k4ecgx_formats[i].code)
> +			break;
> +
> +	fse->code = s5k4ecgx_formats[i].code;
> +	fse->min_width	= S5K4ECGX_WIN_WIDTH_MIN;
> +	fse->max_width	= S5K4ECGX_WIN_WIDTH_MAX;

min_width, max_width should be equal in your case, to a pixel width
of resolution pointed by fse->index.

> +	fse->max_height = S5K4ECGX_WIN_HEIGHT_MIN;
> +	fse->min_height = S5K4ECGX_WIN_HEIGHT_MAX;

Similar as for width.

> +
> +	return 0;
> +}
> +
> +static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
> +			    struct v4l2_subdev_format *fmt)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	struct v4l2_mbus_framefmt *mf;
> +
> +	memset(fmt->reserved, 0, sizeof(fmt->reserved));

I think it's safe to drop that line.

> +	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> +		mf = v4l2_subdev_get_try_format(fh, 0);
> +		fmt->format = *mf;
> +		return 0;
> +	}
> +	mutex_lock(&priv->lock);
> +	fmt->format.width = priv->p_now->width;
> +	fmt->format.height = priv->p_now->height;
> +	mutex_unlock(&priv->lock);
> +
> +	return 0;
> +}
> +
> +static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
> +			    struct v4l2_subdev_format *fmt)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	struct s5k4ecgx_preset *preset = priv->preset;
> +	struct v4l2_mbus_framefmt *mf;
> +	struct v4l2_rect *crop;
> +	int ret = 0;
> +
> +	mutex_lock(&priv->lock);
> +	s5k4ecgx_try_fmt(priv,&fmt->format);
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> +		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
> +		crop = v4l2_subdev_get_try_crop(fh, 0);
> +	} else {
> +		if (priv->streaming)
> +			ret = -EBUSY;
> +		else
> +			mf =&preset->mbus_fmt;
> +	}
> +	if (ret == 0) {
> +		*mf = fmt->format;
> +		s5k4ecgx_set_framesize(sd,&fmt->format);
> +	}
> +	mutex_unlock(&priv->lock);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_subdev_pad_ops s5k4ecgx_pad_ops = {
> +	.enum_mbus_code		= s5k4ecgx_enum_mbus_code,
> +	.enum_frame_size	= s5k4ecgx_enum_frame_size,
> +	.get_fmt	= s5k4ecgx_get_fmt,
> +	.set_fmt	= s5k4ecgx_set_fmt,
> +};
> +
> +/*
> + * V4L2 subdev controls
> + */
> +static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +
> +	struct v4l2_subdev *sd =&container_of(ctrl->handler, struct s5k4ecgx,
> +						handler)->sd;
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	int err = 0;
> +
> +	v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val);
> +	mutex_lock(&priv->lock);
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_CONTRAST:
> +		err = s5k4ecgx_write_ctrl(sd, REG_USER_CONTRAST, ctrl->val);
> +		break;
> +
> +	case V4L2_CID_SATURATION:
> +		err = s5k4ecgx_write_ctrl(sd, REG_USER_SATURATION, ctrl->val);
> +		break;
> +
> +	case V4L2_CID_SHARPNESS:
> +		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP1, ctrl->val);
> +		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP2, ctrl->val);
> +		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP3, ctrl->val);
> +		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP4, ctrl->val);
> +		err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP5, ctrl->val);

????????

Are you writing sharpness value for all possible "presets" even though
only preset 0 is used ?

> +		break;
> +
> +	case V4L2_CID_BRIGHTNESS:
> +		err = s5k4ecgx_write_ctrl(sd, REG_USER_BRIGHTNESS, ctrl->val);
> +		break;
> +	default:

This should never happen, i.e. s_ctrl is only called with valid ctrl->id.

> +		v4l2_dbg(1, debug, sd, "unknown set ctrl id 0x%x\n", ctrl->id);
> +		err = -ENOIOCTLCMD;

Return value should be -EINVAL, if you ever decide to keep it.

> +		break;
> +	}
> +
> +	/* Review this */
> +	priv->reg_type = TOK_TERM;
> +
> +	mutex_unlock(&priv->lock);
> +
> +	if (err<  0)
> +		v4l2_err(sd, "Failed to write videoc_s_ctrl err %d\n", err);

"Failed to write videoc_s_ctrl err" ? ;)

> +	return err;
> +}
> +
> +static const struct v4l2_ctrl_ops s5k4ecgx_ctrl_ops = {
> +	.s_ctrl = s5k4ecgx_s_ctrl,
> +};
> +
> +/*
> + * Reading s5k4ecgx version information
> + */
> +static int s5k4ecgx_registered(struct v4l2_subdev *sd)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	int ret;
> +
> +	if (!priv->set_power) {
> +		v4l2_err(sd, "Error: power callback undefined!\n");

Is it possible to avoid this callback, by moving voltage regulators
handling to this driver ?

> +		return -EIO;
> +	}
> +
> +	mutex_lock(&priv->lock);
> +	priv->set_power(true);
> +	/* Time to stablize sensor */
> +	mdelay(priv->mdelay);

Ugh, why people keep using those busy wait delays, instead of
yielding CPU cycles to other tasks, by using *sleep*(..) versions ?

> +	ret = s5k4ecgx_read_fw_ver(sd);
> +	priv->set_power(false);
> +	mutex_unlock(&priv->lock);
> +
> +	return ret;
> +}
> +
> +/*
> + *  V4L2 subdev internal operations
> + */
> +static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> +{
> +
> +	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
> +	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
> +
> +	format->colorspace = s5k4ecgx_formats[0].colorspace;
> +	format->code = s5k4ecgx_formats[0].code;
> +	format->width = S5K4ECGX_OUT_WIDTH_DEF;
> +	format->height = S5K4ECGX_OUT_HEIGHT_DEF;
> +	format->field = V4L2_FIELD_NONE;
> +
> +	crop->width = S5K4ECGX_WIN_WIDTH_MAX;
> +	crop->height = S5K4ECGX_WIN_HEIGHT_MAX;
> +	crop->left = 0;
> +	crop->top = 0;
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_internal_ops s5k4ecgx_subdev_internal_ops = {
> +	.registered = s5k4ecgx_registered,
> +	.open = s5k4ecgx_open,
> +};
> +
> +static int s5k4ecgx_s_power(struct v4l2_subdev *sd, int on)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +
> +	if (!priv->set_power)
> +		return -EIO;
> +
> +	v4l2_dbg(1, debug, sd, "Switching %s\n", on ? "on" : "off");
> +
> +	if (on) {
> +		priv->set_power(on);
> +		/* Time to stablize sensor */
> +		mdelay(priv->mdelay);

msleep()

> +		/* Loading firmware into ARM7 core of sensor */
> +		if (s5k4ecgx_write_array(sd, s5k4ecgx_init_regs)<  0) {

Yes, those register arrays could be converted to real firmware blobs
as well. :)

> +			priv->set_power(0); /* Turn off power */
> +			return -EIO;
> +		}
> +		s5k4ecgx_init_parameters(sd);
> +	} else {
> +		priv->set_power(0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int s5k4ecgx_log_status(struct v4l2_subdev *sd)
> +{
> +	v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_subdev_core_ops s5k4ecgx_core_ops = {
> +	.s_power = s5k4ecgx_s_power,
> +	.log_status	= s5k4ecgx_log_status,
> +};
> +
> +static int __s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	int err = 0;
> +
> +	if (on)
> +		err = s5k4ecgx_write_array(sd, pview_size[priv->p_now->idx]);
> +
> +	return err;
> +}
> +
> +static int s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
> +{
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +	int ret = 0;
> +
> +	v4l2_dbg(1, debug, sd, "Turn streaming %s\n", on ? "on" : "off");
> +	mutex_lock(&priv->lock);
> +
> +	if (on) {
> +		/* Ignore if s_stream is called twice */
> +		if (!priv->streaming) {
> +			ret = __s5k4ecgx_s_stream(sd, on);
> +			if (!ret)
> +				priv->streaming = on;
> +		}
> +	} else {
> +		priv->streaming = 0;

Data streaming is still active, as no registers were touched in this 
case. So this line should probably be moved to s_power(sd, 0) case above.

> +	}
> +
> +	mutex_unlock(&priv->lock);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_subdev_video_ops s5k4ecgx_video_ops = {
> +	.s_stream = s5k4ecgx_s_stream,
> +};
> +
> +static const struct v4l2_subdev_ops s5k4ecgx_ops = {
> +	.core =&s5k4ecgx_core_ops,
> +	.pad =&s5k4ecgx_pad_ops,
> +	.video =&s5k4ecgx_video_ops,
> +};
> +
> +static int s5k4ecgx_initialize_ctrls(struct s5k4ecgx *priv)
> +{
> +	const struct v4l2_ctrl_ops *ops =&s5k4ecgx_ctrl_ops;
> +	struct v4l2_ctrl_handler *hdl =&priv->handler;
> +	int ret;
> +
> +	ret =  v4l2_ctrl_handler_init(hdl, 16);

The hint should be 4, not 16. There are only 4 controls added to the
control handler below.

> +	if (ret)
> +		return ret;
> +
> +	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -208, 127, 1, 0);

Is minimum brightness really -208 ?

> +	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
> +	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
> +
> +	/* For sharpness, 0x6024 is default value */
> +	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704, 24612, 8208,
> +			  24612);

How about:
	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704/8208, 24612/8208, 1,
> +			  24612/8208);

and multiplying brightness control value by 8208 in s_ctrl() ?
It's not that difficult and would let us present more uniform interface
to the user.

> +	if (hdl->error) {
> +		ret = hdl->error;
> +		v4l2_ctrl_handler_free(hdl);
> +		return ret;
> +	}
> +	priv->sd.ctrl_handler = hdl;
> +
> +	return 0;
> +};
> +
> +/*
> + * Set initial values for all preview presets
> + */
> +static void s5k4ecgx_presets_data_init(struct s5k4ecgx *priv)
> +{
> +	struct s5k4ecgx_preset *preset =&priv->presets[0];
> +	int i;
> +
> +	for (i = 0; i<  S5K4ECGX_MAX_PRESETS; i++) {
> +		preset->mbus_fmt.width	= S5K4ECGX_OUT_WIDTH_DEF;
> +		preset->mbus_fmt.height	= S5K4ECGX_OUT_HEIGHT_DEF;
> +		preset->mbus_fmt.code	= s5k4ecgx_formats[0].code;
> +		preset->index		= i;
> +		preset->clk_id		= 0;
> +		preset++;
> +	}
> +	priv->preset =&priv->presets[0];
> +}
> +
> +/*
> +  * Fetching platform data is being done with s_config subdev call.

This is not true, please remove it. There have been no s_config callback
for ages now.

> +  * In probe routine, we just register subdev device

This comment also doesn't add any special value, IMHO.

> +  */
> +static int s5k4ecgx_probe(struct i2c_client *client,
> +			  const struct i2c_device_id *id)
> +{
> +	struct v4l2_subdev *sd;
> +	struct s5k4ecgx *priv;
> +	struct s5k4ecgx_platform_data *pdata = client->dev.platform_data;
> +	int	ret;
> +
> +	if (pdata == NULL) {
> +		dev_err(&client->dev, "platform data is missing!\n");
> +		return -EINVAL;
> +	}
> +	priv = kzalloc(sizeof(struct s5k4ecgx), GFP_KERNEL);

devm_kzalloc ?

> +
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	mutex_init(&priv->lock);
> +
> +	priv->set_power = pdata->set_power;
> +	priv->mdelay = pdata->mdelay;
> +
> +	sd =&priv->sd;
> +	/* Registering subdev */
> +	v4l2_i2c_subdev_init(sd, client,&s5k4ecgx_ops);
> +	strlcpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
> +
> +	sd->internal_ops =&s5k4ecgx_subdev_internal_ops;
> +	/* Support v4l2 sub-device userspace API */
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> +	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
> +	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
> +	ret = media_entity_init(&sd->entity, 1,&priv->pad, 0);
> +	if (ret)
> +		goto out_err;
> +
> +	ret = s5k4ecgx_initialize_ctrls(priv);
> +	s5k4ecgx_presets_data_init(priv);
> +
> +	if (ret)
> +		goto out_err;
> +
> +	return 0;
> +
> + out_err:
> +	media_entity_cleanup(&priv->sd.entity);
> +	kfree(priv);
> +
> +	return ret;
> +}
> +
> +static int s5k4ecgx_remove(struct i2c_client *client)
> +{
> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +	struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> +
> +	mutex_destroy(&priv->lock);
> +	v4l2_device_unregister_subdev(sd);
> +	v4l2_ctrl_handler_free(&priv->handler);

If you use devm_kzalloc() in probe(), then this could be:

	v4l2_ctrl_handler_free(sd->ctrl_handler);

> +	media_entity_cleanup(&sd->entity);
> +	kfree(priv);

...and this line could be dropped.

> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id s5k4ecgx_id[] = {
> +	{ S5K4ECGX_DRIVER_NAME, 0 },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id);
> +
> +static struct i2c_driver v4l2_i2c_driver = {
> +	.driver = {
> +		.owner	= THIS_MODULE,
> +		.name = S5K4ECGX_DRIVER_NAME,
> +	},
> +	.probe = s5k4ecgx_probe,
> +	.remove = s5k4ecgx_remove,
> +	.id_table = s5k4ecgx_id,
> +};
> +
> +module_i2c_driver(v4l2_i2c_driver);
> +
> +MODULE_DESCRIPTION("Samsung S5K4ECGX 5MP SOC camera");
> +MODULE_AUTHOR("Sangwook Lee<sangwook.lee@linaro.org>");
> +MODULE_AUTHOR("Seok-Young Jang<quartz.jang@samsung.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/media/s5k4ecgx.h b/include/media/s5k4ecgx.h
> new file mode 100644
> index 0000000..e041761
> --- /dev/null
> +++ b/include/media/s5k4ecgx.h
> @@ -0,0 +1,29 @@
> +/*
> + * S5K4ECGX Platform data header

S5K4ECGX image sensor driver header ?

> + *
> + * Copyright (C) 2012, Linaro
> + *
> + * Copyright (C) 2010, SAMSUNG ELECTRONICS

Plase use lower case, and proper copyright for Samsung is exactly:

 "Copyright (C) 2010, Samsung Electronics Co., Ltd."

> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef S5K4ECGX_H
> +#define S5K4ECGX_H
> +
> +/**
> + * struct ss5k4ecgx_platform_data- s5k4ecgx driver platform data
> + * @set_power: an callback to give the chance to turn off/on
> + *		 camera which is depending on the board code
> + * @mdelay   : delay (ms) needed after enabling power
> + */
> +
> +struct s5k4ecgx_platform_data {
> +	int (*set_power)(int);

It would be good to replace this callback with something else, 
for the reasons I mentioned above. I think for Origen board we 
could get rid of it by adding (fixed) voltage regulator support 
in this driver and passing SRST, nSTBY GPIOs through this platform 
data structure. 

It's done this way in s5k6aa case, and for some boards the 
set_power callback remains unused (it's treated as optional in
the driver).

> +	int mdelay;
> +};
> +
> +#endif /* S5K4ECGX_H */

--

Thanks!
Sylwester

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor
       [not found]     ` <CADPsn1bniYQQ-pefrX+XdbLk1n-Na_dSYWspORkGCwo5+XBtrw@mail.gmail.com>
@ 2012-07-20 10:03       ` Sangwook Lee
  2012-07-24 20:38         ` Sylwester Nawrocki
  0 siblings, 1 reply; 8+ messages in thread
From: Sangwook Lee @ 2012-07-20 10:03 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: linux-media, mchehab, laurent.pinchart, sakari.ailus, suapapa,
	quartz.jang, linaro-dev, patches, usman.ahmad, david.a.cohen

Opps, the previous email has a HTML part, so resending.




Hi Sylwester

Thank for the review.

On 19 July 2012 20:40, Sylwester Nawrocki <sylvester.nawrocki@gmail.com> wrote:
>
> Hi Sangwook,
>
> On 07/19/2012 02:14 PM, Sangwook Lee wrote:
> > Add factory default settings for S5K4ECGX sensor registers.
> > I copied them from the reference code of Samsung S.LSI.
>
> I'm pretty sure we can do better than that. I've started S5K6AAFX sensor
> driver development with similar set of write-only register address/value
> arrays, that stored mainly register default values after the device reset,
> or were configuring presets that were never used.
>
> If you lok at the s5k6aa driver, you'll find only one relatively small
> array of register values for the analog processing block settings.
> It's true that I had to reverse engineer a couple of things, but I also
>
> had a relatively good datasheet for the sensor.
>

Yes, I already saw analog settings in s5k6aa. Compared to s5k6aa,
I couldn't also understand why the sensor has lots of initial values.
Is it because s5k4ecgx is slightly more complicated than s5k6aa ?

> > According to comments from the reference code, they do not
> > recommend any changes of these settings.
>
> Yes, but it doesn't mean cannot convert, at least part of, those ugly
> tables into function calls.


Yes, the biggest table seems to be one time for boot-up, at least I need to
remove one more macro (token)

>
> Have you tried to contact Samsung S.LSI for a datasheet that would
> contain better registers' description ?


As you might know, there is a limitation for me to get those information. :-)
Instead, if I look into the source code of Google Nexus S which uses s5k4ecgx,

  https://android.googlesource.com/kernel/samsung.git

I can discover that both Google and Samsung are using the same huge table
just for initial settings from the sensor booting-up. I added the
original author
of this sensor driver. Hopes he might add some comments :-)



Thanks
Sangwook

>
> --
>
> Thanks,
> Sylwester

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] v4l: Add v4l2 subdev driver for S5K4ECGX sensor
  2012-07-19 21:40   ` Sylwester Nawrocki
@ 2012-07-20 15:36     ` Sangwook Lee
  0 siblings, 0 replies; 8+ messages in thread
From: Sangwook Lee @ 2012-07-20 15:36 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: linux-media, mchehab, laurent.pinchart, sakari.ailus, suapapa,
	quartz.jang, linaro-dev, patches, usman.ahmad

Hi Sylwester

Thank you for the great review!

On 19 July 2012 22:40, Sylwester Nawrocki <sylvester.nawrocki@gmail.com> wrote:
>
> Hi Sangwook,
>
> A few review comments for you below...
>
> On 07/19/2012 02:14 PM, Sangwook Lee wrote:
> > This dirver implements preview mode of the S5K4ECGX sensor.
>
> dirver -> driver

OK, I will fix this.

> > capture (snapshot) operation, face detection are missing now.
> >
> > Following controls are supported:
> > contrast/saturation/birghtness/sharpness
>
> birghtness -> brightness
>

ditto

> > Signed-off-by: Sangwook Lee<sangwook.lee@linaro.org>
> > ---
> > + * Driver for s5k4ecgx (5MP Camera) from SAMSUNG
> > + * a quarter-inch optical format 1.4 micron 5 megapixel (Mp)
> > + * CMOS image sensor, as reffering to s5k6aa.c
>
> I think this should be mentioned after your own copyright notice,
> e.g. in form of:
>
> Based on s5k6aa driver,
> Copyright (C) 2011, Samsung Electronics Co., Ltd.

ditto

> > + *
> > + * Copyright (C) 2012, Linaro, Sangwook Lee<sangwook.lee@linaro.org>
> > + * Copyright (C) 2012, Insignal Co,. Ltd,  Homin
> > Lee<suapapa@insignal.co.kr>
> > + * Copyright (C) 2011, SAMSUNG ELECTRONICS
>
> No need to shout, "Samsung Electronics Co., Ltd." would be just enough.

ditto

>

> > +#include<media/v4l2-device.h>
> > +#include<media/v4l2-subdev.h>
> > +#include<media/media-entity.h>
> > +#include<media/v4l2-ctrls.h>
> > +#include<media/v4l2-mediabus.h>
> > +#include<media/s5k4ecgx.h>
>
> Can we, please, have these sorted alphabetically ?

OK, I will fix this.

>
> > +#include "s5k4ecgx_regs.h"
> > +
> > +static int debug;
> > +module_param(debug, int, 0644);
> > +
[snip]
> > +/* General purpose parameters */
> > +#define REG_USER_BRIGHTNESS          0x7000022C /* Brigthness */
>
> availble -> available

ditto

>
> > +#define REG_USER_SHARP1                      0x70000A28
> > +#define REG_USER_SHARP2                      0x70000ADE
> > +#define REG_USER_SHARP3                      0x70000B94
> > +#define REG_USER_SHARP4                      0x70000C4A
> > +#define REG_USER_SHARP5                      0x70000D00
> > +
> > +#define LSB(X) (((X)&  0xFF))
> > +#define MSB(Y) (((Y)>>  8)&  0xFF)
>
> Lower case for hex numbers is preferred.
>

ditto

> > +
> > +/*
> > + * Preview size lists supported by sensor
> > + */
> > +struct regval_list *pview_size[] = {
> > +     s5k4ecgx_176_preview,
> > +     s5k4ecgx_352_preview,
> > +     s5k4ecgx_640_preview,
> > +     s5k4ecgx_720_preview,
> > +};
> > +
> > +struct s5k4ecgx_framesize {
> > +     u32 idx; /* Should indicate index of pview_size */
> > +     u32 width;
> > +     u32 height;
> > +};
> > +
> > +/*
> > + * TODO: currently only preview is supported and snapshopt(capture)
> > + * is not implemented yet
> > + */
> > +static struct s5k4ecgx_framesize p_sets[] = {
>
> p_sets -> s5k4ecgx_framesizes ?

Hmm, the structure name needs to be changed properly.

>
> > +     {0, 176, 144},
> > +     {1, 352, 288},
> > +     {2, 640, 480},
> > +     {3, 720, 480},
>
> I believe we can do without presets for just the preview operation mode.

This (p_sets[]) is only used to configure preview size dynamically
when _s_fmt is called and then s_stream become on.

> Then, the number of registers to configure when device is powered on
> should then decrease significantly.
> Those presets are meant to speed up switching the device context, e.g.
> from preview to capture, but they just slow down initialization, because
> you have to configure all presets beforehand.
>
> > +};
> > +
> > +#define S5K4ECGX_NUM_PREV ARRAY_SIZE(p_sets)
> > +struct s5k4ecgx_pixfmt {
> > +     enum v4l2_mbus_pixelcode code;
> > +     u32 colorspace;
> > +};
> > +
> > +/* By defaut value, output from sensor will be YUV422 0-255 */
> > +static const struct s5k4ecgx_pixfmt s5k4ecgx_formats[] = {
> > +     { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
>
> Nit: missing whitespace before }.

Thanks, I will fix this.

>
> > +};
> > +
> > +struct s5k4ecgx_preset {
> > +             /* output pixel format and resolution */
> > +             struct v4l2_mbus_framefmt mbus_fmt;
> > +             u8 clk_id;
> > +             u8 index;
> > +};
> > +
> > +struct s5k4ecgx {
> > +     struct v4l2_subdev sd;
> > +     struct media_pad pad;
> > +     struct v4l2_ctrl_handler handler;
> > +
> > +     struct s5k4ecgx_platform_data *pdata;
> > +     struct s5k4ecgx_preset presets[S5K4ECGX_MAX_PRESETS];
> > +     struct s5k4ecgx_preset *preset;
> > +     struct s5k4ecgx_framesize *p_now;       /* Current frame size */
> > +     struct v4l2_fract timeperframe;
> > +
> > +       /* protects the struct members below */
> > +     struct mutex lock;
> > +     int streaming;
> > +
> > +     /* Token for I2C burst write */
> > +     enum token_type reg_type;
> > +     u16 reg_addr_high;
> > +     u16 reg_addr_low;
> > +
> > +     /* Platform specific field */
> > +     int (*set_power)(int);
>
> This need to be replaced with regulator/GPIO API, if possible.
> Platform data callbacks cannot be supported on device tree platforms,
> hence we really need to avoid such callbacks.

Thanks for reminding me about device tree.
let me update the driver with regulator/GPIO API.

>
> > +     int mdelay;
> > +};
> > +
> > +static inline struct s5k4ecgx *to_s5k4ecgx(struct v4l2_subdev *sd)
> > +{
> > +     return container_of(sd, struct s5k4ecgx, sd);
> > +}
> > +
> > +static int s5k4ecgx_write_i2c(struct i2c_client *client, u8 *data, u16
> > len)
> > +{
> > +     struct i2c_msg msg = {client->addr, 0, len, (u8 *)data};
> > +     int ret;
> > +
> > +     ret = i2c_transfer(client->adapter,&msg, 1);
> > +     mdelay(S5K4ECGX_POLL_TIME);
>
> Argh, why is this needed ? If it can't be avoided, please replace it
> with usleep_range().

Ok, I will update this.

>
> > +     if (ret<  0) {
> > +             dev_err(&client->dev, "Failed to write I2C err\n");
> > +             return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int s5k4ecgx_write32(struct i2c_client *client,
> > +                                    u16 addr, u16 data)
> > +{
> > +     u8 buf[4];
> > +
> > +     buf[0] = MSB(addr); /* SWAP 16 bit */
> > +     buf[1] = LSB(addr);
> > +     buf[2] = MSB(data);
> > +     buf[3] = LSB(data);
> > +
> > +     return s5k4ecgx_write_i2c(client, buf, 4);
> > +}
> > +
> > +static int s5k4ecgx_read_setup(struct v4l2_subdev *sd, u32 addr)
> > +{
> > +     struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     u16 high = addr>>  16, low =  addr&  0xFFFF;
> > +     int ret = 0;
> > +
> > +     if (priv->reg_type != TOK_READ) {
> > +             priv->reg_addr_high = 0;
> > +             priv->reg_type = TOK_READ;
> > +     }
> > +     if (priv->reg_addr_high != high) {
> > +             ret = s5k4ecgx_write32(client, 0x002C, high);
> > +             priv->reg_addr_high = high;
> > +     }
> > +     ret |= s5k4ecgx_write32(client, 0x002E, low);
> > +
> > +     return ret;
> > +}
> > +
> > +static int s5k4ecgx_read16(struct i2c_client *client, u16 *val)
> > +{
> > +     struct i2c_msg msg[2];
> > +     u16 subaddr = 0x0F12;
> > +     u8 buf[2];
> > +     int err;
> > +
> > +     subaddr = swab16(subaddr);
> > +
> > +     msg[0].addr = client->addr;
> > +     msg[0].flags = 0;
> > +     msg[0].len = 2;
> > +     msg[0].buf = (u8 *)&subaddr;
> > +
> > +     msg[1].addr = client->addr;
> > +     msg[1].flags = I2C_M_RD;
> > +     msg[1].len = 2;
> > +     msg[1].buf = buf;
> > +
> > +     err = i2c_transfer(client->adapter, msg, 2);
> > +     if (unlikely(err != 2)) {
>
> "unlikely" doesn't make much sense here, it's not a fast path.

OK, I will fix this.

>
> > +             dev_err(&client->dev, "Failed to read register 0x%02x!\n",
> > +                     subaddr);
> > +             return -EIO;
> > +     }
> > +
> > +     *val = ((buf[0]<<  8) | buf[1]);
> > +
> > +     return 0;
> > +}
> > +
> > +/*
> > + * Access address will be remapped inside sensor (ARM7 core)
> > + */
> > +static int s5k4ecgx_write_setup(struct v4l2_subdev *sd, u16 high, u16
> > low)
> > +{
> > +     struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     int ret = 0;
> > +
> > +     if (priv->reg_type != TOK_WRITE) {
> > +             priv->reg_addr_high = 0;
> > +             priv->reg_addr_low = 0;
> > +             priv->reg_type = TOK_WRITE;
> > +     }
> > +
> > +     /* FIXME: no information about 0x0028 in the datasheet */
>
> Hint: have a look at the S5K6AAFX sensor documentation.
>
> > +     if (priv->reg_addr_high != high) {
> > +             ret = s5k4ecgx_write32(client, 0x0028, high);
> > +             priv->reg_addr_high = high;
> > +             priv->reg_addr_low = 0;
> > +     }
> > +
> > +     /* FIXME: no information about 0x002A in the datasheet */
>
> Ditto.
>
> > +     if (priv->reg_addr_low != low) {
> > +             ret |= s5k4ecgx_write32(client, 0x002A, low);
> > +             priv->reg_addr_low = low;
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> > +static int s5k4ecgx_write_ctrl(struct v4l2_subdev *sd, u32 addr, u16
> > data)
> > +{
> > +     struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +     int ret;
> > +
> > +     v4l2_dbg(1, debug, sd, "Ctrl register val 0x%4x\n", data);
> > +     s5k4ecgx_write_setup(sd, addr>>  16, addr&  0xffff);
> > +     ret = s5k4ecgx_write32(client, 0x0F12, data);
>
> Just do:
>         return s5k4ecgx_write32(client, 0x0f12, data);

OK, I will change this.

> > +
> > +     return ret;
> > +}
> > +
> > +static u8 *s5k4ecgx_prep_buffer(int *cnt, struct regval_list **pos)
> > +{
> > +     struct regval_list *p_cur = *pos;
> > +     int burst_len = 0, len;
> > +     u8 *p_buf;
> > +
> > +     while (p_cur->type != TOK_TERM) {
> > +             /*
> > +              * Make sure two bytes data are used and address is
> > continous
>
> continous -> continuous

ditto

>
> > +              * to write them in a block
> > +              */
> > +             burst_len += 2;
> > +             if (TOK_WRITE != (p_cur + 1)->type)
> > +                     break;
> > +             if ((p_cur->addr + 2) != (p_cur + 1)->addr)
> > +                     break;
> > +             p_cur += 1;
> > +     }
> > +     p_buf = vmalloc(burst_len + 2);
>
> what ? why ? Is it just to append 2 bytes at the beginning of
> a register address/value array,

Yes it is just to append 2 bytes in the beginning.

>or just to swap regiter value
> bytes ?
>
> > +     if (!p_buf)
> > +             return NULL;
> > +
> > +     p_buf[0] = 0x0F; /* FIXME: no information in the datasheet */
> > +     p_buf[1] = 0x12;
>
> This may be some command write buffer I2C sub-address.

It makes sense. thanks!

>
> > +     p_cur = *pos;
> > +     len = 2;
> > +     burst_len += 2; /* Add two bytes */
> > +     while (1) {
> > +             p_buf[len] = MSB(p_cur->val);
> > +             p_buf[len + 1] = LSB(p_cur->val);
> > +             len += 2;
> > +             if (len<  burst_len)
> > +                     p_cur++;
> > +             else
> > +                     break;
> > +     }
> > +     *pos = p_cur;
> > +     *cnt = burst_len ;
>
> This looks really suspicious to me. I guess the purpose of this
> function is similar to what s5k6aa_write_array() does.
> It looks like a helper for writing an array of registers with
> contiguous addresses.

I think so. but I can't find any burst I2C writing information in the datasheet,
and as long as the sensor requires lots of initial settings value, It makes
sense.

>This shouldn't be needed as long as you update
> the I2C register write pointer as you go, when a difference of two
> subsequent addresses does not equal some constant value.
>
> Can you shed some light on why this function is needed ?
>
currently it is also updating register write pointers (regval_list **pos)
as it is only filling register data except address.

> > +
> > +     return p_buf;
> > +}
> > +
> > +static int s5k4ecgx_write_burst(struct v4l2_subdev *sd,
> > +                                     struct regval_list **pos)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +     struct regval_list *p_cur = *pos;
> > +     int burst_len, ret = 0;
> > +     u8 *p_buf;
> > +
> > +     /* Select starting address of burst data */
> > +     s5k4ecgx_write_setup(sd, p_cur->addr>>  16, p_cur->addr&  0xffff);
> > +
> > +     /* Make buffer and then copy data into it */
> > +     p_buf = s5k4ecgx_prep_buffer(&burst_len, pos);
> > +     if (!p_buf)
> > +             return -ENOMEM;
> > +     ret = s5k4ecgx_write_i2c(client, p_buf, burst_len);
> > +     vfree(p_buf);
> > +     priv->reg_addr_low = 0;
> > +
> > +     return ret;
> > +}
> > +
> > +static int s5k4ecgx_write_array(struct v4l2_subdev *sd,
> > +                                     struct regval_list *vals)
> > +{
> > +     struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +     int err = 0;
> > +
> > +     while (vals->type != TOK_TERM&&  !err) {
> > +             switch (vals->type) {
> > +             case TOK_WRITE:
> > +                     /*
> > +                      * This function continues to check the
> > +                      * following addresses, then update the address of
> > vals
> > +                      */
> > +                     err = s5k4ecgx_write_burst(sd,&vals);
> > +                     break;
> > +             case TOK_CMD:
> > +                     err = s5k4ecgx_write32(client, vals->addr,
> > vals->val);
> > +                     break;
> > +             case TOK_DELAY:
> > +                     msleep(vals->val);
> > +                     break;
> > +             default:
> > +                     v4l2_err(sd, "Failed to detect i2c type!\n");
> > +                     err = -EINVAL;
> > +                     break;
> > +             }
> > +             vals++;
> > +     }
> > +
> > +     if (unlikely(vals->type != TOK_TERM) || err)
> > +             v4l2_err(sd, "Failed to write array!\n");
> > +
> > +     return err;
> > +}
> > +
> > +static void s5k4ecgx_init_parameters(struct v4l2_subdev *sd)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     int err = 0;
> > +
> > +     priv->streaming = 0;
> > +     /* brigthness default */
> > +     err = s5k4ecgx_write_array(sd, s5k4ecgx_ev_default);
> > +     /* no image effect */
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_effect_normal);
> > +     /* white blance auto */
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_wb_auto);
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_contrast_default);
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_iso_auto);
> > +     /* default 30 FPS */
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_fps_30);
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_scene_default);
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_saturation_default);
> > +     err |= s5k4ecgx_write_array(sd, s5k4ecgx_sharpness_default);
>
> I hope most of these go away, when we're done ;
>
> > +     if (err)
> > +             v4l2_err(sd, "Failed to write init params!\n");
> > +}
> > +
> > +static void s5k4ecgx_set_framesize(struct v4l2_subdev *sd,
> > +                                     struct v4l2_mbus_framefmt *in)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     struct s5k4ecgx_framesize *a = p_sets;
> > +     struct s5k4ecgx_framesize *z = p_sets + S5K4ECGX_NUM_PREV - 1;
> > +
> > +     /* If not match, assign the biggest size  */
> > +     while (a != z) {
> > +             if (a->width == in->width&&  a->height == in->height)
> > +                     break;
> > +             a++;
> > +     }
> > +     priv->p_now = a;
> > +}
> > +
> > +static int s5k4ecgx_get_pixfmt_index(struct s5k4ecgx *priv,
> > +                                struct v4l2_mbus_framefmt *mf)
> > +{
> > +     unsigned int i;
> > +
> > +     for (i = 0; i<  ARRAY_SIZE(s5k4ecgx_formats); i++)
> > +             if (mf->colorspace == s5k4ecgx_formats[i].colorspace&&
> > +                 mf->code == s5k4ecgx_formats[i].code)
> > +                     return i;
> > +
> > +     return 0;
> > +}
> > +
> > +static void s5k4ecgx_try_fmt(struct s5k4ecgx *priv,
> > +                          struct v4l2_mbus_framefmt *mf)
> > +{
> > +     unsigned int index;
> > +
> > +     v4l_bound_align_image(&mf->width, S5K4ECGX_WIN_WIDTH_MIN,
> > +                     S5K4ECGX_WIN_WIDTH_MAX, 1,&mf->height,
> > +                     S5K4ECGX_WIN_HEIGHT_MIN, S5K4ECGX_WIN_HEIGHT_MAX,
> > 1, 0);
>
> You should return just 1 of 4 discrete resolutions here, according to
> p_sets[] array. Now the user is juts fooled that we support any resolution
> in range from S5K4ECGX_WIN_WIDTH_MIN x S5K4ECGX_WIN_HEIGHT_MIN to
> S5K4ECGX_WIN_WIDTH_MAX x S5K4ECGX_WIN_HEIGHT_MAX, with 2 pixel increments.
>
> Please see noon010pc30.c driver for a reference.
Thanks for info.
>
> > +     if (mf->colorspace != V4L2_COLORSPACE_JPEG)
> > +             mf->colorspace = V4L2_COLORSPACE_JPEG;
> > +     index = s5k4ecgx_get_pixfmt_index(priv, mf);
> > +     mf->colorspace  = s5k4ecgx_formats[0].colorspace;
> > +     mf->code                = s5k4ecgx_formats[0].code;
> > +     mf->field               = V4L2_FIELD_NONE;
> > +}
> > +
> > +static int s5k4ecgx_read_fw_ver(struct v4l2_subdev *sd)
> > +{
> > +     struct i2c_client *client = v4l2_get_subdevdata(sd);
> > +     u16 fw_ver = 0, hw_rev = 0;
> > +
> > +     s5k4ecgx_read_setup(sd, REG_FW_VERSION);
> > +     s5k4ecgx_read16(client,&fw_ver);
> > +     if (fw_ver != S5K4ECGX_FW_VERSION) {
> > +             v4l2_err(sd, "FW version check failed!");
> > +             return -ENODEV;
> > +     }
> > +     s5k4ecgx_read_setup(sd, REG_FW_REVISION);
> > +     s5k4ecgx_read16(client,&hw_rev);
> > +
> > +     if (hw_rev == S5K4ECGX_REVISION_1_1) {
> > +             v4l2_info(sd, "chip found FW ver: 0x%X, HW rev: 0x%X\n",
> > +                                             fw_ver, hw_rev);
> > +     } else {
> > +             v4l2_err(sd, "chip found but it has unknown revision
> > 0x%x\n",
>
> How about just making it:
>                 v4l2_err(sd, "Unknown H/W revision: %#x\n", hw_rev);
>
Oh, it looks better, I will take it.

> > +             return -ENODEV;
> > +     };
> > +
> > +     return 0;
> > +}
> > +
> > +static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd,
> > +                                struct v4l2_subdev_fh *fh,
> > +                                struct v4l2_subdev_mbus_code_enum
> > *code)
> > +{
> > +     if (code->index>= ARRAY_SIZE(s5k4ecgx_formats))
> > +             return -EINVAL;
> > +     code->code = s5k4ecgx_formats[code->index].code;
> > +
> > +     return 0;
> > +}
> > +
> > +static int s5k4ecgx_enum_frame_size(struct v4l2_subdev *sd,
> > +                               struct v4l2_subdev_fh *fh,
> > +                               struct v4l2_subdev_frame_size_enum *fse)
> > +{
> > +     int i = ARRAY_SIZE(s5k4ecgx_formats);
> > +
> > +     if (fse->index>  0)
>
> No, if you support 4 resolutions, fse->index = 0..3 are valid.

Thanks, let me fix this.

>
> > +             return -EINVAL;
> > +
> > +     while (--i)
> > +             if (fse->code == s5k4ecgx_formats[i].code)
> > +                     break;
> > +
> > +     fse->code = s5k4ecgx_formats[i].code;
> > +     fse->min_width  = S5K4ECGX_WIN_WIDTH_MIN;
> > +     fse->max_width  = S5K4ECGX_WIN_WIDTH_MAX;
>
> min_width, max_width should be equal in your case, to a pixel width
> of resolution pointed by fse->index.
>
> > +     fse->max_height = S5K4ECGX_WIN_HEIGHT_MIN;
> > +     fse->min_height = S5K4ECGX_WIN_HEIGHT_MAX;
>
> Similar as for width.
>
> > +
> > +     return 0;
> > +}
> > +
> > +static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct
> > v4l2_subdev_fh *fh,
> > +                         struct v4l2_subdev_format *fmt)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     struct v4l2_mbus_framefmt *mf;
> > +
> > +     memset(fmt->reserved, 0, sizeof(fmt->reserved));
>
> I think it's safe to drop that line.
>
> > +     if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> > +             mf = v4l2_subdev_get_try_format(fh, 0);
> > +             fmt->format = *mf;
> > +             return 0;
> > +     }
> > +     mutex_lock(&priv->lock);
> > +     fmt->format.width = priv->p_now->width;
> > +     fmt->format.height = priv->p_now->height;
> > +     mutex_unlock(&priv->lock);
> > +
> > +     return 0;
> > +}
> > +
> > +static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct
> > v4l2_subdev_fh *fh,
> > +                         struct v4l2_subdev_format *fmt)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     struct s5k4ecgx_preset *preset = priv->preset;
> > +     struct v4l2_mbus_framefmt *mf;
> > +     struct v4l2_rect *crop;
> > +     int ret = 0;
> > +
> > +     mutex_lock(&priv->lock);
> > +     s5k4ecgx_try_fmt(priv,&fmt->format);
> > +
> > +     if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> > +             mf = v4l2_subdev_get_try_format(fh, fmt->pad);
> > +             crop = v4l2_subdev_get_try_crop(fh, 0);
> > +     } else {
> > +             if (priv->streaming)
> > +                     ret = -EBUSY;
> > +             else
> > +                     mf =&preset->mbus_fmt;
> > +     }
> > +     if (ret == 0) {
> > +             *mf = fmt->format;
> > +             s5k4ecgx_set_framesize(sd,&fmt->format);
> > +     }
> > +     mutex_unlock(&priv->lock);
> > +
> > +     return ret;
> > +}
> > +
> > +static const struct v4l2_subdev_pad_ops s5k4ecgx_pad_ops = {
> > +     .enum_mbus_code         = s5k4ecgx_enum_mbus_code,
> > +     .enum_frame_size        = s5k4ecgx_enum_frame_size,
> > +     .get_fmt        = s5k4ecgx_get_fmt,
> > +     .set_fmt        = s5k4ecgx_set_fmt,
> > +};
> > +
> > +/*
> > + * V4L2 subdev controls
> > + */
> > +static int s5k4ecgx_s_ctrl(struct v4l2_ctrl *ctrl)
> > +{
> > +
> > +     struct v4l2_subdev *sd =&container_of(ctrl->handler, struct
> > s5k4ecgx,
> > +                                             handler)->sd;
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     int err = 0;
> > +
> > +     v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id,
> > ctrl->val);
> > +     mutex_lock(&priv->lock);
> > +
> > +     switch (ctrl->id) {
> > +     case V4L2_CID_CONTRAST:
> > +             err = s5k4ecgx_write_ctrl(sd, REG_USER_CONTRAST,
> > ctrl->val);
> > +             break;
> > +
> > +     case V4L2_CID_SATURATION:
> > +             err = s5k4ecgx_write_ctrl(sd, REG_USER_SATURATION,
> > ctrl->val);
> > +             break;
> > +
> > +     case V4L2_CID_SHARPNESS:
> > +             err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP1,
> > ctrl->val);
> > +             err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP2,
> > ctrl->val);
> > +             err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP3,
> > ctrl->val);
> > +             err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP4,
> > ctrl->val);
> > +             err |= s5k4ecgx_write_ctrl(sd, REG_USER_SHARP5,
> > ctrl->val);
>
> ????????
>
> Are you writing sharpness value for all possible "presets" even though
> only preset 0 is used ?

I don't think so. If I see the base reference code (from Google Nexus
S 3.0 kernel)
with one set sharpness, driver always write 5 registers continuously
with the defined
same value.

For example:

S5K4ECGX_DEFINE_REGSET(s5k4ecgx_Sharpness_Minus_3) = {
        S5K4ECGX_REG_WRITE(0x70000A28, 0x0000),
        S5K4ECGX_REG_WRITE(0x70000ADE, 0x0000),
        S5K4ECGX_REG_WRITE(0x70000B94, 0x0000),
        S5K4ECGX_REG_WRITE(0x70000C4A, 0x0000),
        S5K4ECGX_REG_WRITE(0x70000D00, 0x0000),
        S5K4ECGX_REGSET_END
};


>
> > +             break;
> > +
> > +     case V4L2_CID_BRIGHTNESS:
> > +             err = s5k4ecgx_write_ctrl(sd, REG_USER_BRIGHTNESS,
> > ctrl->val);
> > +             break;
> > +     default:
>
> This should never happen, i.e. s_ctrl is only called with valid ctrl->id.

Thanks, I will fix this.

>
> > +             v4l2_dbg(1, debug, sd, "unknown set ctrl id 0x%x\n",
> > ctrl->id);
> > +             err = -ENOIOCTLCMD;
>
> Return value should be -EINVAL, if you ever decide to keep it.
>
> > +             break;
> > +     }
> > +
> > +     /* Review this */
> > +     priv->reg_type = TOK_TERM;
> > +
> > +     mutex_unlock(&priv->lock);
> > +
> > +     if (err<  0)
> > +             v4l2_err(sd, "Failed to write videoc_s_ctrl err %d\n",
> > err);
>
> "Failed to write videoc_s_ctrl err" ? ;)
>
> > +     return err;
> > +}
> > +
> > +static const struct v4l2_ctrl_ops s5k4ecgx_ctrl_ops = {
> > +     .s_ctrl = s5k4ecgx_s_ctrl,
> > +};
> > +
> > +/*
> > + * Reading s5k4ecgx version information
> > + */
> > +static int s5k4ecgx_registered(struct v4l2_subdev *sd)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     int ret;
> > +
> > +     if (!priv->set_power) {
> > +             v4l2_err(sd, "Error: power callback undefined!\n");
>
> Is it possible to avoid this callback, by moving voltage regulators
> handling to this driver ?

let me see it again when I use voltage regulator

>
> > +             return -EIO;
> > +     }
> > +
> > +     mutex_lock(&priv->lock);
> > +     priv->set_power(true);
> > +     /* Time to stablize sensor */
> > +     mdelay(priv->mdelay);
>
> Ugh, why people keep using those busy wait delays, instead of
> yielding CPU cycles to other tasks, by using *sleep*(..) versions ?
>
> > +     ret = s5k4ecgx_read_fw_ver(sd);
> > +     priv->set_power(false);
> > +     mutex_unlock(&priv->lock);
> > +
> > +     return ret;
> > +}
> > +
> > +/*
> > + *  V4L2 subdev internal operations
> > + */
> > +static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh
> > *fh)
> > +{
> > +
> > +     struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh,
> > 0);
> > +     struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0);
> > +
> > +     format->colorspace = s5k4ecgx_formats[0].colorspace;
> > +     format->code = s5k4ecgx_formats[0].code;
> > +     format->width = S5K4ECGX_OUT_WIDTH_DEF;
> > +     format->height = S5K4ECGX_OUT_HEIGHT_DEF;
> > +     format->field = V4L2_FIELD_NONE;
> > +
> > +     crop->width = S5K4ECGX_WIN_WIDTH_MAX;
> > +     crop->height = S5K4ECGX_WIN_HEIGHT_MAX;
> > +     crop->left = 0;
> > +     crop->top = 0;
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct v4l2_subdev_internal_ops
> > s5k4ecgx_subdev_internal_ops = {
> > +     .registered = s5k4ecgx_registered,
> > +     .open = s5k4ecgx_open,
> > +};
> > +
> > +static int s5k4ecgx_s_power(struct v4l2_subdev *sd, int on)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +
> > +     if (!priv->set_power)
> > +             return -EIO;
> > +
> > +     v4l2_dbg(1, debug, sd, "Switching %s\n", on ? "on" : "off");
> > +
> > +     if (on) {
> > +             priv->set_power(on);
> > +             /* Time to stablize sensor */
> > +             mdelay(priv->mdelay);
>
> msleep()
ditto

>
> > +             /* Loading firmware into ARM7 core of sensor */
> > +             if (s5k4ecgx_write_array(sd, s5k4ecgx_init_regs)<  0) {
>
> Yes, those register arrays could be converted to real firmware blobs
> as well. :)
For me, it looks like loading firmware. too many initial values. :-)

>
> > +                     priv->set_power(0); /* Turn off power */
> > +                     return -EIO;
> > +             }
> > +             s5k4ecgx_init_parameters(sd);
> > +     } else {
> > +             priv->set_power(0);
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int s5k4ecgx_log_status(struct v4l2_subdev *sd)
> > +{
> > +     v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct v4l2_subdev_core_ops s5k4ecgx_core_ops = {
> > +     .s_power = s5k4ecgx_s_power,
> > +     .log_status     = s5k4ecgx_log_status,
> > +};
> > +
> > +static int __s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     int err = 0;
> > +
> > +     if (on)
> > +             err = s5k4ecgx_write_array(sd,
> > pview_size[priv->p_now->idx]);
> > +
> > +     return err;
> > +}
> > +
> > +static int s5k4ecgx_s_stream(struct v4l2_subdev *sd, int on)
> > +{
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +     int ret = 0;
> > +
> > +     v4l2_dbg(1, debug, sd, "Turn streaming %s\n", on ? "on" : "off");
> > +     mutex_lock(&priv->lock);
> > +
> > +     if (on) {
> > +             /* Ignore if s_stream is called twice */
> > +             if (!priv->streaming) {
> > +                     ret = __s5k4ecgx_s_stream(sd, on);
> > +                     if (!ret)
> > +                             priv->streaming = on;
> > +             }
> > +     } else {
> > +             priv->streaming = 0;
>
> Data streaming is still active, as no registers were touched in this
> case. So this line should probably be moved to s_power(sd, 0) case above.

I agree that is more sensible. I just wanted a status variable in the
same function.
let me update this as well.

>
> > +     }
> > +
> > +     mutex_unlock(&priv->lock);
> > +
> > +     return ret;
> > +}
> > +
> > +static const struct v4l2_subdev_video_ops s5k4ecgx_video_ops = {
> > +     .s_stream = s5k4ecgx_s_stream,
> > +};
> > +
> > +static const struct v4l2_subdev_ops s5k4ecgx_ops = {
> > +     .core =&s5k4ecgx_core_ops,
> > +     .pad =&s5k4ecgx_pad_ops,
> > +     .video =&s5k4ecgx_video_ops,
> > +};
> > +
> > +static int s5k4ecgx_initialize_ctrls(struct s5k4ecgx *priv)
> > +{
> > +     const struct v4l2_ctrl_ops *ops =&s5k4ecgx_ctrl_ops;
> > +     struct v4l2_ctrl_handler *hdl =&priv->handler;
> > +     int ret;
> > +
> > +     ret =  v4l2_ctrl_handler_init(hdl, 16);
>
> The hint should be 4, not 16. There are only 4 controls added to the
> control handler below.

Good point, I will change this.

>
> > +     if (ret)
> > +             return ret;
> > +
> > +     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -208, 127, 1, 0);
>
> Is minimum brightness really -208 ?

so to speak, this is kind of reverse engineering :-), not from the datasheet.

I got the values such 0xFF30, 0xFFA0, 0xFFC8, 0XFFE0, 0x0, 0x20, 0X7F
                                 -208      -96
                           127

For example)
S5K4ECGX_DEFINE_REGSET(s5k4ecgx_EV_Minus_4) = {
        S5K4ECGX_REG_WRITE(0x70000230, 0xFF30),
        S5K4ECGX_REGSET_END
};


>
> > +     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
> > +     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
> > +
> > +     /* For sharpness, 0x6024 is default value */
> > +     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704, 24612,
> > 8208,
> > +                       24612);
>
> How about:
>         v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704/8208,
> 24612/8208, 1,
> > +                       24612/8208);
>
> and multiplying brightness control value by 8208 in s_ctrl() ?
> It's not that difficult and would let us present more uniform interface
> to the user.

Good point, I will change this.


> > +     if (hdl->error) {
> > +             ret = hdl->error;
> > +             v4l2_ctrl_handler_free(hdl);
> > +             return ret;
> > +     }
> > +     priv->sd.ctrl_handler = hdl;
> > +
> > +     return 0;
> > +};
> > +
> > +/*
> > + * Set initial values for all preview presets
> > + */
> > +static void s5k4ecgx_presets_data_init(struct s5k4ecgx *priv)
> > +{
> > +     struct s5k4ecgx_preset *preset =&priv->presets[0];
> > +     int i;
> > +
> > +     for (i = 0; i<  S5K4ECGX_MAX_PRESETS; i++) {
> > +             preset->mbus_fmt.width  = S5K4ECGX_OUT_WIDTH_DEF;
> > +             preset->mbus_fmt.height = S5K4ECGX_OUT_HEIGHT_DEF;
> > +             preset->mbus_fmt.code   = s5k4ecgx_formats[0].code;
> > +             preset->index           = i;
> > +             preset->clk_id          = 0;
> > +             preset++;
> > +     }
> > +     priv->preset =&priv->presets[0];
> > +}
> > +
> > +/*
> > +  * Fetching platform data is being done with s_config subdev call.
>
> This is not true, please remove it. There have been no s_config callback
> for ages now.
>
> > +  * In probe routine, we just register subdev device
>
> This comment also doesn't add any special value, IMHO.
>
> > +  */
> > +static int s5k4ecgx_probe(struct i2c_client *client,
> > +                       const struct i2c_device_id *id)
> > +{
> > +     struct v4l2_subdev *sd;
> > +     struct s5k4ecgx *priv;
> > +     struct s5k4ecgx_platform_data *pdata = client->dev.platform_data;
> > +     int     ret;
> > +
> > +     if (pdata == NULL) {
> > +             dev_err(&client->dev, "platform data is missing!\n");
> > +             return -EINVAL;
> > +     }
> > +     priv = kzalloc(sizeof(struct s5k4ecgx), GFP_KERNEL);
>
> devm_kzalloc ?

Thanks, please let me look at this.

>
> > +
> > +     if (!priv)
> > +             return -ENOMEM;
> > +
> > +     mutex_init(&priv->lock);
> > +
> > +     priv->set_power = pdata->set_power;
> > +     priv->mdelay = pdata->mdelay;
> > +
> > +     sd =&priv->sd;
> > +     /* Registering subdev */
> > +     v4l2_i2c_subdev_init(sd, client,&s5k4ecgx_ops);
> > +     strlcpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name));
> > +
> > +     sd->internal_ops =&s5k4ecgx_subdev_internal_ops;
> > +     /* Support v4l2 sub-device userspace API */
> > +     sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> > +
> > +     priv->pad.flags = MEDIA_PAD_FL_SOURCE;
> > +     sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
> > +     ret = media_entity_init(&sd->entity, 1,&priv->pad, 0);
> > +     if (ret)
> > +             goto out_err;
> > +
> > +     ret = s5k4ecgx_initialize_ctrls(priv);
> > +     s5k4ecgx_presets_data_init(priv);
> > +
> > +     if (ret)
> > +             goto out_err;
> > +
> > +     return 0;
> > +
> > + out_err:
> > +     media_entity_cleanup(&priv->sd.entity);
> > +     kfree(priv);
> > +
> > +     return ret;
> > +}
> > +
> > +static int s5k4ecgx_remove(struct i2c_client *client)
> > +{
> > +     struct v4l2_subdev *sd = i2c_get_clientdata(client);
> > +     struct s5k4ecgx *priv = to_s5k4ecgx(sd);
> > +
> > +     mutex_destroy(&priv->lock);
> > +     v4l2_device_unregister_subdev(sd);
> > +     v4l2_ctrl_handler_free(&priv->handler);
>
> If you use devm_kzalloc() in probe(), then this could be:
>
>         v4l2_ctrl_handler_free(sd->ctrl_handler);
>
> > +     media_entity_cleanup(&sd->entity);
> > +     kfree(priv);
>
> ...and this line could be dropped.
>
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct i2c_device_id s5k4ecgx_id[] = {
> > +     { S5K4ECGX_DRIVER_NAME, 0 },
> > +     {}
> > +};
> > +MODULE_DEVICE_TABLE(i2c, s5k4ecgx_id);
> > +
> > +static struct i2c_driver v4l2_i2c_driver = {
> > +     .driver = {
> > +             .owner  = THIS_MODULE,
> > +             .name = S5K4ECGX_DRIVER_NAME,
> > +     },
> > +     .probe = s5k4ecgx_probe,
> > +     .remove = s5k4ecgx_remove,
> > +     .id_table = s5k4ecgx_id,
> > +};
> > +
> > +module_i2c_driver(v4l2_i2c_driver);
> > +
> > +MODULE_DESCRIPTION("Samsung S5K4ECGX 5MP SOC camera");
> > +MODULE_AUTHOR("Sangwook Lee<sangwook.lee@linaro.org>");
> > +MODULE_AUTHOR("Seok-Young Jang<quartz.jang@samsung.com>");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/media/s5k4ecgx.h b/include/media/s5k4ecgx.h
> > new file mode 100644
> > index 0000000..e041761
> > --- /dev/null
> > +++ b/include/media/s5k4ecgx.h
> > @@ -0,0 +1,29 @@
> > +/*
> > + * S5K4ECGX Platform data header
>
> S5K4ECGX image sensor driver header ?
>
> > + *
> > + * Copyright (C) 2012, Linaro
> > + *
> > + * Copyright (C) 2010, SAMSUNG ELECTRONICS
>
> Plase use lower case, and proper copyright for Samsung is exactly:

Good point.

>
>  "Copyright (C) 2010, Samsung Electronics Co., Ltd."
>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#ifndef S5K4ECGX_H
> > +#define S5K4ECGX_H
> > +
> > +/**
> > + * struct ss5k4ecgx_platform_data- s5k4ecgx driver platform data
> > + * @set_power: an callback to give the chance to turn off/on
> > + *            camera which is depending on the board code
> > + * @mdelay   : delay (ms) needed after enabling power
> > + */
> > +
> > +struct s5k4ecgx_platform_data {
> > +     int (*set_power)(int);
>
> It would be good to replace this callback with something else,
> for the reasons I mentioned above. I think for Origen board we
> could get rid of it by adding (fixed) voltage regulator support
> in this driver and passing SRST, nSTBY GPIOs through this platform
> data structure.

Fair enough, I will fix this.

>
> It's done this way in s5k6aa case, and for some boards the
> set_power callback remains unused (it's treated as optional in
> the driver).
>
> > +     int mdelay;
> > +};
> > +
> > +#endif /* S5K4ECGX_H */
>
> --
>
> Thanks!
> Sylwester


Thanks
Sangwook

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor
  2012-07-20 10:03       ` Sangwook Lee
@ 2012-07-24 20:38         ` Sylwester Nawrocki
  0 siblings, 0 replies; 8+ messages in thread
From: Sylwester Nawrocki @ 2012-07-24 20:38 UTC (permalink / raw)
  To: Sangwook Lee
  Cc: Sylwester Nawrocki, linux-media, mchehab, laurent.pinchart,
	sakari.ailus, suapapa, quartz.jang, linaro-dev, patches,
	usman.ahmad, david.a.cohen

Hi Sangwook,

On 07/20/2012 12:03 PM, Sangwook Lee wrote:
> Hi Sylwester
> 
> Thank for the review.
> 
> On 19 July 2012 20:40, Sylwester Nawrocki<sylvester.nawrocki@gmail.com>  wrote:
>> On 07/19/2012 02:14 PM, Sangwook Lee wrote:
...
>>> Add factory default settings for S5K4ECGX sensor registers.
>>> I copied them from the reference code of Samsung S.LSI.
>>
>> I'm pretty sure we can do better than that. I've started S5K6AAFX sensor
>> driver development with similar set of write-only register address/value
>> arrays, that stored mainly register default values after the device reset,
>> or were configuring presets that were never used.
>>
>> If you lok at the s5k6aa driver, you'll find only one relatively small
>> array of register values for the analog processing block settings.
>> It's true that I had to reverse engineer a couple of things, but I also
>>
>> had a relatively good datasheet for the sensor.
>>
> 
> Yes, I already saw analog settings in s5k6aa. Compared to s5k6aa,
> I couldn't also understand why the sensor has lots of initial values.
> Is it because s5k4ecgx is slightly more complicated than s5k6aa ?

IIRC, original S5K6AAFX driver had similar number of initial values that 
were being written during initialization through I2C bus. But that's true 
the s5k4ecgx is more complex, it has more still capture features built in.

>>> According to comments from the reference code, they do not
>>> recommend any changes of these settings.
>>
>> Yes, but it doesn't mean cannot convert, at least part of, those ugly
>> tables into function calls.
> 
> 
> Yes, the biggest table seems to be one time for boot-up, at least I need to
> remove one more macro (token)

That would be a good start. Also 2 most significant bytes of register
addresses seem redundant, you'll find there mostly 0xD000 and 0x7000.
Dropping the token and 2 MS address bytes would decrease the single entry 
size from 10 to 4 bytes. Given that there is about 3000 table entries 
the driver's code size would decrease by 18 kB.

BTW, you didn't make those arrays "const", so it's all copied to RAM
during initialization...

>>
>> Have you tried to contact Samsung S.LSI for a datasheet that would
>> contain better registers' description ?
> 
> 
> As you might know, there is a limitation for me to get those information. :-)

I find it odd, given that you guys work on software support for one of
official Exynos4 reference platforms. It's really surprising.
Maybe you should just contact the right persons ?

> Instead, if I look into the source code of Google Nexus S which uses s5k4ecgx,
> 
>    https://android.googlesource.com/kernel/samsung.git
> 
> I can discover that both Google and Samsung are using the same huge table
> just for initial settings from the sensor booting-up. I added the
> original author
> of this sensor driver. Hopes he might add some comments :-)

Yeah, that would be great.

I think, this pattern of using register/value arrays is good for quick
development of drivers for many different sensors - you just switch the 
tables and everything else mostly stays the same. However, V4L2 mainline 
standards are a bit different. It would be good to convert as many of 
those arrays to functions calls as possible.

Also using vmalloc is an overkill IMO. I suspect you could use this
function (with minimal adaptations):

8<-------------------------------------------------------------------
static int s5k6aa_write_array(struct v4l2_subdev *sd,
			      const struct s5k6aa_regval *msg)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	u16 addr_incr = 0;
	int ret = 0;

	while (msg->addr != S5K6AA_TERM) {
		if (addr_incr != 2)
			ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL,
					       msg->addr);
		if (ret)
			break;
		ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val);
		if (ret)
			break;
		/* Assume that msg->addr is always less than 0xfffc */
		addr_incr = (msg + 1)->addr - msg->addr;
		msg++;
	}

	return ret;
}
8<----------------------------------------------------------------------

instead of s5k4ecgx_prep_buffer() and s5k4ecgx_write_burst(). But that 
would have to be confirmed with the datasheet or by experimentation.

--

Thanks,
Sylwester

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-07-24 20:38 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-19 12:14 [PATCH v2 0/2] Add v4l2 subdev driver for S5K4ECGX sensor with embedded SoC ISP Sangwook Lee
2012-07-19 12:14 ` [PATCH v2 1/2] v4l: Add factory register values form S5K4ECGX sensor Sangwook Lee
2012-07-19 19:40   ` Sylwester Nawrocki
     [not found]     ` <CADPsn1bniYQQ-pefrX+XdbLk1n-Na_dSYWspORkGCwo5+XBtrw@mail.gmail.com>
2012-07-20 10:03       ` Sangwook Lee
2012-07-24 20:38         ` Sylwester Nawrocki
2012-07-19 12:14 ` [PATCH v2 2/2] v4l: Add v4l2 subdev driver for " Sangwook Lee
2012-07-19 21:40   ` Sylwester Nawrocki
2012-07-20 15:36     ` Sangwook Lee

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.