Re: [PATCH v4 4/4] media: i2c: Add RDACM20 driver
From: Sakari Ailus <sakari.ailus@iki.fi>
Date: 2018-12-20 23:12:04
Also in:
linux-media, linux-renesas-soc, lkml
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:quoted
Hi Kieran, On Fri, Nov 02, 2018 at 03:47:23PM +0000, Kieran Bingham wrote:quoted
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.cdiff --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
quoted
quoted
+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 [off-list ref] S: Maintaineddiff --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.
quoted
quoted
+ 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_ADP1653diff --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.odiff --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 933A 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:quoted
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.pdfquoted
quoted
+ +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.
quoted
quoted
+ + 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.
quoted
quoted
+#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.quoted
quoted
+ 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.quoted
quoted
+ 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 :)quoted
quoted
+ + 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. Thanksquoted
quoted
+ 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.quoted
quoted
+ 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 ...)quoted
quoted
+ .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