All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sakari Ailus <sakari.ailus@iki.fi>
To: Kieran Bingham <kieran.bingham@ideasonboard.com>
Cc: linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org,
	devicetree@vger.kernel.org,
	"Niklas Söderlund" <niklas.soderlund@ragnatech.se>,
	"Jacopo Mondi" <jacopo@jmondi.org>,
	"Laurent Pinchart" <laurent.pinchart@ideasonboard.com>,
	"Kieran Bingham" <kieran.bingham+renesas@ideasonboard.com>,
	linux-kernel@vger.kernel.org,
	"Jacopo Mondi" <jacopo+renesas@jmondi.org>,
	"Laurent Pinchart" <laurent.pinchart+renesas@ideasonboard.com>,
	"Niklas Söderlund" <niklas.soderlund+renesas@ragnatech.se>
Subject: Re: [PATCH v4 4/4] media: i2c: Add RDACM20 driver
Date: Fri, 21 Dec 2018 01:11:14 +0200	[thread overview]
Message-ID: <20181220231114.frij25qhwtzpfjrr@valkosipuli.retiisi.org.uk> (raw)
In-Reply-To: <cb663bd5-479a-25d3-6545-a525df1329ca@ideasonboard.com>

Hu Kieran,

Apologies for the late reply.

On Wed, Nov 28, 2018 at 12:51:39PM +0000, Kieran Bingham wrote:
> Hi Sakari,
> 
> Thank you for your review,
> 
> On 20/11/2018 08:34, Sakari Ailus wrote:
> > Hi Kieran,
> > 
> > On Fri, Nov 02, 2018 at 03:47:23PM +0000, Kieran Bingham wrote:
> >> From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> >>
> >> The RDACM20 is a GMSL camera supporting 1280x800 resolution images
> >> developed by IMI based on an Omnivision 10635 sensor and a Maxim MAX9271
> >> GMSL serializer.
> >>
> >> The GMSL link carries power, control (I2C) and video data over a
> >> single coax cable.
> >>
> >> 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>
> >>
> >> ---
> >> v2:
> >>  - Fix MAINTAINERS entry
> >>
> >> v3:
> >>  - Use new V4L2_MBUS_CSI2_DPHY bus type
> >>  - Remove 'always zero' error print
> >>  - Fix module description
> >> ---
> >>  MAINTAINERS                         |  10 +
> >>  drivers/media/i2c/Kconfig           |  11 +
> >>  drivers/media/i2c/Makefile          |   1 +
> >>  drivers/media/i2c/rdacm20-ov10635.h | 953 ++++++++++++++++++++++++++++
> >>  drivers/media/i2c/rdacm20.c         | 635 ++++++++++++++++++
> >>  5 files changed, 1610 insertions(+)
> >>  create mode 100644 drivers/media/i2c/rdacm20-ov10635.h
> >>  create mode 100644 drivers/media/i2c/rdacm20.c
> >>
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index 745f0fd1fff1..26ef20087a43 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -12230,6 +12230,16 @@ S:	Supported
> >>  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
> >>  F:	tools/testing/selftests/rcutorture
> >>  
> >> +RDACM20 Camera Sensor
> >> +M:	Jacopo Mondi <jacopo+renesas@jmondi.org>
> >> +M:	Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> >> +M:	Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> >> +M:	Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > 
> > I'm happy to see this will be well maintained. :-)
> 
> Well it means /someone/ should always be able to pick it up :D
> 
> I didn't know who to put here - so I put all of the current blamees ;)
> We've all put a lot of time and work in to the GMSL bring up and
> refactoring.
> 
> If you think it's overkill, I can reduce the names. Same on max9286.

Not at all. There are too many drivers that do not receive the attention
they'd need. :-I

> 
> 
> >> +L:	linux-media@vger.kernel.org
> >> +S:	Maintained
> >> +F:	Documentation/devicetree/bindings/media/i2c/rdacm20.txt
> >> +F:	drivers/media/i2c/rdacm20*
> >> +
> >>  RDC R-321X SoC
> >>  M:	Florian Fainelli <florian@openwrt.org>
> >>  S:	Maintained
> >> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> >> index eadc00bdd3bf..5eded5e337ec 100644
> >> --- a/drivers/media/i2c/Kconfig
> >> +++ b/drivers/media/i2c/Kconfig
> >> @@ -989,6 +989,17 @@ config VIDEO_S5C73M3
> >>  	  This is a V4L2 sensor driver for Samsung S5C73M3
> >>  	  8 Mpixel camera.
> >>  
> >> +config VIDEO_RDACM20

Btw. I think this might be worth a new comment to tell what devices can be
found here --- it's not a camera sensor as such really. But I wonder how
should it be called. We do have "Miscellaneous helper chips" at the end.
I'm not sure that'd be better. As-is could be fine, too.

> >> +	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, used in
> >> +	  ADAS systems.
> >> +
> >> +	  This camera should be used in conjunction with a GMSL
> >> +	  deserialiser such as the MAX9286.
> >> +
> >>  comment "Flash devices"
> >>  
> >>  config VIDEO_ADP1653
> >> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> >> index 4de7fe62b179..121d28283d45 100644
> >> --- a/drivers/media/i2c/Makefile
> >> +++ b/drivers/media/i2c/Makefile
> >> @@ -111,5 +111,6 @@ obj-$(CONFIG_VIDEO_IMX274)	+= imx274.o
> >>  obj-$(CONFIG_VIDEO_IMX319)	+= imx319.o
> >>  obj-$(CONFIG_VIDEO_IMX355)	+= imx355.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 000000000000..3c53a3262ee2
> >> --- /dev/null
> >> +++ b/drivers/media/i2c/rdacm20-ov10635.h
> >> @@ -0,0 +1,953 @@
> >> +/* SPDX-License-Identifier: GPL-2.0+ */
> >> +/*
> >> + * IMI RDACM20 camera OV10635 sensor register initialization values
> >> + *
> >> + * 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.
> >> + *
> >> + */
> >> +
> >> +/*
> >> + * 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
> > 
> > A part of this driver looks like a driver for an OV camera sensor. Would
> > there be something that prevents separating the camera sensor driver from
> > this one?
> 
> I don't think there's anything preventing it - except (a fair bit of)
> development time.
> 
> We also have the RDACM21 to support, which uses the max9271 and an
> OV10640. At that time - this will absolutely have to be split. We
> shouldn't replicate the max9271 code.
> 
> I mentioned briefly in the cover letter:
> 
> > Further anticipated work in this area includes supporting the RDACM21
> > camera, at which point the RDACM20 will be adapted to separate out the
> > MAX9271 and the OV10635 sensor components.

Oh, sorry; I missed that.

Does the DT currently contain all the necessary information for the drivers
to get everything they need, if you separated them?

> 
> But to get more dedicated time to work this - we need to show some
> progress on GMSL up-streaming, so the max9286 and bindings take priority
> for now.
> 
> A little bit catch 22 ... :D
> 
> I'm sure there will be overlap between GMSL and FPD-Link with the RDACM
> range [0] of cameras too, which also provide TI-FPD Link serialisers.
> 
> I currently envisage that we would have an RDACM20 'driver' which would
> know that it has a max9271 serialiser and an OV10635 sensor, and would
> handle the links of any subdevices internally.

I don't remember all the details, but my understanding is that RDACM20 is
much more than just a box that contains the serialiser and the sensors. So
very probably it'll need its own driver, too. Powering on the sensors, for
instance, seemed hard to make generic.

> 
> As the RDACM20 is an object itself, I think this makes sense ... unless
> anyone suggests that each part should be broken down into the DT
> directly ? (I think that would possibly be a bit too much)
> 
> 
> [0]
> https://www.global-imi.com/sites/default/files/Generic-Minicube-Catalogue-1020151.pdf
> 
> 
> >> +
> >> +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 000000000000..d96b2eb5ab1b
> >> --- /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_DPHY;
> > 
> > Hmm. What are you using g_mbus_config() for?
> 
> Good point here ... I assumed it was passed through up to the VIN - but
> it's really not applicable here.
> 
> Or if it is - then it should be describing the GMSL bus link!
> 
> I'll bet this isn't even getting called and can likely be removed.

There are two use cases I know for this --- SoC camera and something that
changes dynamically. The former is obsolete and the latter is better
addressed by the frame descriptors I'd like to see go in for 4.22.

> 
> 
> > 
> >> +
> >> +	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);
> > 
> > Do you need a busy loop? Could you use msleep()?
> 
> Checkpatch warns here:
> 
> WARNING: msleep < 20ms can sleep for up to 20ms; see
> Documentation/timers/timers-howto.txt
> #10: FILE: drivers/media/i2c/rdacm20.c:461:
> +       msleep(10);
> 
> I think for this context, msleep(10) even with the warning is fine here,
> but perhaps we can meet that with a usleep_range(10000, 20000); too.

usleep_range(), then, but just setting the delay to precisely 10 ms is much
better than a 10 ms busy loop.

> 
> 
> >> +#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));
> > 
> > return ov...(); ?
> 
> Yes, that would be nicer.
> 
> > 
> >> +	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);
> > 
> > You could use devm_kzalloc().
> 
> Will change.
> 
> > 
> >> +	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;
> > 
> > |=, as in the other patch.
> 
> Bah - yes :)
> 
> 
> > 
> >> +
> >> +	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\n",
> >> +			client->dev.of_node);
> >> +		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:
> > 
> > You're missing v4l2_ctrl_handler_free() here.
> 
> Good spot. Thanks
> 
> > 
> >> +	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);
> > 
> > As well as here.
> 
> 
> Ack.
> 
> 
> > 
> >> +	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,
> > 
> > Could you use probe_new, so you could remove the i2c ID table? Or do you
> > need that for something?
> 
> I believe probe_new is probably fine.
> 
> I should really resurrect my i2c-probe-coccinelle patch and get that
> conversion task done, so we can get to removing and replacing .probe :)

That'd be nice!

> 
> (note to self ... starting projects when unemployed becomes difficult to
> continue when someone else gives you projects to work on all the time ...)
> 
> 
> > 
> >> +	.remove		= rdacm20_remove,
> >> +	.shutdown	= rdacm20_shutdown,
> >> +	.id_table	= rdacm20_id,
> >> +};
> >> +
> >> +module_i2c_driver(rdacm20_i2c_driver);
> >> +
> >> +MODULE_DESCRIPTION("GMSL Camera driver for RDACM20");
> >> +MODULE_AUTHOR("Vladimir Barinov");
> >> +MODULE_LICENSE("GPL");
> 
> Changes described above made and tested on a *single MAX9286* capturing
> 4 cameras simultaneously, now on my rcar.git gmsl/v5 branch ... :D

-- 
Regards,

Sakari Ailus

      reply	other threads:[~2018-12-20 23:12 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-02 15:47 [PATCH v4 0/4] MAX9286 GMSL Support Kieran Bingham
2018-11-02 15:47 ` [PATCH v4 1/4] dt-bindings: media: i2c: Add bindings for Maxim Integrated MAX9286 Kieran Bingham
2018-11-05 20:02   ` Rob Herring
2018-11-13 22:42   ` Luca Ceresoli
2018-11-13 23:12     ` Kieran Bingham
2018-11-14 10:04       ` Luca Ceresoli
2018-11-27 22:47         ` Kieran Bingham
2018-12-01 18:41           ` Luca Ceresoli
2018-11-02 15:47 ` [PATCH v4 2/4] dt-bindings: media: i2c: Add bindings for IMI RDACM20 Kieran Bingham
2018-11-05 20:13   ` Rob Herring
2018-11-02 15:47 ` [PATCH v4 3/4] media: i2c: Add MAX9286 driver Kieran Bingham
2018-11-07 15:06   ` Kieran Bingham
2018-11-07 17:24     ` Luca Ceresoli
2018-11-08 10:11       ` jacopo mondi
2018-11-08 11:24         ` Luca Ceresoli
2018-11-13 22:49   ` Luca Ceresoli
2018-11-14  0:46     ` Kieran Bingham
2018-11-14 10:04       ` Luca Ceresoli
2018-11-20  0:32         ` Kieran Bingham
2018-11-20 10:51           ` Luca Ceresoli
2018-11-20 17:44             ` jacopo mondi
2018-11-21 10:05               ` Luca Ceresoli
2018-11-02 15:47 ` [PATCH v4 4/4] media: i2c: Add RDACM20 driver Kieran Bingham
2018-11-20  8:34   ` Sakari Ailus
2018-11-20  8:34     ` Sakari Ailus
2018-11-28 12:51     ` Kieran Bingham
2018-12-20 23:11       ` Sakari Ailus [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181220231114.frij25qhwtzpfjrr@valkosipuli.retiisi.org.uk \
    --to=sakari.ailus@iki.fi \
    --cc=devicetree@vger.kernel.org \
    --cc=jacopo+renesas@jmondi.org \
    --cc=jacopo@jmondi.org \
    --cc=kieran.bingham+renesas@ideasonboard.com \
    --cc=kieran.bingham@ideasonboard.com \
    --cc=laurent.pinchart+renesas@ideasonboard.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-renesas-soc@vger.kernel.org \
    --cc=niklas.soderlund+renesas@ragnatech.se \
    --cc=niklas.soderlund@ragnatech.se \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.