From patchwork Sun Mar 28 07:47:58 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiaolin Zhang X-Patchwork-Id: 88740 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2S7m17K031858 for ; Sun, 28 Mar 2010 07:48:10 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753896Ab0C1HsJ (ORCPT ); Sun, 28 Mar 2010 03:48:09 -0400 Received: from mga11.intel.com ([192.55.52.93]:56307 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753781Ab0C1HsH convert rfc822-to-8bit (ORCPT ); Sun, 28 Mar 2010 03:48:07 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 28 Mar 2010 00:44:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.51,321,1267430400"; d="scan'208,223";a="552829394" Received: from pgsmsx601.gar.corp.intel.com ([10.221.43.69]) by fmsmga002.fm.intel.com with ESMTP; 28 Mar 2010 00:46:44 -0700 Received: from shsmsx602.ccr.corp.intel.com (10.239.4.104) by pgsmsx601.gar.corp.intel.com (10.221.43.69) with Microsoft SMTP Server (TLS) id 8.2.176.0; Sun, 28 Mar 2010 15:48:04 +0800 Received: from shsmsx501.ccr.corp.intel.com ([10.239.4.141]) by SHSMSX602.ccr.corp.intel.com ([10.239.4.104]) with mapi; Sun, 28 Mar 2010 15:48:03 +0800 From: "Zhang, Xiaolin" To: "linux-media@vger.kernel.org" CC: "Zhu, Daniel" , "Yu, Jinlu" , "Wang, Wen W" , "Huang, Kai" , "Hu, Gang A" , "Ba, Zheng" , "Zhang, Xiaolin" Date: Sun, 28 Mar 2010 15:47:58 +0800 Subject: [PATCH v2 8/10] V4L2 patches for Intel Moorestown Camera Imaging Drivers Thread-Topic: [PATCH v2 8/10] V4L2 patches for Intel Moorestown Camera Imaging Drivers Thread-Index: AcrOSvwcPCi2V55WS4i7MG8CO04XHA== Message-ID: <33AB447FBD802F4E932063B962385B351D6D5352@shsmsx501.ccr.corp.intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-cr-puzzleid: {265A5193-1EE3-4E95-8161-D850F1AE7967} x-cr-hashedpuzzle: AQqC AmUB BE49 BJo/ BWy6 CDzr DptG Dug7 D2ZV D3FO EBlz EEXp HClU IFTO JsyF KDzH; 1; bABpAG4AdQB4AC0AbQBlAGQAaQBhAEAAdgBnAGUAcgAuAGsAZQByAG4AZQBsAC4AbwByAGcA; Sosha1_v1; 7; {265A5193-1EE3-4E95-8161-D850F1AE7967}; eABpAGEAbwBsAGkAbgAuAHoAaABhAG4AZwBAAGkAbgB0AGUAbAAuAGMAbwBtAA==; Sun, 28 Mar 2010 07:47:58 GMT; WwBQAEEAVABDAEgAIAB2ADIAIAA4AC8AMQAwAF0AIABWADQATAAyACAAcABhAHQAYwBoAGUAcwAgAGYAbwByACAASQBuAHQAZQBsACAATQBvAG8AcgBlAHMAdABvAHcAbgAgAEMAYQBtAGUAcgBhACAASQBtAGEAZwBpAG4AZwAgAEQAcgBpAHYAZQByAHMA acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Sun, 28 Mar 2010 07:48:10 +0000 (UTC) diff --git a/drivers/media/video/mrstci/mrsts5k4e1/Kconfig b/drivers/media/video/mrstci/mrsts5k4e1/Kconfig new file mode 100644 index 0000000..7dee787 --- /dev/null +++ b/drivers/media/video/mrstci/mrsts5k4e1/Kconfig @@ -0,0 +1,9 @@ +config VIDEO_MRST_S5K4E1 + tristate "Moorestown s5k4e1 RAW Sensor" + depends on I2C && VIDEO_MRST_ISP + + ---help--- + Say Y here if your platform support s5k4e1 RAW Sensor. + + To compile this driver as a module, choose M here: the + module will be called mrstov2650.ko. diff --git a/drivers/media/video/mrstci/mrsts5k4e1/Makefile b/drivers/media/video/mrstci/mrsts5k4e1/Makefile new file mode 100644 index 0000000..8733fa8 --- /dev/null +++ b/drivers/media/video/mrstci/mrsts5k4e1/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_VIDEO_MRST_S5K4E1) += mrsts5k4e1.o + +EXTRA_CFLAGS += -I$(src)/../include diff --git a/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c new file mode 100644 index 0000000..1c31872 --- /dev/null +++ b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.c @@ -0,0 +1,861 @@ +/* + * Support for Moorestown Langwell Camera Imaging ISP subsystem. + * + * Copyright (c) 2009 Intel Corporation. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * + * Xiaolin Zhang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ci_sensor_common.h" +#include "mrsts5k4e1.h" + +static int s5k4e1_debug; +module_param(s5k4e1_debug, int, 0644); +MODULE_PARM_DESC(s5k4e1_debug, "Debug level (0-1)"); + +#define dprintk(level, fmt, arg...) \ + do { \ + if (s5k4e1_debug >= level) \ + printk(KERN_DEBUG "mrstisp@%s: " fmt "\n", \ + __func__, ## arg);\ + } while (0) + +#define eprintk(fmt, arg...) \ + printk(KERN_ERR "mrstisp@%s:" fmt "\n", \ + __func__, ## arg); + +#define DBG_entering dprintk(1, "entering"); +#define DBG_leaving dprintk(1, "leaving"); +#define DBG_line dprintk(1, " line: %d", __LINE__); + +static inline struct ci_sensor_config *to_sensor_config(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ci_sensor_config, sd); +} + +static struct s5k4e1_format_struct { + __u8 *desc; + __u32 pixelformat; + struct regval_list *regs; +} s5k4e1_formats[] = { + { + .desc = "Raw RGB Bayer", + .pixelformat = SENSOR_MODE_MIPI, + .regs = NULL, + }, +}; +#define N_S5K4E1_FMTS ARRAY_SIZE(s5k4e1_formats) + +static struct s5k4e1_res_struct { + __u8 *desc; + int res; + int width; + int height; + int fps; + bool used; + struct regval_list *regs; +} s5k4e1_res[] = { + { + .desc = "QSXGA_PLUS4", + .res = SENSOR_RES_QXGA_PLUS, + .width = 2592, + .height = 1944, + .fps = 15, + .used = 0, + .regs = s5k4e1_res_qsxga_plus4, + }, + { + .desc = "1080P", + .res = SENSOR_RES_1080P, + .width = 1920, + .height = 1080, + .fps = 25, + .used = 0, + .regs = s5k4e1_res_1080p, + }, + { + .desc = "VGA_PLUS", + .res = SENSOR_RES_VGA_PLUS, + .width = 1304, + .height = 980, + .fps = 30, + .used = 0, + .regs = s5k4e1_res_vga_ac04_bill, + }, + { + .desc = "720p", + .res = SENSOR_RES_720P, + .width = 1280, + .height = 720, + .fps = 30, + .used = 0, + .regs = s5k4e1_res_720p, + }, + { + .desc = "VGA", + .res = SENSOR_RES_VGA, + .width = 640, + .height = 480, + .used = 0, + .fps = 40, + .regs = s5k4e1_res_vga_ac04_bill, + }, +}; + +#define N_RES (ARRAY_SIZE(s5k4e1_res)) + +static int s5k4e1_read(struct i2c_client *c, u32 reg, u32 *value) +{ + int ret; + int i; + struct i2c_msg msg[2]; + u8 msgbuf[2]; + u8 ret_val = 0; + *value = 0; + memset(&msg, 0, sizeof(msg)); + msgbuf[0] = 0; + msgbuf[1] = 0; + i = 0; + + msgbuf[i++] = ((u16)reg) >> 8; + msgbuf[i++] = ((u16)reg) & 0xff; + msg[0].addr = c->addr; + msg[0].buf = msgbuf; + msg[0].len = i; + + msg[1].addr = c->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = &ret_val; + msg[1].len = 1; + + ret = i2c_transfer(c->adapter, &msg[0], 2); + *value = ret_val; + + ret = (ret == 2) ? 0 : -1; + dprintk(2, "reg:0x%8x, value:0x%8x - %s", reg, *value, + (ret ? "failed" : "succesfully")); + return ret; +} + +static int s5k4e1_write(struct i2c_client *c, u32 reg, u32 value) +{ + int ret, i; + struct i2c_msg msg; + u8 msgbuf[3]; + + memset(&msg, 0, sizeof(msg)); + i = 0; + msgbuf[i++] = ((u16)reg) >> 8; + msgbuf[i++] = (u16)reg & 0xff; + msgbuf[i++] = (u8)value; + + msg.addr = c->addr; + msg.flags = 0; + msg.buf = msgbuf; + msg.len = i; + + ret = i2c_transfer(c->adapter, &msg, 1); + + if (reg == 0x0103 && (value & 0x01)) + msleep(4); + + ret = (ret == 1) ? 0 : -1; + + return ret; +} + +static int s5k4e1_write_array(struct i2c_client *c, struct regval_list *vals) +{ + struct regval_list *p; + u32 read_val = 0; + int err_num = 0; + int i = 0; + + DBG_entering; + + p = vals; + while (p->reg_num != 0xffff) { + s5k4e1_write(c, (u32)p->reg_num, (u32)p->value); + s5k4e1_read(c, (u32)p->reg_num, &read_val); + if (read_val != p->value) { + eprintk("0x%x write error:should be 0x%x, but 0x%x", + p->reg_num, p->value, read_val); + err_num++; + } + p++; + i++; + } + dprintk(1, "sucessfully wrote %d registers, err is %d", i, + err_num); + return 0; +} + +static int s5k4e1_wakeup(void) +{ + DBG_entering; + + gpio_set_value(GPIO_RESET_PIN, 1); + return 0; +} + +static int s5k4e1_set_img_ctrl(struct i2c_client *c, + const struct ci_sensor_config *config) +{ + int err = 0; + + DBG_entering; + + switch (config->blc) { + case SENSOR_BLC_AUTO: + break; + default: + dprintk(1, "BLC not supported,\ + set to BLC_AUTO by default."); + } + + switch (config->bls) { + case SENSOR_BLS_OFF: + break; + default: + dprintk(1, "Black level not supported,\ + set to BLS_OFF by default."); + } + + switch (config->agc) { + /* only SENSOR_AGC_OFF supported */ + case SENSOR_AGC_OFF: + break; + default: + dprintk(1, "AGC not supported,\ + set to AGC_OFF by default."); + } + + switch (config->awb) { + /* only SENSOR_AWB_OFF supported */ + case SENSOR_AWB_OFF: + break; + default: + dprintk(1, "AWB not supported,\ + set to AWB_OFF by default."); + } + + switch (config->aec) { + /* only SENSOR_AEC_OFF supported */ + case SENSOR_AEC_OFF: + break; + default: + dprintk(1, "AEC not supported,\ + set to AEC_OFF by default."); + } + + DBG_leaving; + + return err; +} + +static int s5k4e1_init(struct i2c_client *c) +{ + int ret = 0; + struct v4l2_subdev *sd = i2c_get_clientdata(c); + struct ci_sensor_config *info = to_sensor_config(sd); + char *name = ""; + + DBG_entering; + + info->mode = s5k4e1_formats[0].pixelformat; + info->res = s5k4e1_res[0].res; + info->type = SENSOR_TYPE_RAW; + info->bls = SENSOR_BLS_OFF; + info->gamma = SENSOR_GAMMA_OFF; + info->cconv = SENSOR_CCONV_OFF; + info->blc = SENSOR_BLC_AUTO; + info->agc = SENSOR_AGC_OFF; + info->awb = SENSOR_AWB_OFF; + info->aec = SENSOR_AEC_OFF; + info->bus_width = SENSOR_BUSWIDTH_12BIT; + info->ycseq = SENSOR_YCSEQ_YCBYCR; + info->conv422 = SENSOR_CONV422_COSITED; + info->bpat = SENSOR_BPAT_GRGRBGBG; + info->field_inv = SENSOR_FIELDINV_NOSWAP; + info->field_sel = SENSOR_FIELDSEL_BOTH; + info->hpol = SENSOR_HPOL_REFPOS; + info->vpol = SENSOR_VPOL_NEG; + info->edge = SENSOR_EDGE_RISING; + info->flicker_freq = SENSOR_FLICKER_100; + info->cie_profile = SENSOR_CIEPROF_F11; + info->mipi_mode = SENSOR_MIPI_MODE_RAW_10; + name = "s5k4e1"; + memcpy(info->name, name, 7); + + ret += s5k4e1_write(c, 0x0100, (u32)0x00); + ret = s5k4e1_write(c, 0x0103, (u32)0x01); + msleep(4); + /* Set MIPI interface */ + #ifdef S5K4E1_MIPI + ret += s5k4e1_write_array(c, s5k4e1_mipi); + #endif + + ret += s5k4e1_set_img_ctrl(c, info); + /* streaming */ + ret += s5k4e1_write(c, 0x0100, (u32)0x01); + msleep(1); + DBG_leaving; + + return ret; +} + +static int distance(struct s5k4e1_res_struct *res, u32 w, u32 h) +{ + int ret; + + DBG_entering; + if (res->width < w || res->height < h) + return -1; + ret = ((res->width - w) + (res->height - h)); + DBG_leaving; + + return ret; +} + +static int s5k4e1_try_res(u32 *w, u32 *h) +{ + struct s5k4e1_res_struct *res_index, *p = NULL; + int dis, last_dis = s5k4e1_res->width + s5k4e1_res->height; + + DBG_entering; + + for (res_index = s5k4e1_res; + res_index < s5k4e1_res + N_RES; + res_index++) { + if ((res_index->width < *w) || (res_index->height < *h)) + break; + dis = distance(res_index, *w, *h); + if (dis < last_dis) { + last_dis = dis; + p = res_index; + } + } + + if (p == NULL) + p = s5k4e1_res; + if ((w != NULL) && (h != NULL)) { + *w = p->width; + *h = p->height; + } + + DBG_leaving; + return 0; +} + +static struct s5k4e1_res_struct *s5k4e1_to_res(u32 w, u32 h) +{ + struct s5k4e1_res_struct *res_index; + + DBG_entering; + for (res_index = s5k4e1_res; + res_index < s5k4e1_res + N_RES; + res_index++) + if ((res_index->width == w) && (res_index->height == h)) + break; + + if (res_index >= s5k4e1_res + N_RES) + res_index--; + DBG_leaving; + + return res_index; +} + +static int s5k4e1_try_fmt(struct v4l2_subdev *sd, + struct v4l2_format *fmt) +{ + DBG_entering; + return s5k4e1_try_res(&fmt->fmt.pix.width, &fmt->fmt.pix.height); + DBG_leaving; +} + +static int s5k4e1_get_fmt(struct v4l2_subdev *sd, + struct v4l2_format *fmt) +{ + struct ci_sensor_config *info = to_sensor_config(sd); + unsigned short width, height; + int index; + + ci_sensor_res2size(info->res, &width, &height); + + for (index = 0; index < N_RES; index++) { + if ((width == s5k4e1_res[index].width) && + (height == s5k4e1_res[index].height)) { + s5k4e1_res[index].used = 1; + continue; + } + s5k4e1_res[index].used = 0; + } + + fmt->fmt.pix.width = width; + fmt->fmt.pix.height = height; + return 0; + +} + +static int s5k4e1_set_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + struct ci_sensor_config *info = to_sensor_config(sd); + int ret = 0; + struct s5k4e1_res_struct *res_index; + u32 width, height; + int index; + + DBG_entering; + + width = fmt->fmt.pix.width; + height = fmt->fmt.pix.height; + + dprintk(1, "was told to set fmt (%d x %d) ", width, height); + ret = s5k4e1_try_res(&width, &height); + + res_index = s5k4e1_to_res(width, height); + + DBG_line; + if (res_index->regs) { + ret += s5k4e1_write(c, 0x0100, (u32)0x00); + ret = s5k4e1_write(c, 0x0103, (u32)0xff); + ret += s5k4e1_write_array(c, res_index->regs); + ret += s5k4e1_set_img_ctrl(c, info); + + #ifdef S5K4E1_MIPI + ret += s5k4e1_write_array(c, s5k4e1_mipi); + #endif + + /* streaming */ + ret = s5k4e1_write(c, 0x0100, (u32)0x01); + msleep(1); + + info->res = res_index->res; + + /* Marked current sensor res as being "used" */ + for (index = 0; index < N_RES; index++) { + if ((width == s5k4e1_res[index].width) && + (height == s5k4e1_res[index].height)) { + s5k4e1_res[index].used = 1; + continue; + } + s5k4e1_res[index].used = 0; + } + + for (index = 0; index < N_RES; index++) + dprintk(2, "index = %d, used = %d\n", index, + s5k4e1_res[index].used); + + DBG_line; + } else { + eprintk("no res for (%d x %d)", width, height); + } + + DBG_leaving; + return ret; +} + +static int s5k4e1_t_gain(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + DBG_entering; + + s5k4e1_write(client, 0x0104, 1); + + /* analog gain */ + s5k4e1_write(client, 0x0204, value >> 8); + s5k4e1_write(client, 0x0205, value & 0xff); + s5k4e1_write(client, 0x0104, 0); + + DBG_leaving; + return 0; +} + +static int s5k4e1_t_exposure(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + DBG_entering; + s5k4e1_write(client, 0x0104, 1); + /* fine integration time */ + s5k4e1_write(client, 0x0200, value >> 24); + s5k4e1_write(client, 0x0201, (value >> 16) & 0xff); + + /* coarse integration time */ + s5k4e1_write(client, 0x0202, (value & 0xff00) >> 8); + s5k4e1_write(client, 0x0203, value & 0xff); + s5k4e1_write(client, 0x0104, 0); + DBG_leaving; + return 0; +} + +static struct s5k4e1_control { + struct v4l2_queryctrl qc; + int (*query)(struct v4l2_subdev *sd, __s32 *value); + int (*tweak)(struct v4l2_subdev *sd, int value); +} s5k4e1_controls[] = { + { + .qc = { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x0, + .maximum = 0xFFFF, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + .tweak = s5k4e1_t_gain, + }, + { + .qc = { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x0, + .maximum = 0xFFFF, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + .tweak = s5k4e1_t_exposure, + }, +}; +#define N_CONTROLS (ARRAY_SIZE(s5k4e1_controls)) + +static struct s5k4e1_control *s5k4e1_find_control(__u32 id) +{ + int i; + + DBG_entering; + for (i = 0; i < N_CONTROLS; i++) + if (s5k4e1_controls[i].qc.id == id) + return s5k4e1_controls + i; + DBG_leaving; + return NULL; +} + +static int s5k4e1_queryctrl(struct v4l2_subdev *sd, + struct v4l2_queryctrl *qc) +{ + struct s5k4e1_control *ctrl = s5k4e1_find_control(qc->id); + + DBG_entering; + if (ctrl == NULL) + return -EINVAL; + *qc = ctrl->qc; + + DBG_leaving; + return 0; +} + +static int s5k4e1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + return 0; +} + +static int s5k4e1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct s5k4e1_control *octrl = s5k4e1_find_control(ctrl->id); + int ret; + + DBG_entering; + + if (octrl == NULL) + return -EINVAL; + ret = octrl->tweak(sd, ctrl->value); + if (ret >= 0) + return 0; + + DBG_leaving; + return ret; +} + +static int s5k4e1_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + DBG_entering; + + if (enable) + s5k4e1_write(client, (u32)0x0100, 0x01); + else + s5k4e1_write(client, (u32)0x0100, 0x00); + + msleep(1); + + DBG_leaving; + return 0; +} + +static int s5k4e1_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_frmsizeenum *fsize) +{ + unsigned int index = fsize->index; + + DBG_entering; + + if (index >= N_RES) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = s5k4e1_res[index].width; + fsize->discrete.height = s5k4e1_res[index].height; + fsize->reserved[0] = s5k4e1_res[index].used; + + DBG_leaving; + return 0; +} + +static int s5k4e1_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_frmivalenum *fival) +{ + unsigned int index = fival->index; + + DBG_entering; + + if (index >= N_RES) + return -EINVAL; + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = s5k4e1_res[index].fps; + + DBG_leaving; + return 0; +} + +static int s5k4e1_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + DBG_entering; + + #define V4L2_IDENT_S5K4E1 8250 + DBG_leaving; + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_S5K4E1, 0); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int s5k4e1_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned char val = 0; + int ret; + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + ret = s5k4e1_read(client, reg->reg & 0xffff, &val); + reg->val = val; + reg->size = 1; + return ret; +} + +static int s5k4e1_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + s5k4e1_write(client, reg->reg & 0xffff, reg->val & 0xff); + return 0; +} +#endif + +static const struct v4l2_subdev_video_ops s5k4e1_video_ops = { + .try_fmt = s5k4e1_try_fmt, + .s_fmt = s5k4e1_set_fmt, + .g_fmt = s5k4e1_get_fmt, + .s_stream = s5k4e1_s_stream, + .enum_framesizes = s5k4e1_enum_framesizes, + .enum_frameintervals = s5k4e1_enum_frameintervals, +}; + +static const struct v4l2_subdev_core_ops s5k4e1_core_ops = { + .g_chip_ident = s5k4e1_g_chip_ident, + .queryctrl = s5k4e1_queryctrl, + .g_ctrl = s5k4e1_g_ctrl, + .s_ctrl = s5k4e1_s_ctrl, + #ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = s5k4e1_g_register, + .s_register = s5k4e1_s_register, + #endif +}; + +static const struct v4l2_subdev_ops s5k4e1_ops = { + .core = &s5k4e1_core_ops, + .video = &s5k4e1_video_ops, +}; + +static int s5k4e1_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + int adap_id = i2c_adapter_id(adapter); + u32 value; + + DBG_entering; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + eprintk("error i2c check func"); + return -ENODEV; + } + + if (adap_id != 1) + return -ENODEV; + + if (s5k4e1_wakeup()) { + eprintk("sensor wakeup failed"); + return -EIO; + } + + s5k4e1_read(client, 0x0003, &value); + if ((value != 0x09)) + return -ENODEV; + + s5k4e1_read(client, 0x0000, &value); + if ((value != 0x4e) && (value != 0x10)) + return -ENODEV; + + s5k4e1_read(client, 0x0001, &value); + if ((value != 0x4e) && (value != 0x10)) + return -ENODEV; + + s5k4e1_read(client, 0x0002, &value); + dprintk(1, "Read from 0x0002: %x", value); + if (value == 0x0010) + return -ENODEV; + + DBG_leaving; + return 0; +} + +static int s5k4e1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ci_sensor_config *info; + struct v4l2_subdev *sd; + int ret = -1; + + DBG_entering; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + /* + * Setup sensor configuration structure + */ + info = kzalloc(sizeof(struct ci_sensor_config), GFP_KERNEL); + if (!info) { + dprintk(0, "fail to malloc for ci_sensor_config"); + ret = -ENOMEM; + goto out; + } + + ret = s5k4e1_detect(client); + if (ret) { + dprintk(0, "error s5k4e1_detect"); + goto out_free; + } + + sd = &info->sd; + v4l2_i2c_subdev_init(sd, client, &s5k4e1_ops); + + /* + * Initialization S5K4E1 + * then turn into standby mode + */ + ret = s5k4e1_init(client); + if (ret) { + dprintk(0, "error calling s5k4e1_init"); + goto out_free; + } + + dprintk(0, "Init s5k4e1 sensor successfully"); + ret = 0; + goto out; + +out_free: + kfree(info); + DBG_leaving; +out: + + DBG_leaving; + return ret; +} + + +static int s5k4e1_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + DBG_entering; + + v4l2_device_unregister_subdev(sd); + kfree(to_sensor_config(sd)); + + DBG_leaving; + return 0; +} + +static const struct i2c_device_id s5k4e1_id[] = { + {"s5k4e1", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, s5k4e1_id); + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "s5k4e1", + .probe = s5k4e1_probe, + .remove = s5k4e1_remove, + .id_table = s5k4e1_id, +}; + +MODULE_AUTHOR("Xiaolin Zhang "); +MODULE_DESCRIPTION("A low-level driver for Samsung S5K4E1 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h new file mode 100644 index 0000000..31c22c7 --- /dev/null +++ b/drivers/media/video/mrstci/mrsts5k4e1/mrsts5k4e1.h @@ -0,0 +1,573 @@ +/* + * Support for Moorestown Langwell Camera Imaging ISP subsystem. + * + * Copyright (c) 2009 Intel Corporation. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * + * Xiaolin Zhang + */ + +#define I2C_S5K4E1 0x6C +#define I2C_DRIVERID_S5K4E1 1046 +#define GPIO_SCLK_25 44 +#define GPIO_STB_PIN 47 +#define GPIO_STDBY_PIN 49 +#define GPIO_RESET_PIN 50 + +struct regval_list { + u16 reg_num; + u8 value; +}; + +static struct regval_list s5k4e1_res_qsxga_plus4[] = { + {0x0100, 0x00}, + {0x0103, 0x01}, + {0x3000, 0x04}, /* ct_ld_start (default = 07h) */ + {0x3001, 0x02}, /* ct_sl_start (default = 05h) */ + {0x3002, 0x0C}, /* ct_rx_start (default = 21h) */ + {0x3003, 0x0E}, /* ct_cds_start (default = 23h) */ + {0x3004, 0x2C}, /* ct_smp_width (default = 60h) */ + {0x3005, 0x0D}, /* ct_az_width (default = 28h) */ + {0x3006, 0x39}, /* ct_s1r_width (default = 88h) */ + {0x3007, 0x02}, /* ct_tx_start (default = 06h) */ + {0x3008, 0x3C}, /* ct_tx_width 1.5us (default = 7Ch) */ + {0x3009, 0x3C}, /* ct_stx_width 1.5us (default = 7Ch) */ + {0x300A, 0x28}, /* ct_dtx_width 1us (default = 3Eh) */ + {0x300B, 0x15}, /* ct_rmp_rst_start (default = 44h) */ + {0x300C, 0x15}, /* ct_rmp_sig_start (default = 48h) */ + {0x300D, 0x02}, /* ct_rmp_lat (default = 02h) */ + {0x300E, 0xA9}, /* D-Shut en[7], CLP On[5], LD high[4] */ + + {0x3010, 0x00}, /* smp_en[2]=0(00) 1(04) row_id[1:0] = 00 */ + {0x3011, 0x7A}, /* RST_MX (288), SIG_MX (1024+352) */ + {0x3012, 0x30}, /* SIG offset1 48 code */ + {0x3013, 0xA0}, /* RST offset1 160 code */ + {0x3014, 0x00}, /* SIG offset2 */ + {0x3015, 0x00}, /* RST offset2 */ + {0x3016, 0x02}, /* ADC_SAT (510mV) */ + {0x3017, 0x94}, /* RMP_INIT[3:0](RMP_REG) 1.8V MS[6:4]=1 */ + {0x3018, 0x78}, /* rmp option - ramp connect[MSB] +RMP INIT DAC MIN */ + {0x301D, 0xD4}, /* CLP level (default = 0Fh) */ + + {0x3021, 0x02}, /* inrush ctrl[1] off */ + {0x3022, 0x44}, /* pump ring oscillator set [7:4]=CP, [3:0]=NCP */ + {0x3024, 0x40}, /* pix voltage 2.8V (default = 88h) */ + {0x3027, 0x08}, /* ntg voltage (default = 04h) */ + + {0x301C, 0x05}, /* Pixel Bias [3:0] (default = 03h) */ + {0x30D8, 0x3F}, /* All tx off 2f, on 3f */ + + {0x3070, 0x5F}, /* [6]L-ADLC BPR, [4]ch sel, [3]L-ADLC, [2]F-ADLC */ + {0x3071, 0x00}, /* F&L-adlc max 127 (default = 11h, max 255) */ + {0x3080, 0x04}, /* F-ADLC filter A (default = 10h) */ + {0x3081, 0x38}, /* F-ADLC filter B (default = 20h) */ + + {0x0202, 0x03}, /* coarse integration time */ + {0x0203, 0xCF}, + {0x0204, 0x00}, /* analog gain[msb] 0100 x8 0080 x4 */ + {0x0205, 0x80}, /* analog gain[lsb] 0040 x2 0020 x1 */ + + {0x0340, 0x07}, /* Capture 07B4(1960[# of row]+12[V-blank]) */ + {0x0341, 0xA4}, /* Preview 03E0(980[# of row]+12[V-blank]) */ + + {0x0342, 0x0A}, /* 2738 */ + {0x0343, 0xB2}, /* (Same as sensor default) */ + + {0x3084, 0x15}, /* SYNC Mode */ + + + {0x30A9, 0x01}, + {0x0387, 0x01}, + + {0x30BD, 0x00}, /* SEL_CCP[0] */ + {0x30B2, 0x08}, /* PLL P = 8 */ + {0x30B3, 0x00}, /* PLL M[8] = 0 */ + {0x30B5, 0x01}, /* PLL S = 0 */ + {0x30BE, 0x1A}, /* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */ + + {0x30BF, 0xAB}, + {0x30C0, 0x00}, /* video_offset[7:4] 3240%12 */ + {0x30C1, 0x01}, /* pack video enable [0] */ + {0x30C8, 0x0C}, /* video_data_length 3260 = 2608 * 1.25 */ + {0x30C9, 0xA8}, + {0x30E2, 0x02}, /* num lanes[1:0] = 2 */ + {0x30EE, 0x02}, /* DPHY enable [1] */ + {0x30F1, 0x70}, /* DPHY BANDCTRL 800MHz=80.6MHz */ + {0x3111, 0x86}, /* Embedded data off [5] */ + + {0x034C, 0x0A}, + {0x034D, 0x20}, + {0x044E, 0x07}, + {0x034F, 0x98}, + + {0x0344, 0x00}, + {0x0345, 0x08}, + {0x0346, 0x00}, + {0x0347, 0x08}, + {0x0348, 0x0A}, + {0x0349, 0x27}, + {0x034A, 0x07}, + {0x034B, 0x9F}, + + {0x30d9, 0x00}, + + {0x0305, 0x05}, + {0x0306, 0x00}, + {0x0307, 0x3c}, + {0x30b5, 0x02}, + + {0x020E, 0x01}, /* Gr Digital Gain */ + {0x020F, 0x00}, + {0x0210, 0x01}, /* Red Digital Gain */ + {0x0211, 0x00}, + {0x0212, 0x01}, /* Blue Digital Gain */ + {0x0213, 0x00}, + {0x0214, 0x01}, /* Gb Digital Gain */ + {0x0215, 0x00}, + {0x0204, 0x00}, + {0x0205, 0x80}, + + {0x30E2, 0x02}, + {0x0305, 0x05}, + {0x0306, 0x00}, + {0x0307, 0x50}, /* vcc_out = 80 */ + {0x30B5, 0x01}, /* pll_s = 1 */ + {0x30B4, 0x50}, + + {0x30B2, 0x05}, + + {0x30BE, 0x1A}, /* DIV_M_PCLK = 5 */ + + {0x0100, 0x01}, + {0xffff, 0xff}, +}; + +static struct regval_list s5k4e1_res_1080p[] = { + {0x0100, 0x00}, /* stream off */ + {0x0103, 0x01}, /* software reset */ + + {0x3000, 0x04}, /* ct_ld_start (default = 07h) */ + {0x3001, 0x02}, /* ct_sl_start (default = 05h) */ + {0x3002, 0x0C}, /* ct_rx_start (default = 21h) */ + {0x3003, 0x0E}, /* ct_cds_start (default = 23h) */ + {0x3004, 0x2C}, /* ct_smp_width (default = 60h) */ + {0x3005, 0x0D}, /* ct_az_width (default = 28h) */ + {0x3006, 0x39}, /* ct_s1r_width (default = 88h) */ + {0x3007, 0x02}, /* ct_tx_start (default = 06h) */ + {0x3008, 0x3C}, /* ct_tx_width 1.5us (default = 7Ch) */ + {0x300A, 0x28}, /* ct_dtx_width 1us (default = 3Eh) */ + {0x300B, 0x15}, /* ct_rmp_rst_start (default = 44h) */ + {0x300C, 0x15}, /* ct_rmp_sig_start (default = 48h) */ + {0x300D, 0x02}, /* ct_rmp_lat (default = 02h) */ + {0x300E, 0xA9}, /* D-Shut en[7], CLP On[5], LD high[4] */ + + {0x3010, 0x00}, /* smp_en[2]=0(00) 1(04) row_id[1:0] = 00 */ + {0x3011, 0x7A}, /* RST_MX (288), SIG_MX (1024+352) */ + {0x3012, 0x30}, /* SIG offset1 48 code */ + {0x3013, 0xA0}, /* RST offset1 160 code */ + {0x3014, 0x00}, /* SIG offset2 */ + {0x3015, 0x00}, /* RST offset2 */ + {0x3016, 0x0A}, /* ADC_SAT (510mV) */ + {0x3017, 0x94}, /* RMP_INIT[3:0](RMP_REG) 1.8V MS[6:4]=1 */ + {0x3018, 0x78}, /* rmp option - ramp connect[MSB] +RMP INIT DAC MIN */ + + {0x301D, 0xD4}, /* CLP level (default = 0Fh) */ + + {0x3021, 0x02}, /* inrush ctrl[1] off */ + {0x3022, 0x41}, /* pump ring oscillator set [7:4]=CP, [3:0]=NCP */ + {0x3024, 0x08}, /* pix voltage 2.8V (default = 88h) */ + {0x3027, 0x08}, /* ntg voltage (default = 04h) */ + + {0x301C, 0x05}, /* Pixel Bias [3:0] (default = 03h) */ + {0x30D8, 0x3F}, /* All tx off 2f, on 3f */ + + {0x3070, 0x5F}, /* [6]L-ADLC BPR, [4]ch sel, [3]L-ADLC, [2]F-ADLC */ + {0x3071, 0x00}, /* F&L-adlc max 127 (default = 11h, max 255) */ + {0x3080, 0x04}, /* F-ADLC filter A (default = 10h) */ + {0x3081, 0x38}, /* F-ADLC filter B (default = 20h) */ + + {0x0202, 0x03}, /* coarse integration time */ + {0x0203, 0xCD}, + {0x0204, 0x00}, /* analog gain[msb] 0100 x8 0080 x4 */ + {0x0205, 0x80}, /* analog gain[lsb] 0040 x2 0020 x1 */ + + {0x0340, 0x04}, /*Capture 07B4(1960[# of row]+12[V-blank]) */ + {0x0341, 0x44}, /*Preview 03E0(980[# of row]+12[V-blank]) */ + + {0x0342, 0x0A}, /* 2738 */ + {0x0343, 0xB2}, /*(Same as sensor default) */ + + {0x3084, 0x15}, /* SYNC Mode */ + + {0x30BD, 0x00}, /* SEL_CCP[0] */ + {0x30B2, 0x08}, /* PLL P = 8 */ + {0x30B3, 0x00}, /* PLL M[8] = 0 */ + {0x30B4, 0x78}, /* PLL M = 129 */ + {0x30B5, 0x00}, /* PLL S = 0 */ + {0x30BE, 0x1A}, /* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */ + + {0x30BF, 0xAB}, + {0x30C0, 0x00}, /* video_offset[7:4] 2400%12 */ + {0x30C1, 0x01}, /* pack video enable [0] */ + {0x30C8, 0x09}, /* video_data_length 2400 = 1920 * 1.25 */ + {0x30C9, 0x60}, + {0x30E2, 0x02}, /* num lanes[1:0] = 2 */ + {0x30EE, 0x02}, /* DPHY enable [1] */ + {0x30F1, 0x70}, /* DPHY BANDCTRL 800MHz=80.6MHz */ + {0x3111, 0x86}, /* Embedded data off [5] */ + + {0x30b4, 0x20}, + {0x30b5, 0x01}, + + {0x30A9, 0x01}, + {0x0387, 0x01}, + {0x0344, 0x01}, /*x_addr_start 344 */ + {0x0345, 0x58}, + {0x0348, 0x08}, /*x_addr_end 2263 */ + {0x0349, 0xD7}, + {0x0346, 0x01}, /*y_addr_start 440 */ + {0x0347, 0xB8}, + {0x034A, 0x05}, /*y_addr_end 1519 */ + {0x034B, 0xEF}, + + {0x034C, 0x07}, /*x_output_size 1920 */ + {0x034D, 0x80}, + {0x034E, 0x04}, /*y_output_size 1080 */ + {0x034F, 0x38}, + + {0x30d9, 0x00}, + + {0x020E, 0x01}, /*Gr Digital Gain */ + {0x020F, 0x00}, + {0x0210, 0x01}, /*Red Digital Gain */ + {0x0211, 0x00}, + {0x0212, 0x01}, /*Blue Digital Gain */ + {0x0213, 0x00}, + {0x0214, 0x01}, /*Gb Digital Gain */ + {0x0215, 0x00}, + {0x0204, 0x00}, + {0x0205, 0x80}, + + {0x30E2, 0x02}, + {0x0305, 0x05}, + {0x0306, 0x00}, + {0x0307, 0x50}, /*vcc_out = 80 */ + {0x30B5, 0x01}, /*pll_s = 1 */ + {0x30B4, 0x50}, + + {0x30B2, 0x05}, + {0x30BE, 0x1A}, /*DIV_M_PCLK = 5 */ + {0x0383, 0x01}, + {0x0100, 0x01}, /* stream on */ + {0xffff, 0xff}, + +}; + +static struct regval_list s5k4e1_res_720p[] = { + {0x0100, 0x00}, /* stream off */ + {0x0103, 0x01}, /* software reset */ + + {0x3000, 0x04}, + {0x3001, 0x02}, + {0x3002, 0x0C}, + {0x3003, 0x0E}, + {0x3004, 0x2C}, + {0x3005, 0x0D}, + {0x3006, 0x39}, + {0x3007, 0x02}, + {0x3008, 0x3C}, + {0x3009, 0x3C}, + {0x300A, 0x28}, + {0x300B, 0x15}, + {0x300C, 0x15}, + {0x300D, 0x02}, + {0x300E, 0xAB}, + + {0x3010, 0x00}, + {0x3011, 0x7A}, + {0x3012, 0x30}, + {0x3013, 0x90}, + {0x3014, 0x00}, + {0x3015, 0x00}, + {0x3016, 0x0A}, + {0x3017, 0x84}, + {0x3018, 0x78}, + {0x301D, 0xD4}, + + {0x3021, 0x02}, + {0x3022, 0x41}, + {0x3024, 0x08}, + {0x3027, 0x08}, + + {0x301C, 0x05}, /* Pixel Bias [3:0] (default = 03h) */ + {0x30D8, 0x3F}, /* All tx off 2f, on 3f */ + + {0x3070, 0x5F}, + {0x3071, 0x00}, + {0x3080, 0x04}, + {0x3081, 0x38}, + + {0x0202, 0x03}, + {0x0203, 0xD8}, + {0x0204, 0x00}, + {0x0205, 0x80}, + + {0x0340, 0x02}, + {0x0341, 0xDC}, + + {0x0342, 0x0A}, /*2738 */ + {0x0343, 0xB2}, + + {0x0387, 0x03}, + {0x30a9, 0x02}, + {0x3084, 0x15}, + + {0x30BD, 0x00}, + {0x30B2, 0x08}, + {0x30B3, 0x00}, + {0x30B4, 0x78}, + {0x30B5, 0x00}, + {0x30BE, 0x1A}, + + {0x30BF, 0xAB}, + {0x30C0, 0x40}, + {0x30C1, 0x01}, + {0x30C8, 0x06}, + {0x30C9, 0x40}, + + {0x30E2, 0x02}, + + {0x30b4, 0x20}, + {0x30b5, 0x01}, + + {0x30EE, 0x02}, + {0x30F1, 0x70}, + {0x3111, 0x86}, + + {0x0344, 0x00}, + {0x0345, 0x18}, + {0x0348, 0x0A}, + {0x0349, 0x17}, + {0x0346, 0x01}, + {0x0347, 0x04}, + {0x034A, 0x06}, + {0x034B, 0xA3}, + + {0x0380, 0x00}, + {0x0381, 0x01}, + {0x0382, 0x00}, + {0x0383, 0x01}, + {0x0384, 0x00}, + {0x0385, 0x01}, + {0x0386, 0x00}, + {0x0387, 0x03}, + + {0x034C, 0x05}, /* x_output_size = 1280 */ + {0x034D, 0x00}, + {0x034E, 0x02}, /* y_output_size = 720 */ + {0x034F, 0xD0}, + + {0x30d9, 0x00}, + + {0x020E, 0x01}, + {0x020F, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + {0x0204, 0x01}, + {0x0205, 0x00}, + + {0x30E2, 0x02}, + {0x0305, 0x05}, + {0x0306, 0x00}, + {0x0307, 0x50}, /*vcc_out = 80 */ + {0x30B5, 0x01}, /*pll_s = 1 */ + {0x30B4, 0x50}, + + {0x30B2, 0x05}, + + {0x30BE, 0x15}, /*DIV_M_PCLK = 5 */ + + {0x0100, 0x01}, /* stream on */ + {0xffff, 0xff}, +}; + +/*VGA*/ +static struct regval_list s5k4e1_res_vga_ac04_bill[] = { + {0x0100, 0x00}, + {0x0103, 0x01}, + + {0x3000, 0x04}, + {0x3001, 0x02}, + {0x3002, 0x0C}, + {0x3003, 0x0E}, + {0x3004, 0x2C}, + {0x3005, 0x0D}, + {0x3006, 0x39}, + {0x3007, 0x02}, + {0x3008, 0x3C}, + {0x3009, 0x3C}, + {0x300A, 0x28}, + {0x300B, 0x15}, + {0x300C, 0x15}, + {0x300D, 0x02}, + {0x300E, 0xA8}, + + {0x3010, 0x00}, + {0x3011, 0x7A}, + {0x3012, 0x30}, + {0x3013, 0xA0}, + {0x3014, 0x00}, + {0x3015, 0x00}, + {0x3016, 0x0A}, + {0x3017, 0x94}, + {0x3018, 0x78}, + + {0x301D, 0xD4}, + + {0x3021, 0x02}, + {0x3022, 0x41}, + {0x3024, 0x08}, + {0x3027, 0x08}, + + {0x301C, 0x05}, + {0x30D8, 0x3F}, + + {0x3070, 0x5F}, + {0x3071, 0x00}, + {0x3080, 0x04}, + {0x3081, 0x38}, + + {0x0202, 0x03}, + {0x0203, 0xD4}, + {0x0204, 0x00}, + {0x0205, 0x20}, + + {0x0340, 0x03}, + {0x0341, 0xE0}, + + {0x0342, 0x0A}, + {0x0343, 0xB2}, + + {0x0344, 0x00}, + {0x0345, 0x18}, + {0x0348, 0x0A}, + {0x0349, 0x17}, + {0x0346, 0x00}, + {0x0347, 0x14}, + {0x034A, 0x07}, + {0x034B, 0x93}, + + {0x034C, 0x02}, + {0x034D, 0x80}, + {0x034E, 0x01}, + {0x034F, 0xE0}, + + {0x0380, 0x00}, + {0x0381, 0x01}, + {0x0382, 0x00}, + {0x0383, 0x07}, + {0x0384, 0x00}, + {0x0385, 0x01}, + {0x0386, 0x00}, + {0x0387, 0x07}, + + {0x3084, 0x15}, + + {0x30BD, 0x00}, + + {0x30b3, 0x00}, + {0x30b4, 0x57}, + {0x30b5, 0x01}, + {0x30f1, 0x70}, + + {0x30BE, 0x1A}, + + {0x30BF, 0xAB}, + {0x30C0, 0x80}, + {0x30C1, 0x01}, + {0x30C8, 0x03}, + {0x30C9, 0x20}, + + {0x30b2, 0x06}, + {0x30E2, 0x02}, + + {0x30EE, 0x02}, + + {0x3111, 0x86}, + + {0x30d9, 0x00}, + + {0x020E, 0x01}, + {0x020F, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + {0x0204, 0x01}, + {0x0205, 0x00}, + + {0x30E2, 0x02}, + {0x0305, 0x05}, + {0x0306, 0x00}, + {0x0307, 0x50}, + {0x30B5, 0x01}, + {0x30B4, 0x50}, + + {0x30B2, 0x05}, + {0x30BE, 0x15}, + + /* 1304x980 */ + {0x3013, 0x90}, + {0x3017, 0x84}, + {0x30A9, 0x02}, + {0x300E, 0xAB}, + + {0x0387, 0x03}, + {0x0344, 0x00}, /* x_addr_start = 0 */ + {0x0345, 0x00}, + {0x0348, 0x0A}, /* x_addr_end = 2607 */ + {0x0349, 0x2F}, + {0x0346, 0x00}, /* y_addr_start = 0 */ + {0x0347, 0x00}, + {0x034A, 0x07}, /* y_addr_end = 1959 */ + {0x034B, 0xA7}, + {0x0380, 0x00}, + {0x0381, 0x01}, + {0x0382, 0x00}, + {0x0383, 0x01}, + {0x0384, 0x00}, + {0x0385, 0x01}, + {0x0386, 0x00}, + {0x0387, 0x03}, + {0x034c, 0x05}, /* x_output_size = 1304 */ + {0x034d, 0x18}, + {0x034e, 0x03}, /* y_output_size = 980 */ + {0x034f, 0xd4}, + {0x30BF, 0xAB}, + {0x30c0, 0xa0}, + {0x30C8, 0x06}, /* x_output_size * 1.25 */ + {0x30c9, 0x5e}, + + {0x0100, 0x01}, + {0xffff, 0xff}, +};