v4l: Add RDACM20 driver
The RDACM20 is a GMSL camera developed by IMI based on an Omnivision
10635 sensor and a Maxim MAX9271 GMSL serializer.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
media: i2c: rdacm20: Remove cross-device writes in s_stream
Remove writes to max9286 subdevice in rdacm20 s_stream now that we have
an s_stream operation in max9286 driver
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
media: i2c: rdacm20: Remove commented out writes in s_stream
Remove writes commented out in rdacm20 s_stream operation.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
v4l: rdacm20: Initialize the hardware before the V4L2 subdev
This ensures that the hardware is responsive before proceeding with
further initialization.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Use an I2C dummy client to communicate with the sensor
Use the right API for the job instead of modifying the address of the
I2C client on the fly.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Check the MAX9271 ID register at probe time
This ensures proper communication with the hardware.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Initialize the OV10635 unconditionally
We don't support "MAXIM_IMI_MCU_POWERED" cameras, whatever they are.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Read sensor ID after resetting it
Resetting the sensor first makes sure it will respond properly to the ID
read messages.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Add macros for MAX9271 register bits
The register addresses are left as hardcoded numbers as registers are
not named in the datasheet. Register bits, however, have a name, so
macros can be defined for them.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Disable the serial link at startup and stream off time
The serial link only needs to be enabled when streaming video. Disable
it at all other times.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Set I2C addresses of MAX9271 and OV10635 to unique values
Change the address of the MAX9271 and OV10635 from their boot time value
to unique values provided through DT to avoid address conflicts between
multiple channels of a MAX9286 or between multiple MAX9286. I2C address
translation isn't needed with that setup, so we don't configure it.
We have to remove the writes to the OV10635 address register from its
initialization array, otherwise it will be reset to the default address.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Log and react to all I2C communication errors
I2C communication error are bad enough to warrant error messages,
instead of disabled-by-default debug messages.
They also warrant stopping on the first write failure when writing the
sensor initial configuration instead of ignoring all errors.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Configure the MAX9271
Perform the MAX9271 configuration steps that are currently performed by
the max9286 driver.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: Remove duplicate device address from error messages
The device address is printed by dev_err() as part of the device name,
there's no need to duplicate it in the error message itself.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
v4l: rdacm20: increase delay after enabling control link
The datasheet states that you should wait more then 3ms for the control
link to become available after enabling it. This was discovered while
working with a problematic camera that sporadically failed to probed
with i2c write errors after the control link was enabled.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: rdacm20: read device id after configuration link is enabled
I'm not sure why but some cameras always fail to probe if the driver
tries to read the device ID before first writing to the 0x04 register. I
have no idea why this is, maybe the MCU dose something funny but that
seems unlikely. This should most likely be reverted once the true
problem is found, but for now keep it.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: rdacm20: add delay after changing i2c address
It's not documented in the datasheet but testing shows that
cameras who have a hard time reliably being probed, manage to probe much
more reliably if the driver is delayed by the same amount of time as
when enabling/disabling the control link when reprogramming an i2c
address.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: rdacm20: change i2c address of the max9271 as first step
Move the reprogramming of the max9271 slave address as the first step in
the initialize sequence. This more closely matches the programming guide
and it decreases the chances of failure when communicating with the
max9271.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: rdacm20: use GPIO to rest the OV10635
Software reset don't seem to do the trick. Switching to a hard reset by
toggling the GPIO pin of the max9271 get rids of lots of probe errors
where communication with the OV10635 fails after a short while.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: rdacm20: add delay after hard reset of the OV10635
Allow some time for the OV10635 to power on after toggling the GPIO ping
to reset the sensor. Without this fix there are lots of failures
communicating with the OV10635 shortly after it have been reset.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: rdacm20: add delay after configuring data mode and rate
According to the programming guide one should delay 2ms after changing
this register. Write failures have been observed after this write using
the cameras which needs auto-ack enabled on the MAX9286 to probe. Adding
the delay here fixes the write failure.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
v4l: i2c: rdacm20: Register subdevice on endpoint
v4l2-async framework assigns to subdevice's fwnode the fwnode associated
with device node when the subdevice is registered with fwnode field not
set.
As max9286 registered notifier expects to match the fwnode associated
with the remote endpoint, fix this by assigning the subdevice fwnode
with the endpoint of rdacm20 device node.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
rdacm20: do not sleep after starting the camera
There is no need to sleep here, the max9286 handles the synchronization
by waiting for FSYNC. Sleeping here will only delay to start of multiple
cameras.
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
media: i2c: rdacm20: Break MAX9271 configuration into functions
Split the rdacm20_initialize code that modifies the MAX9271 state into
smaller functions, to ease refactoring and allow clear visibility of
configuration orders.
This commit should be a non-configurational change - however it's not.
Please note this commit pulls the configuration of register 0x04 and
0x07 into a single function - and changes the sequence of programming.
The original code flow was: 0x00, 0x04, (r)0x1e, 0x08, 0x0d, 0x07
This new code flow is : 0x00, 0x04, 0x07, (r)0x1e, 0x08, 0x0d
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
This change is probably overkill - but it does / did help me get my head
around the ordering of the configuration - and makes it much easier to
add extra calls to read/verify the ID and try different configuration
orderings.
media: i2c: rdacm20: Increase configuration delays
The deserializer data sheet recommends delays of 5 ms. During testing,
occasional bit errors are seen after or around the writes for
configuration registers, including registers writes not making it across
the bus at all.
Increase the delays to the more conservative 5ms minimum, and also add a
delay which appeared to be missing after register write to 0x0d
configuring the I2C speed.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
media: i2c: rdacm20: Configure I2C and GMSL link before identifying device
Ensure that we make a full attempt at configuring both the GMSL link and
the I2C link before we try to read from the device.
This is vital in ensuring link stability and correct configuration to be
able to read the device ID correctly, and program the new device
address.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
rdacm20: Fix SPDX and copyrights
media: i2c: rdacm20: Detect PCLK before SEREN
Detect valid pixel clock signal from camera before enabling the
serializer serial link.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
media: i2c: gmsl: Use Cogent's settings
Use sensor settings from Cogent ov10635.h sensor driver.
Register values have been compared using a script tool that parses the
sensor configuration.
Notable changes:
* ov10635: Remove dead code
* ov10635: Do not hardcode sizes but use macros
* ov10635: Use falling edge pixel clock
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
media: i2c: rdacm20: Fix a compiler warning
Fix the following compiler warning:
../drivers/media/i2c/rdacm20.c:558:4 warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long int’ [-Wformat=]
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
rdacm20-ov10635: Hex to lower:
Perform the following operation on the ov10635 register tables:
sed -re 's/(0x[0-9a-fA-F]+)/\L\1/g'
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
rdacm20: GPL licence is 2.0+
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
media: i2c: rdacm20: Adjust color space and ycbcr_enc
Set colorspace description informations to correct values.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5879b76..a595174 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -908,6 +908,13 @@
This is a V4L2 sensor-level driver for Samsung S5C73M3
8 Mpixel camera.
+config VIDEO_RDACM20
+ tristate "IMI RDACM20 camera support"
+ depends on I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ help
+ This driver supports the IMI RDACM20 GMSL camera.
+
comment "Flash devices"
config VIDEO_ADP1653
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 9142204..0cf4cd7 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -104,5 +104,6 @@
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
+obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o
diff --git a/drivers/media/i2c/rdacm20-ov10635.h b/drivers/media/i2c/rdacm20-ov10635.h
new file mode 100644
index 0000000..8819946e
--- /dev/null
+++ b/drivers/media/i2c/rdacm20-ov10635.h
@@ -0,0 +1,952 @@
+/*
+ * IMI RDACM20 camera OV10635 sensor registers initialization values
+ *
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Generated by the OmniVision ov10635 sensor camera wizard for
+ * 1280x800@30/UYVY/BT601/8bit.
+ */
+
+#ifndef __RDACM20_OV10635_H__
+#define __RDACM20_OV10635_H__
+
+#define OV10635_SENSOR_WIDTH 1312
+#define OV10635_SENSOR_HEIGHT 814
+
+#define OV10635_MAX_WIDTH 1280
+#define OV10635_MAX_HEIGHT 800
+
+/* VTS = PCLK / FPS / HTS / 2 (= 88MHz / 1572 / 30 / 2) */
+#define OV10635_HTS 1572
+/* FPS = 29,9998 */
+#define OV10635_VTS 933
+
+struct ov10635_reg {
+ u16 reg;
+ u8 val;
+};
+
+static const struct ov10635_reg ov10635_regs_wizard[] = {
+ { 0x301b, 0xff },
+ { 0x301c, 0xff },
+ { 0x301a, 0xff },
+ { 0x3011, 0x42 },
+ { 0x6900, 0x0c },
+ { 0x6901, 0x19 },
+ { 0x3503, 0x10 },
+ { 0x3025, 0x03 },
+ { 0x3003, 0x16 },
+ { 0x3004, 0x30 },
+ { 0x3005, 0x40 },
+ { 0x3006, 0x91 },
+ { 0x3600, 0x74 },
+ { 0x3601, 0x2b },
+ { 0x3612, 0x00 },
+ { 0x3611, 0x67 },
+ { 0x3633, 0xca },
+ { 0x3602, 0xaf },
+ { 0x3603, 0x04 },
+ { 0x3630, 0x28 },
+ { 0x3631, 0x16 },
+ { 0x3714, 0x10 },
+ { 0x371d, 0x01 },
+ { 0x4300, 0x3a },
+ { 0x3007, 0x01 },
+ { 0x3024, 0x03 },
+ { 0x3020, 0x0a },
+ { 0x3702, 0x0d },
+ { 0x3703, 0x20 },
+ { 0x3704, 0x15 },
+ { 0x3709, 0xa8 },
+ { 0x370c, 0xc7 },
+ { 0x370d, 0x80 },
+ { 0x3712, 0x00 },
+ { 0x3713, 0x20 },
+ { 0x3715, 0x04 },
+ { 0x381d, 0x40 },
+ { 0x381c, 0x00 },
+ { 0x3822, 0x50 },
+ { 0x3824, 0x10 },
+ { 0x3815, 0x8c },
+ { 0x3804, 0x05 },
+ { 0x3805, 0x1f },
+ { 0x3800, 0x00 },
+ { 0x3801, 0x00 },
+ { 0x3806, 0x03 },
+ { 0x3807, 0x28 },
+ { 0x3802, 0x00 },
+ { 0x3803, 0x07 },
+ { 0x3808, 0x05 },
+ { 0x3809, 0x00 },
+ { 0x380a, 0x03 },
+ { 0x380b, 0x20 },
+ { 0x380c, OV10635_HTS >> 8 },
+ { 0x380d, OV10635_HTS & 0xff },
+ { 0x380e, OV10635_VTS >> 8 },
+ { 0x380f, OV10635_VTS & 0xff },
+ { 0x3813, 0x02 },
+ { 0x3811, 0x08 },
+ { 0x381f, 0x0c },
+ { 0x3819, 0x04 },
+ { 0x3804, 0x01 },
+ { 0x3805, 0x00 },
+ { 0x3828, 0x03 },
+ { 0x3829, 0x10 },
+ { 0x382a, 0x10 },
+ { 0x3621, 0x63 },
+ { 0x5005, 0x08 },
+ { 0x56d5, 0x00 },
+ { 0x56d6, 0x80 },
+ { 0x56d7, 0x00 },
+ { 0x56d8, 0x00 },
+ { 0x56d9, 0x00 },
+ { 0x56da, 0x80 },
+ { 0x56db, 0x00 },
+ { 0x56dc, 0x00 },
+ { 0x56e8, 0x00 },
+ { 0x56e9, 0x7f },
+ { 0x56ea, 0x00 },
+ { 0x56eb, 0x7f },
+ { 0x5100, 0x00 },
+ { 0x5101, 0x80 },
+ { 0x5102, 0x00 },
+ { 0x5103, 0x80 },
+ { 0x5104, 0x00 },
+ { 0x5105, 0x80 },
+ { 0x5106, 0x00 },
+ { 0x5107, 0x80 },
+ { 0x5108, 0x00 },
+ { 0x5109, 0x00 },
+ { 0x510a, 0x00 },
+ { 0x510b, 0x00 },
+ { 0x510c, 0x00 },
+ { 0x510d, 0x00 },
+ { 0x510e, 0x00 },
+ { 0x510f, 0x00 },
+ { 0x5110, 0x00 },
+ { 0x5111, 0x80 },
+ { 0x5112, 0x00 },
+ { 0x5113, 0x80 },
+ { 0x5114, 0x00 },
+ { 0x5115, 0x80 },
+ { 0x5116, 0x00 },
+ { 0x5117, 0x80 },
+ { 0x5118, 0x00 },
+ { 0x5119, 0x00 },
+ { 0x511a, 0x00 },
+ { 0x511b, 0x00 },
+ { 0x511c, 0x00 },
+ { 0x511d, 0x00 },
+ { 0x511e, 0x00 },
+ { 0x511f, 0x00 },
+ { 0x56d0, 0x00 },
+ { 0x5006, 0x04 },
+ { 0x5608, 0x05 },
+ { 0x52d7, 0x06 },
+ { 0x528d, 0x08 },
+ { 0x5293, 0x12 },
+ { 0x52d3, 0x12 },
+ { 0x5288, 0x06 },
+ { 0x5289, 0x20 },
+ { 0x52c8, 0x06 },
+ { 0x52c9, 0x20 },
+ { 0x52cd, 0x04 },
+ { 0x5381, 0x00 },
+ { 0x5382, 0xff },
+ { 0x5589, 0x76 },
+ { 0x558a, 0x47 },
+ { 0x558b, 0xef },
+ { 0x558c, 0xc9 },
+ { 0x558d, 0x49 },
+ { 0x558e, 0x30 },
+ { 0x558f, 0x67 },
+ { 0x5590, 0x3f },
+ { 0x5591, 0xf0 },
+ { 0x5592, 0x10 },
+ { 0x55a2, 0x6d },
+ { 0x55a3, 0x55 },
+ { 0x55a4, 0xc3 },
+ { 0x55a5, 0xb5 },
+ { 0x55a6, 0x43 },
+ { 0x55a7, 0x38 },
+ { 0x55a8, 0x5f },
+ { 0x55a9, 0x4b },
+ { 0x55aa, 0xf0 },
+ { 0x55ab, 0x10 },
+ { 0x5581, 0x52 },
+ { 0x5300, 0x01 },
+ { 0x5301, 0x00 },
+ { 0x5302, 0x00 },
+ { 0x5303, 0x0e },
+ { 0x5304, 0x00 },
+ { 0x5305, 0x0e },
+ { 0x5306, 0x00 },
+ { 0x5307, 0x36 },
+ { 0x5308, 0x00 },
+ { 0x5309, 0xd9 },
+ { 0x530a, 0x00 },
+ { 0x530b, 0x0f },
+ { 0x530c, 0x00 },
+ { 0x530d, 0x2c },
+ { 0x530e, 0x00 },
+ { 0x530f, 0x59 },
+ { 0x5310, 0x00 },
+ { 0x5311, 0x7b },
+ { 0x5312, 0x00 },
+ { 0x5313, 0x22 },
+ { 0x5314, 0x00 },
+ { 0x5315, 0xd5 },
+ { 0x5316, 0x00 },
+ { 0x5317, 0x13 },
+ { 0x5318, 0x00 },
+ { 0x5319, 0x18 },
+ { 0x531a, 0x00 },
+ { 0x531b, 0x26 },
+ { 0x531c, 0x00 },
+ { 0x531d, 0xdc },
+ { 0x531e, 0x00 },
+ { 0x531f, 0x02 },
+ { 0x5320, 0x00 },
+ { 0x5321, 0x24 },
+ { 0x5322, 0x00 },
+ { 0x5323, 0x56 },
+ { 0x5324, 0x00 },
+ { 0x5325, 0x85 },
+ { 0x5326, 0x00 },
+ { 0x5327, 0x20 },
+ { 0x5609, 0x01 },
+ { 0x560a, 0x40 },
+ { 0x560b, 0x01 },
+ { 0x560c, 0x40 },
+ { 0x560d, 0x00 },
+ { 0x560e, 0xfa },
+ { 0x560f, 0x00 },
+ { 0x5610, 0xfa },
+ { 0x5611, 0x02 },
+ { 0x5612, 0x80 },
+ { 0x5613, 0x02 },
+ { 0x5614, 0x80 },
+ { 0x5615, 0x01 },
+ { 0x5616, 0x2c },
+ { 0x5617, 0x01 },
+ { 0x5618, 0x2c },
+ { 0x563b, 0x01 },
+ { 0x563c, 0x01 },
+ { 0x563d, 0x01 },
+ { 0x563e, 0x01 },
+ { 0x563f, 0x03 },
+ { 0x5640, 0x03 },
+ { 0x5641, 0x03 },
+ { 0x5642, 0x05 },
+ { 0x5643, 0x09 },
+ { 0x5644, 0x05 },
+ { 0x5645, 0x05 },
+ { 0x5646, 0x05 },
+ { 0x5647, 0x05 },
+ { 0x5651, 0x00 },
+ { 0x5652, 0x80 },
+ { 0x521a, 0x01 },
+ { 0x521b, 0x03 },
+ { 0x521c, 0x06 },
+ { 0x521d, 0x0a },
+ { 0x521e, 0x0e },
+ { 0x521f, 0x12 },
+ { 0x5220, 0x16 },
+ { 0x5223, 0x02 },
+ { 0x5225, 0x04 },
+ { 0x5227, 0x08 },
+ { 0x5229, 0x0c },
+ { 0x522b, 0x12 },
+ { 0x522d, 0x18 },
+ { 0x522f, 0x1e },
+ { 0x5241, 0x04 },
+ { 0x5242, 0x01 },
+ { 0x5243, 0x03 },
+ { 0x5244, 0x06 },
+ { 0x5245, 0x0a },
+ { 0x5246, 0x0e },
+ { 0x5247, 0x12 },
+ { 0x5248, 0x16 },
+ { 0x524a, 0x03 },
+ { 0x524c, 0x04 },
+ { 0x524e, 0x08 },
+ { 0x5250, 0x0c },
+ { 0x5252, 0x12 },
+ { 0x5254, 0x18 },
+ { 0x5256, 0x1e },
+ /* fifo_line_length = 2*hts */
+ { 0x4606, (2 * OV10635_HTS) >> 8 },
+ { 0x4607, (2 * OV10635_HTS) & 0xff },
+ /* fifo_hsync_start = 2*(hts - xres) */
+ { 0x460a, (2 * (OV10635_HTS - OV10635_MAX_WIDTH)) >> 8 },
+ { 0x460b, (2 * (OV10635_HTS - OV10635_MAX_WIDTH)) & 0xff },
+ { 0x460c, 0x00 },
+ { 0x4620, 0x0e },
+ /* BT601: 0x08 is also acceptable as HS/VS mode */
+ { 0x4700, 0x04 },
+ { 0x4701, 0x00 },
+ { 0x4702, 0x01 },
+ { 0x4004, 0x04 },
+ { 0x4005, 0x18 },
+ { 0x4001, 0x06 },
+ { 0x4050, 0x22 },
+ { 0x4051, 0x24 },
+ { 0x4052, 0x02 },
+ { 0x4057, 0x9c },
+ { 0x405a, 0x00 },
+ { 0x4202, 0x02 },
+ { 0x3023, 0x10 },
+ { 0x0100, 0x01 },
+ { 0x0100, 0x01 },
+ { 0x6f10, 0x07 },
+ { 0x6f11, 0x82 },
+ { 0x6f12, 0x04 },
+ { 0x6f13, 0x00 },
+ { 0xd000, 0x19 },
+ { 0xd001, 0xa0 },
+ { 0xd002, 0x00 },
+ { 0xd003, 0x01 },
+ { 0xd004, 0xa9 },
+ { 0xd005, 0xad },
+ { 0xd006, 0x10 },
+ { 0xd007, 0x40 },
+ { 0xd008, 0x44 },
+ { 0xd009, 0x00 },
+ { 0xd00a, 0x68 },
+ { 0xd00b, 0x00 },
+ { 0xd00c, 0x15 },
+ { 0xd00d, 0x00 },
+ { 0xd00e, 0x00 },
+ { 0xd00f, 0x00 },
+ { 0xd040, 0x9c },
+ { 0xd041, 0x21 },
+ { 0xd042, 0xff },
+ { 0xd043, 0xf8 },
+ { 0xd044, 0xd4 },
+ { 0xd045, 0x01 },
+ { 0xd046, 0x48 },
+ { 0xd047, 0x00 },
+ { 0xd048, 0xd4 },
+ { 0xd049, 0x01 },
+ { 0xd04a, 0x50 },
+ { 0xd04b, 0x04 },
+ { 0xd04c, 0x18 },
+ { 0xd04d, 0x60 },
+ { 0xd04e, 0x00 },
+ { 0xd04f, 0x01 },
+ { 0xd050, 0xa8 },
+ { 0xd051, 0x63 },
+ { 0xd052, 0x02 },
+ { 0xd053, 0xa4 },
+ { 0xd054, 0x85 },
+ { 0xd055, 0x43 },
+ { 0xd056, 0x00 },
+ { 0xd057, 0x00 },
+ { 0xd058, 0x18 },
+ { 0xd059, 0x60 },
+ { 0xd05a, 0x00 },
+ { 0xd05b, 0x01 },
+ { 0xd05c, 0xa8 },
+ { 0xd05d, 0x63 },
+ { 0xd05e, 0x03 },
+ { 0xd05f, 0xf0 },
+ { 0xd060, 0x98 },
+ { 0xd061, 0xa3 },
+ { 0xd062, 0x00 },
+ { 0xd063, 0x00 },
+ { 0xd064, 0x8c },
+ { 0xd065, 0x6a },
+ { 0xd066, 0x00 },
+ { 0xd067, 0x6e },
+ { 0xd068, 0xe5 },
+ { 0xd069, 0x85 },
+ { 0xd06a, 0x18 },
+ { 0xd06b, 0x00 },
+ { 0xd06c, 0x10 },
+ { 0xd06d, 0x00 },
+ { 0xd06e, 0x00 },
+ { 0xd06f, 0x10 },
+ { 0xd070, 0x9c },
+ { 0xd071, 0x80 },
+ { 0xd072, 0x00 },
+ { 0xd073, 0x03 },
+ { 0xd074, 0x18 },
+ { 0xd075, 0x60 },
+ { 0xd076, 0x00 },
+ { 0xd077, 0x01 },
+ { 0xd078, 0xa8 },
+ { 0xd079, 0x63 },
+ { 0xd07a, 0x07 },
+ { 0xd07b, 0x80 },
+ { 0xd07c, 0x07 },
+ { 0xd07d, 0xff },
+ { 0xd07e, 0xf9 },
+ { 0xd07f, 0x03 },
+ { 0xd080, 0x8c },
+ { 0xd081, 0x63 },
+ { 0xd082, 0x00 },
+ { 0xd083, 0x00 },
+ { 0xd084, 0xa5 },
+ { 0xd085, 0x6b },
+ { 0xd086, 0x00 },
+ { 0xd087, 0xff },
+ { 0xd088, 0x18 },
+ { 0xd089, 0x80 },
+ { 0xd08a, 0x00 },
+ { 0xd08b, 0x01 },
+ { 0xd08c, 0xa8 },
+ { 0xd08d, 0x84 },
+ { 0xd08e, 0x01 },
+ { 0xd08f, 0x04 },
+ { 0xd090, 0xe1 },
+ { 0xd091, 0x6b },
+ { 0xd092, 0x58 },
+ { 0xd093, 0x00 },
+ { 0xd094, 0x94 },
+ { 0xd095, 0x6a },
+ { 0xd096, 0x00 },
+ { 0xd097, 0x70 },
+ { 0xd098, 0xe1 },
+ { 0xd099, 0x6b },
+ { 0xd09a, 0x20 },
+ { 0xd09b, 0x00 },
+ { 0xd09c, 0x95 },
+ { 0xd09d, 0x6b },
+ { 0xd09e, 0x00 },
+ { 0xd09f, 0x00 },
+ { 0xd0a0, 0xe4 },
+ { 0xd0a1, 0x8b },
+ { 0xd0a2, 0x18 },
+ { 0xd0a3, 0x00 },
+ { 0xd0a4, 0x0c },
+ { 0xd0a5, 0x00 },
+ { 0xd0a6, 0x00 },
+ { 0xd0a7, 0x23 },
+ { 0xd0a8, 0x15 },
+ { 0xd0a9, 0x00 },
+ { 0xd0aa, 0x00 },
+ { 0xd0ab, 0x00 },
+ { 0xd0ac, 0x18 },
+ { 0xd0ad, 0x60 },
+ { 0xd0ae, 0x80 },
+ { 0xd0af, 0x06 },
+ { 0xd0b0, 0xa8 },
+ { 0xd0b1, 0x83 },
+ { 0xd0b2, 0x40 },
+ { 0xd0b3, 0x08 },
+ { 0xd0b4, 0xa8 },
+ { 0xd0b5, 0xe3 },
+ { 0xd0b6, 0x38 },
+ { 0xd0b7, 0x2a },
+ { 0xd0b8, 0xa8 },
+ { 0xd0b9, 0xc3 },
+ { 0xd0ba, 0x40 },
+ { 0xd0bb, 0x09 },
+ { 0xd0bc, 0xa8 },
+ { 0xd0bd, 0xa3 },
+ { 0xd0be, 0x38 },
+ { 0xd0bf, 0x29 },
+ { 0xd0c0, 0x8c },
+ { 0xd0c1, 0x65 },
+ { 0xd0c2, 0x00 },
+ { 0xd0c3, 0x00 },
+ { 0xd0c4, 0xd8 },
+ { 0xd0c5, 0x04 },
+ { 0xd0c6, 0x18 },
+ { 0xd0c7, 0x00 },
+ { 0xd0c8, 0x8c },
+ { 0xd0c9, 0x67 },
+ { 0xd0ca, 0x00 },
+ { 0xd0cb, 0x00 },
+ { 0xd0cc, 0xd8 },
+ { 0xd0cd, 0x06 },
+ { 0xd0ce, 0x18 },
+ { 0xd0cf, 0x00 },
+ { 0xd0d0, 0x18 },
+ { 0xd0d1, 0x60 },
+ { 0xd0d2, 0x80 },
+ { 0xd0d3, 0x06 },
+ { 0xd0d4, 0xa8 },
+ { 0xd0d5, 0xe3 },
+ { 0xd0d6, 0x67 },
+ { 0xd0d7, 0x02 },
+ { 0xd0d8, 0xa9 },
+ { 0xd0d9, 0x03 },
+ { 0xd0da, 0x67 },
+ { 0xd0db, 0x03 },
+ { 0xd0dc, 0xa8 },
+ { 0xd0dd, 0xc3 },
+ { 0xd0de, 0x3d },
+ { 0xd0df, 0x05 },
+ { 0xd0e0, 0x8c },
+ { 0xd0e1, 0x66 },
+ { 0xd0e2, 0x00 },
+ { 0xd0e3, 0x00 },
+ { 0xd0e4, 0xb8 },
+ { 0xd0e5, 0x63 },
+ { 0xd0e6, 0x00 },
+ { 0xd0e7, 0x18 },
+ { 0xd0e8, 0xb8 },
+ { 0xd0e9, 0x63 },
+ { 0xd0ea, 0x00 },
+ { 0xd0eb, 0x98 },
+ { 0xd0ec, 0xbc },
+ { 0xd0ed, 0x03 },
+ { 0xd0ee, 0x00 },
+ { 0xd0ef, 0x00 },
+ { 0xd0f0, 0x10 },
+ { 0xd0f1, 0x00 },
+ { 0xd0f2, 0x00 },
+ { 0xd0f3, 0x16 },
+ { 0xd0f4, 0xb8 },
+ { 0xd0f5, 0x83 },
+ { 0xd0f6, 0x00 },
+ { 0xd0f7, 0x19 },
+ { 0xd0f8, 0x8c },
+ { 0xd0f9, 0x67 },
+ { 0xd0fa, 0x00 },
+ { 0xd0fb, 0x00 },
+ { 0xd0fc, 0xb8 },
+ { 0xd0fd, 0xa4 },
+ { 0xd0fe, 0x00 },
+ { 0xd0ff, 0x98 },
+ { 0xd100, 0xb8 },
+ { 0xd101, 0x83 },
+ { 0xd102, 0x00 },
+ { 0xd103, 0x08 },
+ { 0xd104, 0x8c },
+ { 0xd105, 0x68 },
+ { 0xd106, 0x00 },
+ { 0xd107, 0x00 },
+ { 0xd108, 0xe0 },
+ { 0xd109, 0x63 },
+ { 0xd10a, 0x20 },
+ { 0xd10b, 0x04 },
+ { 0xd10c, 0xe0 },
+ { 0xd10d, 0x65 },
+ { 0xd10e, 0x18 },
+ { 0xd10f, 0x00 },
+ { 0xd110, 0xa4 },
+ { 0xd111, 0x83 },
+ { 0xd112, 0xff },
+ { 0xd113, 0xff },
+ { 0xd114, 0xb8 },
+ { 0xd115, 0x64 },
+ { 0xd116, 0x00 },
+ { 0xd117, 0x48 },
+ { 0xd118, 0xd8 },
+ { 0xd119, 0x07 },
+ { 0xd11a, 0x18 },
+ { 0xd11b, 0x00 },
+ { 0xd11c, 0xd8 },
+ { 0xd11d, 0x08 },
+ { 0xd11e, 0x20 },
+ { 0xd11f, 0x00 },
+ { 0xd120, 0x9c },
+ { 0xd121, 0x60 },
+ { 0xd122, 0x00 },
+ { 0xd123, 0x00 },
+ { 0xd124, 0xd8 },
+ { 0xd125, 0x06 },
+ { 0xd126, 0x18 },
+ { 0xd127, 0x00 },
+ { 0xd128, 0x00 },
+ { 0xd129, 0x00 },
+ { 0xd12a, 0x00 },
+ { 0xd12b, 0x08 },
+ { 0xd12c, 0x15 },
+ { 0xd12d, 0x00 },
+ { 0xd12e, 0x00 },
+ { 0xd12f, 0x00 },
+ { 0xd130, 0x8c },
+ { 0xd131, 0x6a },
+ { 0xd132, 0x00 },
+ { 0xd133, 0x76 },
+ { 0xd134, 0xbc },
+ { 0xd135, 0x23 },
+ { 0xd136, 0x00 },
+ { 0xd137, 0x00 },
+ { 0xd138, 0x13 },
+ { 0xd139, 0xff },
+ { 0xd13a, 0xff },
+ { 0xd13b, 0xe6 },
+ { 0xd13c, 0x18 },
+ { 0xd13d, 0x60 },
+ { 0xd13e, 0x80 },
+ { 0xd13f, 0x06 },
+ { 0xd140, 0x03 },
+ { 0xd141, 0xff },
+ { 0xd142, 0xff },
+ { 0xd143, 0xdd },
+ { 0xd144, 0xa8 },
+ { 0xd145, 0x83 },
+ { 0xd146, 0x40 },
+ { 0xd147, 0x08 },
+ { 0xd148, 0x85 },
+ { 0xd149, 0x21 },
+ { 0xd14a, 0x00 },
+ { 0xd14b, 0x00 },
+ { 0xd14c, 0x85 },
+ { 0xd14d, 0x41 },
+ { 0xd14e, 0x00 },
+ { 0xd14f, 0x04 },
+ { 0xd150, 0x44 },
+ { 0xd151, 0x00 },
+ { 0xd152, 0x48 },
+ { 0xd153, 0x00 },
+ { 0xd154, 0x9c },
+ { 0xd155, 0x21 },
+ { 0xd156, 0x00 },
+ { 0xd157, 0x08 },
+ { 0x6f0e, 0x03 },
+ { 0x6f0f, 0x00 },
+ { 0x460e, 0x08 },
+ { 0x460f, 0x01 },
+ { 0x4610, 0x00 },
+ { 0x4611, 0x01 },
+ { 0x4612, 0x00 },
+ { 0x4613, 0x01 },
+ /* 8 bits */
+ { 0x4605, 0x08 },
+ /* Swap data bits order [9:0] -> [0:9] */
+ { 0x4709, 0x10 },
+ { 0x4608, 0x00 },
+ { 0x4609, 0x08 },
+ { 0x6804, 0x00 },
+ { 0x6805, 0x06 },
+ { 0x6806, 0x00 },
+ { 0x5120, 0x00 },
+ { 0x3510, 0x00 },
+ { 0x3504, 0x00 },
+ { 0x6800, 0x00 },
+ { 0x6f0d, 0x01 },
+ /* PCLK falling edge */
+ { 0x4708, 0x01 },
+ { 0x5000, 0xff },
+ { 0x5001, 0xbf },
+ { 0x5002, 0x7e },
+ { 0x503d, 0x00 },
+ { 0xc450, 0x01 },
+ { 0xc452, 0x04 },
+ { 0xc453, 0x00 },
+ { 0xc454, 0x00 },
+ { 0xc455, 0x01 },
+ { 0xc456, 0x01 },
+ { 0xc457, 0x00 },
+ { 0xc458, 0x00 },
+ { 0xc459, 0x00 },
+ { 0xc45b, 0x00 },
+ { 0xc45c, 0x01 },
+ { 0xc45d, 0x00 },
+ { 0xc45e, 0x00 },
+ { 0xc45f, 0x00 },
+ { 0xc460, 0x00 },
+ { 0xc461, 0x01 },
+ { 0xc462, 0x01 },
+ { 0xc464, 0x03 },
+ { 0xc465, 0x00 },
+ { 0xc466, 0x8a },
+ { 0xc467, 0x00 },
+ { 0xc468, 0x86 },
+ { 0xc469, 0x00 },
+ { 0xc46a, 0x40 },
+ { 0xc46b, 0x50 },
+ { 0xc46c, 0x30 },
+ { 0xc46d, 0x28 },
+ { 0xc46e, 0x60 },
+ { 0xc46f, 0x40 },
+ { 0xc47c, 0x01 },
+ { 0xc47d, 0x38 },
+ { 0xc47e, 0x00 },
+ { 0xc47f, 0x00 },
+ { 0xc480, 0x00 },
+ { 0xc481, 0xff },
+ { 0xc482, 0x00 },
+ { 0xc483, 0x40 },
+ { 0xc484, 0x00 },
+ { 0xc485, 0x18 },
+ { 0xc486, 0x00 },
+ { 0xc487, 0x18 },
+ { 0xc488, (OV10635_VTS - 8) * 16 >> 8},
+ { 0xc489, (OV10635_VTS - 8) * 16 & 0xff},
+ { 0xc48a, (OV10635_VTS - 8) * 16 >> 8},
+ { 0xc48b, (OV10635_VTS - 8) * 16 & 0xff},
+ { 0xc48c, 0x00 },
+ { 0xc48d, 0x04 },
+ { 0xc48e, 0x00 },
+ { 0xc48f, 0x04 },
+ { 0xc490, 0x03 },
+ { 0xc492, 0x20 },
+ { 0xc493, 0x08 },
+ { 0xc498, 0x02 },
+ { 0xc499, 0x00 },
+ { 0xc49a, 0x02 },
+ { 0xc49b, 0x00 },
+ { 0xc49c, 0x02 },
+ { 0xc49d, 0x00 },
+ { 0xc49e, 0x02 },
+ { 0xc49f, 0x60 },
+ { 0xc4a0, 0x03 },
+ { 0xc4a1, 0x00 },
+ { 0xc4a2, 0x04 },
+ { 0xc4a3, 0x00 },
+ { 0xc4a4, 0x00 },
+ { 0xc4a5, 0x10 },
+ { 0xc4a6, 0x00 },
+ { 0xc4a7, 0x40 },
+ { 0xc4a8, 0x00 },
+ { 0xc4a9, 0x80 },
+ { 0xc4aa, 0x0d },
+ { 0xc4ab, 0x00 },
+ { 0xc4ac, 0x0f },
+ { 0xc4ad, 0xc0 },
+ { 0xc4b4, 0x01 },
+ { 0xc4b5, 0x01 },
+ { 0xc4b6, 0x00 },
+ { 0xc4b7, 0x01 },
+ { 0xc4b8, 0x00 },
+ { 0xc4b9, 0x01 },
+ { 0xc4ba, 0x01 },
+ { 0xc4bb, 0x00 },
+ { 0xc4bc, 0x01 },
+ { 0xc4bd, 0x60 },
+ { 0xc4be, 0x02 },
+ { 0xc4bf, 0x33 },
+ { 0xc4c8, 0x03 },
+ { 0xc4c9, 0xd0 },
+ { 0xc4ca, 0x0e },
+ { 0xc4cb, 0x00 },
+ { 0xc4cc, 0x0e },
+ { 0xc4cd, 0x51 },
+ { 0xc4ce, 0x0e },
+ { 0xc4cf, 0x51 },
+ { 0xc4d0, 0x04 },
+ { 0xc4d1, 0x80 },
+ { 0xc4e0, 0x04 },
+ { 0xc4e1, 0x02 },
+ { 0xc4e2, 0x01 },
+ { 0xc4e4, 0x10 },
+ { 0xc4e5, 0x20 },
+ { 0xc4e6, 0x30 },
+ { 0xc4e7, 0x40 },
+ { 0xc4e8, 0x50 },
+ { 0xc4e9, 0x60 },
+ { 0xc4ea, 0x70 },
+ { 0xc4eb, 0x80 },
+ { 0xc4ec, 0x90 },
+ { 0xc4ed, 0xa0 },
+ { 0xc4ee, 0xb0 },
+ { 0xc4ef, 0xc0 },
+ { 0xc4f0, 0xd0 },
+ { 0xc4f1, 0xe0 },
+ { 0xc4f2, 0xf0 },
+ { 0xc4f3, 0x80 },
+ { 0xc4f4, 0x00 },
+ { 0xc4f5, 0x20 },
+ { 0xc4f6, 0x02 },
+ { 0xc4f7, 0x00 },
+ { 0xc4f8, 0x00 },
+ { 0xc4f9, 0x00 },
+ { 0xc4fa, 0x00 },
+ { 0xc4fb, 0x01 },
+ { 0xc4fc, 0x01 },
+ { 0xc4fd, 0x00 },
+ { 0xc4fe, 0x04 },
+ { 0xc4ff, 0x02 },
+ { 0xc500, 0x48 },
+ { 0xc501, 0x74 },
+ { 0xc502, 0x58 },
+ { 0xc503, 0x80 },
+ { 0xc504, 0x05 },
+ { 0xc505, 0x80 },
+ { 0xc506, 0x03 },
+ { 0xc507, 0x80 },
+ { 0xc508, 0x01 },
+ { 0xc509, 0xc0 },
+ { 0xc50a, 0x01 },
+ { 0xc50b, 0xa0 },
+ { 0xc50c, 0x01 },
+ { 0xc50d, 0x2c },
+ { 0xc50e, 0x01 },
+ { 0xc50f, 0x0a },
+ { 0xc510, 0x00 },
+ { 0xc511, 0x00 },
+ { 0xc512, 0xe5 },
+ { 0xc513, 0x14 },
+ { 0xc514, 0x04 },
+ { 0xc515, 0x00 },
+ { 0xc518, OV10635_VTS >> 8},
+ { 0xc519, OV10635_VTS & 0xff},
+ { 0xc51a, OV10635_HTS >> 8},
+ { 0xc51b, OV10635_HTS & 0xff},
+ { 0xc2e0, 0x00 },
+ { 0xc2e1, 0x51 },
+ { 0xc2e2, 0x00 },
+ { 0xc2e3, 0xd6 },
+ { 0xc2e4, 0x01 },
+ { 0xc2e5, 0x5e },
+ { 0xc2e9, 0x01 },
+ { 0xc2ea, 0x7a },
+ { 0xc2eb, 0x90 },
+ { 0xc2ed, 0x00 },
+ { 0xc2ee, 0x7a },
+ { 0xc2ef, 0x64 },
+ { 0xc308, 0x00 },
+ { 0xc309, 0x00 },
+ { 0xc30a, 0x00 },
+ { 0xc30c, 0x00 },
+ { 0xc30d, 0x01 },
+ { 0xc30e, 0x00 },
+ { 0xc30f, 0x00 },
+ { 0xc310, 0x01 },
+ { 0xc311, 0x60 },
+ { 0xc312, 0xff },
+ { 0xc313, 0x08 },
+ { 0xc314, 0x01 },
+ { 0xc315, 0x00 },
+ { 0xc316, 0xff },
+ { 0xc317, 0x0b },
+ { 0xc318, 0x00 },
+ { 0xc319, 0x0c },
+ { 0xc31a, 0x00 },
+ { 0xc31b, 0xe0 },
+ { 0xc31c, 0x00 },
+ { 0xc31d, 0x14 },
+ { 0xc31e, 0x00 },
+ { 0xc31f, 0xc5 },
+ { 0xc320, 0xff },
+ { 0xc321, 0x4b },
+ { 0xc322, 0xff },
+ { 0xc323, 0xf0 },
+ { 0xc324, 0xff },
+ { 0xc325, 0xe8 },
+ { 0xc326, 0x00 },
+ { 0xc327, 0x46 },
+ { 0xc328, 0xff },
+ { 0xc329, 0xd2 },
+ { 0xc32a, 0xff },
+ { 0xc32b, 0xe4 },
+ { 0xc32c, 0xff },
+ { 0xc32d, 0xbb },
+ { 0xc32e, 0x00 },
+ { 0xc32f, 0x61 },
+ { 0xc330, 0xff },
+ { 0xc331, 0xf9 },
+ { 0xc332, 0x00 },
+ { 0xc333, 0xd9 },
+ { 0xc334, 0x00 },
+ { 0xc335, 0x2e },
+ { 0xc336, 0x00 },
+ { 0xc337, 0xb1 },
+ { 0xc338, 0xff },
+ { 0xc339, 0x64 },
+ { 0xc33a, 0xff },
+ { 0xc33b, 0xeb },
+ { 0xc33c, 0xff },
+ { 0xc33d, 0xe8 },
+ { 0xc33e, 0x00 },
+ { 0xc33f, 0x48 },
+ { 0xc340, 0xff },
+ { 0xc341, 0xd0 },
+ { 0xc342, 0xff },
+ { 0xc343, 0xed },
+ { 0xc344, 0xff },
+ { 0xc345, 0xad },
+ { 0xc346, 0x00 },
+ { 0xc347, 0x66 },
+ { 0xc348, 0x01 },
+ { 0xc349, 0x00 },
+ { 0x6700, 0x04 },
+ { 0x6701, 0x7b },
+ { 0x6702, 0xfd },
+ { 0x6703, 0xf9 },
+ { 0x6704, 0x3d },
+ { 0x6705, 0x71 },
+ { 0x6706, 0x78 },
+ { 0x6708, 0x05 },
+ { 0x6f06, 0x6f },
+ { 0x6f07, 0x00 },
+ { 0x6f0a, 0x6f },
+ { 0x6f0b, 0x00 },
+ { 0x6f00, 0x03 },
+ { 0xc34c, 0x01 },
+ { 0xc34d, 0x00 },
+ { 0xc34e, 0x46 },
+ { 0xc34f, 0x55 },
+ { 0xc350, 0x00 },
+ { 0xc351, 0x40 },
+ { 0xc352, 0x00 },
+ { 0xc353, 0xff },
+ { 0xc354, 0x04 },
+ { 0xc355, 0x08 },
+ { 0xc356, 0x01 },
+ { 0xc357, 0xef },
+ { 0xc358, 0x30 },
+ { 0xc359, 0x01 },
+ { 0xc35a, 0x64 },
+ { 0xc35b, 0x46 },
+ { 0xc35c, 0x00 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0x3042, 0xf0 },
+ { 0xc261, 0x01 },
+ { 0x301b, 0xf0 },
+ { 0x301c, 0xf0 },
+ { 0x301a, 0xf0 },
+ { 0x6f00, 0xc3 },
+ { 0xc46a, 0x30 },
+ { 0xc46d, 0x20 },
+ { 0xc464, 0x84 },
+ { 0xc465, 0x00 },
+ { 0x6f00, 0x03 },
+ { 0x6f00, 0x43 },
+ { 0x381c, 0x00 },
+ { 0x381d, 0x40 },
+ { 0xc454, 0x01 },
+ { 0x6f00, 0xc3 },
+ { 0xc454, 0x00 },
+ { 0xc4b1, 0x02 },
+ { 0xc4b2, 0x01 },
+ { 0xc4b3, 0x03 },
+ { 0x6f00, 0x03 },
+ { 0x6f00, 0x43 },
+ /* enable FSIN (FRAMESYNC input) functionality */
+ { 0x3832, (0x0d + 2 * 0x20 + 0x15 + 38) >> 8 },
+ { 0x3833, (0x0d + 2 * 0x20 + 0x15 + 38) & 0xff },
+ { 0x3834, OV10635_VTS >> 8 },
+ { 0x3835, OV10635_VTS & 0xff },
+ { 0x302e, 0x01 },
+};
+
+#endif /* __RDACM20_OV10635_H__ */
diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c
new file mode 100644
index 0000000..352c549
--- /dev/null
+++ b/drivers/media/i2c/rdacm20.c
@@ -0,0 +1,635 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IMI RDACM20 GMSL Camera Driver
+ *
+ * Copyright (C) 2017-2018 Jacopo Mondi
+ * Copyright (C) 2017-2018 Kieran Bingham
+ * Copyright (C) 2017-2018 Laurent Pinchart
+ * Copyright (C) 2017-2018 Niklas Söderlund
+ * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ */
+
+/*
+ * The camera is mode of an Omnivision OV10635 sensor connected to a Maxim
+ * MAX9271 GMSL serializer.
+ */
+
+#include <linux/delay.h>
+#include <linux/fwnode.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "rdacm20-ov10635.h"
+
+#define RDACM20_SENSOR_HARD_RESET
+
+#define MAX9271_I2C_ADDRESS 0x40
+
+/* Register 0x04 */
+#define MAX9271_SEREN BIT(7)
+#define MAX9271_CLINKEN BIT(6)
+#define MAX9271_PRBSEN BIT(5)
+#define MAX9271_SLEEP BIT(4)
+#define MAX9271_INTTYPE_I2C (0 << 2)
+#define MAX9271_INTTYPE_UART (1 << 2)
+#define MAX9271_INTTYPE_NONE (2 << 2)
+#define MAX9271_REVCCEN BIT(1)
+#define MAX9271_FWDCCEN BIT(0)
+/* Register 0x07 */
+#define MAX9271_DBL BIT(7)
+#define MAX9271_DRS BIT(6)
+#define MAX9271_BWS BIT(5)
+#define MAX9271_ES BIT(4)
+#define MAX9271_HVEN BIT(2)
+#define MAX9271_EDC_1BIT_PARITY (0 << 0)
+#define MAX9271_EDC_6BIT_CRC (1 << 0)
+#define MAX9271_EDC_6BIT_HAMMING (2 << 0)
+/* Register 0x08 */
+#define MAX9271_INVVS BIT(7)
+#define MAX9271_INVHS BIT(6)
+#define MAX9271_REV_LOGAIN BIT(3)
+#define MAX9271_REV_HIVTH BIT(0)
+/* Register 0x09 */
+#define MAX9271_ID 0x09
+/* Register 0x0d */
+#define MAX9271_I2CLOCACK BIT(7)
+#define MAX9271_I2CSLVSH_1046NS_469NS (3 << 5)
+#define MAX9271_I2CSLVSH_938NS_352NS (2 << 5)
+#define MAX9271_I2CSLVSH_469NS_234NS (1 << 5)
+#define MAX9271_I2CSLVSH_352NS_117NS (0 << 5)
+#define MAX9271_I2CMSTBT_837KBPS (7 << 2)
+#define MAX9271_I2CMSTBT_533KBPS (6 << 2)
+#define MAX9271_I2CMSTBT_339KBPS (5 << 2)
+#define MAX9271_I2CMSTBT_173KBPS (4 << 2)
+#define MAX9271_I2CMSTBT_105KBPS (3 << 2)
+#define MAX9271_I2CMSTBT_84KBPS (2 << 2)
+#define MAX9271_I2CMSTBT_28KBPS (1 << 2)
+#define MAX9271_I2CMSTBT_8KBPS (0 << 2)
+#define MAX9271_I2CSLVTO_NONE (3 << 0)
+#define MAX9271_I2CSLVTO_1024US (2 << 0)
+#define MAX9271_I2CSLVTO_256US (1 << 0)
+#define MAX9271_I2CSLVTO_64US (0 << 0)
+/* Register 0x0f */
+#define MAX9271_GPIO5OUT BIT(5)
+#define MAX9271_GPIO4OUT BIT(4)
+#define MAX9271_GPIO3OUT BIT(3)
+#define MAX9271_GPIO2OUT BIT(2)
+#define MAX9271_GPIO1OUT BIT(1)
+#define MAX9271_SETGPO BIT(0)
+/* Register 0x15 */
+#define MAX9271_PCLKDET BIT(0)
+
+#define MAXIM_I2C_I2C_SPEED_400KHZ MAX9271_I2CMSTBT_339KBPS
+#define MAXIM_I2C_I2C_SPEED_100KHZ MAX9271_I2CMSTBT_105KBPS
+#define MAXIM_I2C_SPEED MAXIM_I2C_I2C_SPEED_100KHZ
+
+#define OV10635_I2C_ADDRESS 0x30
+
+#define OV10635_SOFTWARE_RESET 0x0103
+#define OV10635_PID 0x300a
+#define OV10635_VER 0x300b
+#define OV10635_SC_CMMN_SCCB_ID 0x300c
+#define OV10635_SC_CMMN_SCCB_ID_SELECT BIT(0)
+#define OV10635_VERSION 0xa635
+
+#define OV10635_WIDTH 1280
+#define OV10635_HEIGHT 800
+#define OV10635_FORMAT MEDIA_BUS_FMT_UYVY8_2X8
+/* #define OV10635_FORMAT MEDIA_BUS_FMT_UYVY10_2X10 */
+
+struct rdacm20_device {
+ struct i2c_client *client;
+ struct i2c_client *sensor;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct v4l2_ctrl_handler ctrls;
+};
+
+static inline struct rdacm20_device *sd_to_rdacm20(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct rdacm20_device, sd);
+}
+
+static inline struct rdacm20_device *i2c_to_rdacm20(struct i2c_client *client)
+{
+ return sd_to_rdacm20(i2c_get_clientdata(client));
+}
+
+static int max9271_read(struct rdacm20_device *dev, u8 reg)
+{
+ int ret;
+
+ dev_dbg(&dev->client->dev, "%s(0x%02x)\n", __func__, reg);
+
+ ret = i2c_smbus_read_byte_data(dev->client, reg);
+ if (ret < 0)
+ dev_dbg(&dev->client->dev,
+ "%s: register 0x%02x read failed (%d)\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int max9271_write(struct rdacm20_device *dev, u8 reg, u8 val)
+{
+ int ret;
+
+ dev_dbg(&dev->client->dev, "%s(0x%02x, 0x%02x)\n", __func__, reg, val);
+
+ ret = i2c_smbus_write_byte_data(dev->client, reg, val);
+ if (ret < 0)
+ dev_err(&dev->client->dev,
+ "%s: register 0x%02x write failed (%d)\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ov10635_read16(struct rdacm20_device *dev, u16 reg)
+{
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ int ret;
+
+ ret = i2c_master_send(dev->sensor, buf, 2);
+ if (ret == 2)
+ ret = i2c_master_recv(dev->sensor, buf, 2);
+
+ if (ret < 0) {
+ dev_dbg(&dev->client->dev,
+ "%s: register 0x%04x read failed (%d)\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ return (buf[0] << 8) | buf[1];
+}
+
+static int __ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val)
+{
+ u8 buf[3] = { reg >> 8, reg & 0xff, val };
+ int ret;
+
+ dev_dbg(&dev->client->dev, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
+
+ ret = i2c_master_send(dev->sensor, buf, 3);
+ return ret < 0 ? ret : 0;
+}
+
+static int ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val)
+{
+ int ret;
+
+ ret = __ov10635_write(dev, reg, val);
+ if (ret < 0)
+ dev_err(&dev->client->dev,
+ "%s: register 0x%04x write failed (%d)\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ov10635_set_regs(struct rdacm20_device *dev,
+ const struct ov10635_reg *regs,
+ unsigned int nr_regs)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < nr_regs; i++) {
+ ret = __ov10635_write(dev, regs[i].reg, regs[i].val);
+ if (ret) {
+ dev_err(&dev->client->dev,
+ "%s: register %u (0x%04x) write failed (%d)\n",
+ __func__, i, regs[i].reg, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * rdacm20_pclk_detect() - Detect valid pixel clock from image sensor
+ *
+ * Wait up to 10ms for a valid pixel clock.
+ *
+ * Returns 0 for success, < 0 for pixel clock not properly detected
+ */
+static int rdacm20_pclk_detect(struct rdacm20_device *dev)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < 100; i++) {
+ ret = max9271_read(dev, 0x15);
+ if (ret < 0)
+ return ret;
+
+ if (ret & MAX9271_PCLKDET)
+ return 0;
+
+ usleep_range(50, 100);
+ }
+
+ dev_err(&dev->client->dev, "Unable to detect valid pixel clock\n");
+ return -EIO;
+}
+
+static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct rdacm20_device *dev = sd_to_rdacm20(sd);
+ int ret;
+
+ if (enable) {
+ ret = rdacm20_pclk_detect(dev);
+ if (ret)
+ return ret;
+
+ /* Enable the serial link. */
+ max9271_write(dev, 0x04, MAX9271_SEREN | MAX9271_REVCCEN |
+ MAX9271_FWDCCEN);
+ } else {
+ /* Disable the serial link. */
+ max9271_write(dev, 0x04, MAX9271_CLINKEN | MAX9271_REVCCEN |
+ MAX9271_FWDCCEN);
+ }
+
+ return 0;
+}
+
+static int rdacm20_g_mbus_config(struct v4l2_subdev *sd,
+ struct v4l2_mbus_config *cfg)
+{
+ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+ cfg->type = V4L2_MBUS_CSI2;
+
+ return 0;
+}
+
+static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->pad || code->index > 0)
+ return -EINVAL;
+
+ code->code = OV10635_FORMAT;
+
+ return 0;
+}
+
+static int rdacm20_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *mf = &format->format;
+
+ if (format->pad)
+ return -EINVAL;
+
+ mf->width = OV10635_WIDTH;
+ mf->height = OV10635_HEIGHT;
+ mf->code = OV10635_FORMAT;
+ mf->colorspace = V4L2_COLORSPACE_RAW;
+ mf->field = V4L2_FIELD_NONE;
+ mf->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ mf->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ mf->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops rdacm20_video_ops = {
+ .s_stream = rdacm20_s_stream,
+ .g_mbus_config = rdacm20_g_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops rdacm20_subdev_pad_ops = {
+ .enum_mbus_code = rdacm20_enum_mbus_code,
+ .get_fmt = rdacm20_get_fmt,
+ .set_fmt = rdacm20_get_fmt,
+};
+
+static struct v4l2_subdev_ops rdacm20_subdev_ops = {
+ .video = &rdacm20_video_ops,
+ .pad = &rdacm20_subdev_pad_ops,
+};
+
+static int max9271_configure_i2c(struct rdacm20_device *dev)
+{
+ /*
+ * Configure the I2C bus:
+ *
+ * - Enable high thresholds on the reverse channel
+ * - Disable artificial ACK and set I2C speed
+ */
+ max9271_write(dev, 0x08, MAX9271_REV_HIVTH);
+ usleep_range(5000, 8000);
+
+ max9271_write(dev, 0x0d, MAX9271_I2CSLVSH_469NS_234NS |
+ MAX9271_I2CSLVTO_1024US | MAXIM_I2C_SPEED);
+ usleep_range(5000, 8000);
+
+ return 0;
+}
+
+static int max9271_configure_gmsl_link(struct rdacm20_device *dev)
+{
+ /*
+ * Disable the serial link and enable the configuration link to allow
+ * the control channel to operate in a low-speed mode in the absence of
+ * the serial link clock.
+ */
+ max9271_write(dev, 0x04, MAX9271_CLINKEN | MAX9271_REVCCEN |
+ MAX9271_FWDCCEN);
+
+ /*
+ * The serializer temporarily disables the reverse control channel for
+ * 350µs after starting/stopping the forward serial link, but the
+ * deserializer synchronization time isn't clearly documented.
+ *
+ * According to the serializer datasheet we should wait 3ms, while
+ * according to the deserializer datasheet we should wait 5ms.
+ *
+ * Short delays here appear to show bit-errors in the writes following.
+ * Therefore a conservative delay seems best here.
+ */
+ usleep_range(5000, 8000);
+
+ /*
+ * Configure the GMSL link:
+ *
+ * - Double input mode, high data rate, 24-bit mode
+ * - Latch input data on PCLKIN rising edge
+ * - Enable HS/VS encoding
+ * - 1-bit parity error detection
+ */
+ max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
+ MAX9271_EDC_1BIT_PARITY);
+ usleep_range(5000, 8000);
+
+ return 0;
+}
+
+static int max9271_verify_id(struct rdacm20_device *dev)
+{
+ int ret;
+
+ ret = max9271_read(dev, 0x1e);
+ if (ret < 0) {
+ dev_err(&dev->client->dev, "MAX9271 ID read failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ if (ret != MAX9271_ID) {
+ dev_err(&dev->client->dev, "MAX9271 ID mismatch (0x%02x)\n",
+ ret);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int max9271_configure_address(struct rdacm20_device *dev, u8 addr)
+{
+ int ret;
+
+ /* Change the MAX9271 I2C address. */
+ ret = max9271_write(dev, 0x00, addr << 1);
+ if (ret < 0) {
+ dev_err(&dev->client->dev,
+ "MAX9271 I2C address change failed (%d)\n", ret);
+ return ret;
+ }
+ dev->client->addr = addr;
+ usleep_range(3500, 5000);
+
+ return 0;
+}
+
+static int rdacm20_initialize(struct rdacm20_device *dev)
+{
+ u32 addrs[2];
+ int ret;
+
+ ret = of_property_read_u32_array(dev->client->dev.of_node, "reg",
+ addrs, ARRAY_SIZE(addrs));
+ if (ret < 0) {
+ dev_err(&dev->client->dev, "Invalid DT reg property\n");
+ return -EINVAL;
+ }
+
+ /*
+ * FIXME: The MAX9271 boots at a default address that we will change to
+ * the address specified in DT. Set the client address back to the
+ * default for initial communication.
+ */
+ dev->client->addr = MAX9271_I2C_ADDRESS;
+
+ /* Verify communication with the MAX9271. */
+ i2c_smbus_read_byte(dev->client); /* ping to wake-up */
+
+ /*
+ * Ensure that we have a good link configuration before attempting to
+ * identify the device.
+ */
+ max9271_configure_i2c(dev);
+ max9271_configure_gmsl_link(dev);
+
+ ret = max9271_verify_id(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = max9271_configure_address(dev, addrs[0]);
+ if (ret < 0)
+ return ret;
+
+ /* Reset and verify communication with the OV10635. */
+#ifdef RDACM20_SENSOR_HARD_RESET
+ /* Cycle the OV10635 reset signal connected to the MAX9271 GPIO1. */
+ max9271_write(dev, 0x0f, 0xff & ~(MAX9271_GPIO1OUT | MAX9271_SETGPO));
+ mdelay(10);
+ max9271_write(dev, 0x0f, 0xff & ~MAX9271_SETGPO);
+ mdelay(10);
+#else
+ /* Perform a software reset. */
+ ret = ov10635_write(dev, OV10635_SOFTWARE_RESET, 1);
+ if (ret < 0) {
+ dev_err(&dev->client->dev, "OV10635 reset failed (%d)\n", ret);
+ return -ENXIO;
+ }
+
+ udelay(100);
+#endif
+
+ ret = ov10635_read16(dev, OV10635_PID);
+ if (ret < 0) {
+ dev_err(&dev->client->dev, "OV10635 ID read failed (%d)\n",
+ ret);
+ return -ENXIO;
+ }
+
+ if (ret != OV10635_VERSION) {
+ dev_err(&dev->client->dev, "OV10635 ID mismatch (0x%04x)\n",
+ ret);
+ return -ENXIO;
+ }
+
+ dev_info(&dev->client->dev, "Identified MAX9271 + OV10635 device\n");
+
+ /* Change the sensor I2C address. */
+ ret = ov10635_write(dev, OV10635_SC_CMMN_SCCB_ID,
+ (addrs[1] << 1) | OV10635_SC_CMMN_SCCB_ID_SELECT);
+ if (ret < 0) {
+ dev_err(&dev->client->dev,
+ "OV10635 I2C address change failed (%d)\n", ret);
+ return ret;
+ }
+ dev->sensor->addr = addrs[1];
+ usleep_range(3500, 5000);
+
+ /* Program the 0V10635 initial configuration. */
+ ret = ov10635_set_regs(dev, ov10635_regs_wizard,
+ ARRAY_SIZE(ov10635_regs_wizard));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rdacm20_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct rdacm20_device *dev;
+ struct fwnode_handle *ep;
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->client = client;
+
+ /* Create the dummy I2C client for the sensor. */
+ dev->sensor = i2c_new_dummy(client->adapter, OV10635_I2C_ADDRESS);
+ if (!dev->sensor) {
+ ret = -ENXIO;
+ goto error;
+ }
+
+ /* Initialize the hardware. */
+ ret = rdacm20_initialize(dev);
+ if (ret < 0)
+ goto error;
+
+ /* Initialize and register the subdevice. */
+ v4l2_i2c_subdev_init(&dev->sd, client, &rdacm20_subdev_ops);
+ dev->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ v4l2_ctrl_handler_init(&dev->ctrls, 1);
+ /*
+ * FIXME: Compute the real pixel rate. The 50 MP/s value comes from the
+ * hardcoded frequency in the BSP CSI-2 receiver driver.
+ */
+ v4l2_ctrl_new_std(&dev->ctrls, NULL, V4L2_CID_PIXEL_RATE, 50000000,
+ 50000000, 1, 50000000);
+ dev->sd.ctrl_handler = &dev->ctrls;
+
+ ret = dev->ctrls.error;
+ if (ret)
+ goto error;
+
+ dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+ dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+ if (ret < 0)
+ goto error;
+
+ ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+ if (!ep) {
+ dev_err(&client->dev,
+ "Unable to get endpoint in node %pOF: %ld\n",
+ client->dev.of_node, PTR_ERR(ep));
+ ret = -ENOENT;
+ goto error;
+ }
+ dev->sd.fwnode = ep;
+
+ ret = v4l2_async_register_subdev(&dev->sd);
+ if (ret)
+ goto error_put_node;
+
+ return 0;
+
+error_put_node:
+ fwnode_handle_put(ep);
+error:
+ media_entity_cleanup(&dev->sd.entity);
+ if (dev->sensor)
+ i2c_unregister_device(dev->sensor);
+ kfree(dev);
+
+ dev_err(&client->dev, "probe failed\n");
+
+ return ret;
+}
+
+static int rdacm20_remove(struct i2c_client *client)
+{
+ struct rdacm20_device *dev = i2c_to_rdacm20(client);
+
+ fwnode_handle_put(dev->sd.fwnode);
+ v4l2_async_unregister_subdev(&dev->sd);
+ media_entity_cleanup(&dev->sd.entity);
+ i2c_unregister_device(dev->sensor);
+ kfree(dev);
+
+ return 0;
+}
+
+static void rdacm20_shutdown(struct i2c_client *client)
+{
+ struct rdacm20_device *dev = i2c_to_rdacm20(client);
+
+ /* make sure stream off during shutdown (reset/reboot) */
+ rdacm20_s_stream(&dev->sd, 0);
+}
+
+static const struct i2c_device_id rdacm20_id[] = {
+ { "rdacm20", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rdacm20_id);
+
+static const struct of_device_id rdacm20_of_ids[] = {
+ { .compatible = "imi,rdacm20", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rdacm20_of_ids);
+
+static struct i2c_driver rdacm20_i2c_driver = {
+ .driver = {
+ .name = "rdacm20",
+ .of_match_table = rdacm20_of_ids,
+ },
+ .probe = rdacm20_probe,
+ .remove = rdacm20_remove,
+ .shutdown = rdacm20_shutdown,
+ .id_table = rdacm20_id,
+};
+
+module_i2c_driver(rdacm20_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for MAX9286<->MAX9271<->OV10635");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_LICENSE("GPL");