Skip to content

Commit 34009bf

Browse files
Jacopo Mondimchehab
authored andcommitted
media: i2c: Add RDACM20 driver
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> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
1 parent e9f8176 commit 34009bf

File tree

6 files changed

+1259
-0
lines changed

6 files changed

+1259
-0
lines changed

MAINTAINERS

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14412,6 +14412,18 @@ S: Supported
1441214412
T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev
1441314413
F: tools/testing/selftests/rcutorture
1441414414

14415+
RDACM20 Camera Sensor
14416+
M: Jacopo Mondi <jacopo+renesas@jmondi.org>
14417+
M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
14418+
M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
14419+
M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
14420+
L: linux-media@vger.kernel.org
14421+
S: Maintained
14422+
F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml
14423+
F: drivers/media/i2c/rdacm20.c
14424+
F: drivers/media/i2c/max9271.c
14425+
F: drivers/media/i2c/max9271.h
14426+
1441514427
RDC R-321X SoC
1441614428
M: Florian Fainelli <florian@openwrt.org>
1441714429
S: Maintained

drivers/media/i2c/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,19 @@ config VIDEO_NOON010PC30
11711171

11721172
source "drivers/media/i2c/m5mols/Kconfig"
11731173

1174+
config VIDEO_RDACM20
1175+
tristate "IMI RDACM20 camera support"
1176+
depends on I2C
1177+
select V4L2_FWNODE
1178+
select VIDEO_V4L2_SUBDEV_API
1179+
select MEDIA_CONTROLLER
1180+
help
1181+
This driver supports the IMI RDACM20 GMSL camera, used in
1182+
ADAS systems.
1183+
1184+
This camera should be used in conjunction with a GMSL
1185+
deserialiser such as the MAX9286.
1186+
11741187
config VIDEO_RJ54N1
11751188
tristate "Sharp RJ54N1CB0C sensor support"
11761189
depends on I2C && VIDEO_V4L2

drivers/media/i2c/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ obj-$(CONFIG_VIDEO_IMX290) += imx290.o
120120
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
121121
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
122122
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
123+
rdacm20-camera_module-objs := rdacm20.o max9271.o
124+
obj-$(CONFIG_VIDEO_RDACM20) += rdacm20-camera_module.o
123125
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
124126

125127
obj-$(CONFIG_SDR_MAX2175) += max2175.o

drivers/media/i2c/max9271.c

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* Copyright (C) 2017-2020 Jacopo Mondi
4+
* Copyright (C) 2017-2020 Kieran Bingham
5+
* Copyright (C) 2017-2020 Laurent Pinchart
6+
* Copyright (C) 2017-2020 Niklas Söderlund
7+
* Copyright (C) 2016 Renesas Electronics Corporation
8+
* Copyright (C) 2015 Cogent Embedded, Inc.
9+
*
10+
* This file exports functions to control the Maxim MAX9271 GMSL serializer
11+
* chip. This is not a self-contained driver, as MAX9271 is usually embedded in
12+
* camera modules with at least one image sensor and optional additional
13+
* components, such as uController units or ISPs/DSPs.
14+
*
15+
* Drivers for the camera modules (i.e. rdacm20/21) are expected to use
16+
* functions exported from this library driver to maximize code re-use.
17+
*/
18+
19+
#include <linux/delay.h>
20+
#include <linux/i2c.h>
21+
22+
#include "max9271.h"
23+
24+
static int max9271_read(struct max9271_device *dev, u8 reg)
25+
{
26+
int ret;
27+
28+
dev_dbg(&dev->client->dev, "%s(0x%02x)\n", __func__, reg);
29+
30+
ret = i2c_smbus_read_byte_data(dev->client, reg);
31+
if (ret < 0)
32+
dev_dbg(&dev->client->dev,
33+
"%s: register 0x%02x read failed (%d)\n",
34+
__func__, reg, ret);
35+
36+
return ret;
37+
}
38+
39+
static int max9271_write(struct max9271_device *dev, u8 reg, u8 val)
40+
{
41+
int ret;
42+
43+
dev_dbg(&dev->client->dev, "%s(0x%02x, 0x%02x)\n", __func__, reg, val);
44+
45+
ret = i2c_smbus_write_byte_data(dev->client, reg, val);
46+
if (ret < 0)
47+
dev_err(&dev->client->dev,
48+
"%s: register 0x%02x write failed (%d)\n",
49+
__func__, reg, ret);
50+
51+
return ret;
52+
}
53+
54+
/*
55+
* max9271_pclk_detect() - Detect valid pixel clock from image sensor
56+
*
57+
* Wait up to 10ms for a valid pixel clock.
58+
*
59+
* Returns 0 for success, < 0 for pixel clock not properly detected
60+
*/
61+
static int max9271_pclk_detect(struct max9271_device *dev)
62+
{
63+
unsigned int i;
64+
int ret;
65+
66+
for (i = 0; i < 100; i++) {
67+
ret = max9271_read(dev, 0x15);
68+
if (ret < 0)
69+
return ret;
70+
71+
if (ret & MAX9271_PCLKDET)
72+
return 0;
73+
74+
usleep_range(50, 100);
75+
}
76+
77+
dev_err(&dev->client->dev, "Unable to detect valid pixel clock\n");
78+
79+
return -EIO;
80+
}
81+
82+
int max9271_set_serial_link(struct max9271_device *dev, bool enable)
83+
{
84+
int ret;
85+
u8 val = MAX9271_REVCCEN | MAX9271_FWDCCEN;
86+
87+
if (enable) {
88+
ret = max9271_pclk_detect(dev);
89+
if (ret)
90+
return ret;
91+
92+
val |= MAX9271_SEREN;
93+
} else {
94+
val |= MAX9271_CLINKEN;
95+
}
96+
97+
/*
98+
* The serializer temporarily disables the reverse control channel for
99+
* 350µs after starting/stopping the forward serial link, but the
100+
* deserializer synchronization time isn't clearly documented.
101+
*
102+
* According to the serializer datasheet we should wait 3ms, while
103+
* according to the deserializer datasheet we should wait 5ms.
104+
*
105+
* Short delays here appear to show bit-errors in the writes following.
106+
* Therefore a conservative delay seems best here.
107+
*/
108+
max9271_write(dev, 0x04, val);
109+
usleep_range(5000, 8000);
110+
111+
return 0;
112+
}
113+
EXPORT_SYMBOL_GPL(max9271_set_serial_link);
114+
115+
int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config)
116+
{
117+
int ret;
118+
119+
ret = max9271_write(dev, 0x0d, i2c_config);
120+
if (ret)
121+
return ret;
122+
123+
/* The delay required after an I2C bus configuration change is not
124+
* characterized in the serializer manual. Sleep up to 5msec to
125+
* stay safe.
126+
*/
127+
usleep_range(3500, 5000);
128+
129+
return 0;
130+
}
131+
EXPORT_SYMBOL_GPL(max9271_configure_i2c);
132+
133+
int max9271_set_high_threshold(struct max9271_device *dev, bool enable)
134+
{
135+
int ret;
136+
137+
ret = max9271_read(dev, 0x08);
138+
if (ret < 0)
139+
return ret;
140+
141+
/*
142+
* Enable or disable reverse channel high threshold to increase
143+
* immunity to power supply noise.
144+
*/
145+
max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0));
146+
usleep_range(2000, 2500);
147+
148+
return 0;
149+
}
150+
EXPORT_SYMBOL_GPL(max9271_set_high_threshold);
151+
152+
int max9271_configure_gmsl_link(struct max9271_device *dev)
153+
{
154+
/*
155+
* Configure the GMSL link:
156+
*
157+
* - Double input mode, high data rate, 24-bit mode
158+
* - Latch input data on PCLKIN rising edge
159+
* - Enable HS/VS encoding
160+
* - 1-bit parity error detection
161+
*
162+
* TODO: Make the GMSL link configuration parametric.
163+
*/
164+
max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN |
165+
MAX9271_EDC_1BIT_PARITY);
166+
usleep_range(5000, 8000);
167+
168+
/*
169+
* Adjust spread spectrum to +4% and auto-detect pixel clock
170+
* and serial link rate.
171+
*/
172+
max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES |
173+
MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT);
174+
usleep_range(5000, 8000);
175+
176+
return 0;
177+
}
178+
EXPORT_SYMBOL_GPL(max9271_configure_gmsl_link);
179+
180+
int max9271_set_gpios(struct max9271_device *dev, u8 gpio_mask)
181+
{
182+
int ret;
183+
184+
ret = max9271_read(dev, 0x0f);
185+
if (ret < 0)
186+
return 0;
187+
188+
ret |= gpio_mask;
189+
ret = max9271_write(dev, 0x0f, ret);
190+
if (ret < 0) {
191+
dev_err(&dev->client->dev, "Failed to set gpio (%d)\n", ret);
192+
return ret;
193+
}
194+
195+
usleep_range(3500, 5000);
196+
197+
return 0;
198+
}
199+
EXPORT_SYMBOL_GPL(max9271_set_gpios);
200+
201+
int max9271_clear_gpios(struct max9271_device *dev, u8 gpio_mask)
202+
{
203+
int ret;
204+
205+
ret = max9271_read(dev, 0x0f);
206+
if (ret < 0)
207+
return 0;
208+
209+
ret &= ~gpio_mask;
210+
ret = max9271_write(dev, 0x0f, ret);
211+
if (ret < 0) {
212+
dev_err(&dev->client->dev, "Failed to clear gpio (%d)\n", ret);
213+
return ret;
214+
}
215+
216+
usleep_range(3500, 5000);
217+
218+
return 0;
219+
}
220+
EXPORT_SYMBOL_GPL(max9271_clear_gpios);
221+
222+
int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask)
223+
{
224+
int ret;
225+
226+
ret = max9271_read(dev, 0x0f);
227+
if (ret < 0)
228+
return 0;
229+
230+
/* BIT(0) reserved: GPO is always enabled. */
231+
ret |= gpio_mask | BIT(0);
232+
ret = max9271_write(dev, 0x0e, ret);
233+
if (ret < 0) {
234+
dev_err(&dev->client->dev, "Failed to enable gpio (%d)\n", ret);
235+
return ret;
236+
}
237+
238+
usleep_range(3500, 5000);
239+
240+
return 0;
241+
}
242+
EXPORT_SYMBOL_GPL(max9271_enable_gpios);
243+
244+
int max9271_disable_gpios(struct max9271_device *dev, u8 gpio_mask)
245+
{
246+
int ret;
247+
248+
ret = max9271_read(dev, 0x0f);
249+
if (ret < 0)
250+
return 0;
251+
252+
/* BIT(0) reserved: GPO cannot be disabled */
253+
ret &= (~gpio_mask | BIT(0));
254+
ret = max9271_write(dev, 0x0e, ret);
255+
if (ret < 0) {
256+
dev_err(&dev->client->dev, "Failed to disable gpio (%d)\n", ret);
257+
return ret;
258+
}
259+
260+
usleep_range(3500, 5000);
261+
262+
return 0;
263+
}
264+
EXPORT_SYMBOL_GPL(max9271_disable_gpios);
265+
266+
int max9271_verify_id(struct max9271_device *dev)
267+
{
268+
int ret;
269+
270+
ret = max9271_read(dev, 0x1e);
271+
if (ret < 0) {
272+
dev_err(&dev->client->dev, "MAX9271 ID read failed (%d)\n",
273+
ret);
274+
return ret;
275+
}
276+
277+
if (ret != MAX9271_ID) {
278+
dev_err(&dev->client->dev, "MAX9271 ID mismatch (0x%02x)\n",
279+
ret);
280+
return -ENXIO;
281+
}
282+
283+
return 0;
284+
}
285+
EXPORT_SYMBOL_GPL(max9271_verify_id);
286+
287+
int max9271_set_address(struct max9271_device *dev, u8 addr)
288+
{
289+
int ret;
290+
291+
ret = max9271_write(dev, 0x00, addr << 1);
292+
if (ret < 0) {
293+
dev_err(&dev->client->dev,
294+
"MAX9271 I2C address change failed (%d)\n", ret);
295+
return ret;
296+
}
297+
usleep_range(3500, 5000);
298+
299+
return 0;
300+
}
301+
EXPORT_SYMBOL_GPL(max9271_set_address);
302+
303+
int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr)
304+
{
305+
int ret;
306+
307+
ret = max9271_write(dev, 0x01, addr << 1);
308+
if (ret < 0) {
309+
dev_err(&dev->client->dev,
310+
"MAX9271 deserializer address set failed (%d)\n", ret);
311+
return ret;
312+
}
313+
usleep_range(3500, 5000);
314+
315+
return 0;
316+
}
317+
EXPORT_SYMBOL_GPL(max9271_set_deserializer_address);
318+
319+
int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest)
320+
{
321+
int ret;
322+
323+
ret = max9271_write(dev, 0x09, source << 1);
324+
if (ret < 0) {
325+
dev_err(&dev->client->dev,
326+
"MAX9271 I2C translation setup failed (%d)\n", ret);
327+
return ret;
328+
}
329+
usleep_range(3500, 5000);
330+
331+
ret = max9271_write(dev, 0x0a, dest << 1);
332+
if (ret < 0) {
333+
dev_err(&dev->client->dev,
334+
"MAX9271 I2C translation setup failed (%d)\n", ret);
335+
return ret;
336+
}
337+
usleep_range(3500, 5000);
338+
339+
return 0;
340+
}
341+
EXPORT_SYMBOL_GPL(max9271_set_translation);

0 commit comments

Comments
 (0)