1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
From 071d66e19764cb2019e95cb44d08a1848e688f12 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 7 Jul 2020 18:29:10 +0100
Subject: [PATCH] media: i2c: ov9281: Add support for 8 bit readout
The sensor supports 8 bit mode as well as 10bit, so add the
relevant code to allow selection of this.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/ov9281.c | 66 ++++++++++++++++++++++++++++++--------
1 file changed, 52 insertions(+), 14 deletions(-)
--- a/drivers/media/i2c/ov9281.c
+++ b/drivers/media/i2c/ov9281.c
@@ -29,11 +29,12 @@
#define OV9281_LINK_FREQ_400MHZ 400000000
#define OV9281_LANES 2
-#define OV9281_BITS_PER_SAMPLE 10
/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
-#define OV9281_PIXEL_RATE (OV9281_LINK_FREQ_400MHZ * 2 * \
- OV9281_LANES / OV9281_BITS_PER_SAMPLE)
+#define OV9281_PIXEL_RATE_10BIT (OV9281_LINK_FREQ_400MHZ * 2 * \
+ OV9281_LANES / 10)
+#define OV9281_PIXEL_RATE_8BIT (OV9281_LINK_FREQ_400MHZ * 2 * \
+ OV9281_LANES / 8)
#define OV9281_XVCLK_FREQ 24000000
#define CHIP_ID 0x9281
@@ -122,24 +123,25 @@ struct ov9281 {
struct v4l2_ctrl *digi_gain;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *test_pattern;
struct mutex mutex;
bool streaming;
bool power_on;
const struct ov9281_mode *cur_mode;
+ u32 code;
};
#define to_ov9281(sd) container_of(sd, struct ov9281, subdev)
/*
* Xclk 24Mhz
- * max_framerate 120fps
+ * max_framerate 120fps for 10 bit, 144fps for 8 bit.
* mipi_datarate per lane 800Mbps
*/
static const struct regval ov9281_1280x800_regs[] = {
{0x0103, 0x01},
{0x0302, 0x32},
- {0x030d, 0x50},
{0x030e, 0x02},
{0x3001, 0x00},
{0x3004, 0x00},
@@ -168,7 +170,6 @@ static const struct regval ov9281_1280x8
{0x3620, 0x6f},
{0x3632, 0x56},
{0x3633, 0x78},
- {0x3662, 0x05},
{0x3666, 0x00},
{0x366f, 0x5a},
{0x3680, 0x84},
@@ -235,6 +236,18 @@ static const struct regval ov9281_1280x8
{REG_NULL, 0x00},
};
+static const struct regval op_10bit[] = {
+ {0x030d, 0x50},
+ {0x3662, 0x05},
+ {REG_NULL, 0x00},
+};
+
+static const struct regval op_8bit[] = {
+ {0x030d, 0x60},
+ {0x3662, 0x07},
+ {REG_NULL, 0x00},
+};
+
static const struct ov9281_mode supported_modes[] = {
{
.width = 1280,
@@ -374,12 +387,13 @@ static int ov9281_set_fmt(struct v4l2_su
{
struct ov9281 *ov9281 = to_ov9281(sd);
const struct ov9281_mode *mode;
- s64 h_blank, vblank_def;
+ s64 h_blank, vblank_def, pixel_rate;
mutex_lock(&ov9281->mutex);
mode = ov9281_find_best_fit(fmt);
- fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
+ if (fmt->format.code != MEDIA_BUS_FMT_Y8_1X8)
+ fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
fmt->format.width = mode->width;
fmt->format.height = mode->height;
fmt->format.field = V4L2_FIELD_NONE;
@@ -396,6 +410,7 @@ static int ov9281_set_fmt(struct v4l2_su
*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
} else {
ov9281->cur_mode = mode;
+ ov9281->code = fmt->format.code;
h_blank = mode->hts_def - mode->width;
__v4l2_ctrl_modify_range(ov9281->hblank, h_blank,
h_blank, 1, h_blank);
@@ -405,6 +420,11 @@ static int ov9281_set_fmt(struct v4l2_su
OV9281_VTS_MAX - mode->height,
1, vblank_def);
__v4l2_ctrl_s_ctrl(ov9281->vblank, vblank_def);
+
+ pixel_rate = (fmt->format.code == MEDIA_BUS_FMT_Y10_1X10) ?
+ OV9281_PIXEL_RATE_10BIT : OV9281_PIXEL_RATE_8BIT;
+ __v4l2_ctrl_modify_range(ov9281->pixel_rate, pixel_rate,
+ pixel_rate, 1, pixel_rate);
}
mutex_unlock(&ov9281->mutex);
@@ -425,7 +445,7 @@ static int ov9281_get_fmt(struct v4l2_su
} else {
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
+ fmt->format.code = ov9281->code;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_SRGB;
fmt->format.ycbcr_enc =
@@ -446,9 +466,16 @@ static int ov9281_enum_mbus_code(struct
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index)
+ switch (code->index) {
+ default:
return -EINVAL;
- code->code = MEDIA_BUS_FMT_Y10_1X10;
+ case 0:
+ code->code = MEDIA_BUS_FMT_Y10_1X10;
+ break;
+ case 1:
+ code->code = MEDIA_BUS_FMT_Y8_1X8;
+ break;
+ }
return 0;
}
@@ -460,7 +487,8 @@ static int ov9281_enum_frame_sizes(struc
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
- if (fse->code != MEDIA_BUS_FMT_Y10_1X10)
+ if (fse->code != MEDIA_BUS_FMT_Y10_1X10 &&
+ fse->code != MEDIA_BUS_FMT_Y8_1X8)
return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
@@ -543,6 +571,13 @@ static int __ov9281_start_stream(struct
if (ret)
return ret;
+ if (ov9281->code == MEDIA_BUS_FMT_Y10_1X10)
+ ret = ov9281_write_array(ov9281->client, op_10bit);
+ else
+ ret = ov9281_write_array(ov9281->client, op_8bit);
+ if (ret)
+ return ret;
+
/* In case these controls are set before streaming */
mutex_unlock(&ov9281->mutex);
ret = v4l2_ctrl_handler_setup(&ov9281->ctrl_handler);
@@ -849,8 +884,11 @@ static int ov9281_initialize_controls(st
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
- 0, OV9281_PIXEL_RATE, 1, OV9281_PIXEL_RATE);
+ ov9281->pixel_rate = v4l2_ctrl_new_std(handler, NULL,
+ V4L2_CID_PIXEL_RATE,
+ OV9281_PIXEL_RATE_10BIT,
+ OV9281_PIXEL_RATE_10BIT, 1,
+ OV9281_PIXEL_RATE_10BIT);
h_blank = mode->hts_def - mode->width;
ov9281->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
|