46826279452a93bcb7fd3cca0a6ee48aaf075caa
[openwrt/staging/ansuel.git] /
1 From 6efb946e6cb808c35e4fb620974c12244a95b4e7 Mon Sep 17 00:00:00 2001
2 From: Naushir Patuck <naush@raspberrypi.com>
3 Date: Fri, 31 Mar 2023 14:56:09 +0100
4 Subject: [PATCH] drivers: media: imx708: Increase usable link
5 frequencies
6
7 Add support for three different usable link frequencies (default 450Mhz,
8 447Mhz, and 453MHz) for the IMX708 camera sensor. The choice of
9 frequency is handled thorugh the "link-frequency" overlay parameter.
10
11 Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
12 ---
13 drivers/media/i2c/imx708.c | 94 +++++++++++++++++++++++++++++++-------
14 1 file changed, 78 insertions(+), 16 deletions(-)
15
16 --- a/drivers/media/i2c/imx708.c
17 +++ b/drivers/media/i2c/imx708.c
18 @@ -35,8 +35,6 @@
19
20 #define IMX708_XCLK_FREQ 24000000
21
22 -#define IMX708_DEFAULT_LINK_FREQ 450000000
23 -
24 /* Default initial pixel rate, will get updated for each mode. */
25 #define IMX708_INITIAL_PIXEL_RATE 590000000
26
27 @@ -181,6 +179,50 @@ static const u8 pdaf_gains[2][9] = {
28 { 0x35, 0x35, 0x35, 0x38, 0x3e, 0x46, 0x4c, 0x4c, 0x4c }
29 };
30
31 +/* Link frequency setup */
32 +enum {
33 + IMX708_LINK_FREQ_450MHZ,
34 + IMX708_LINK_FREQ_447MHZ,
35 + IMX708_LINK_FREQ_453MHZ,
36 +};
37 +
38 +static const s64 link_freqs[] = {
39 + [IMX708_LINK_FREQ_450MHZ] = 450000000,
40 + [IMX708_LINK_FREQ_447MHZ] = 447000000,
41 + [IMX708_LINK_FREQ_453MHZ] = 453000000,
42 +};
43 +
44 +/* 450MHz is the nominal "default" link frequency */
45 +static const struct imx708_reg link_450Mhz_regs[] = {
46 + {0x030E, 0x01},
47 + {0x030F, 0x2c},
48 +};
49 +
50 +static const struct imx708_reg link_447Mhz_regs[] = {
51 + {0x030E, 0x01},
52 + {0x030F, 0x2a},
53 +};
54 +
55 +static const struct imx708_reg link_453Mhz_regs[] = {
56 + {0x030E, 0x01},
57 + {0x030F, 0x2e},
58 +};
59 +
60 +static const struct imx708_reg_list link_freq_regs[] = {
61 + [IMX708_LINK_FREQ_450MHZ] = {
62 + .regs = link_450Mhz_regs,
63 + .num_of_regs = ARRAY_SIZE(link_450Mhz_regs)
64 + },
65 + [IMX708_LINK_FREQ_447MHZ] = {
66 + .regs = link_447Mhz_regs,
67 + .num_of_regs = ARRAY_SIZE(link_447Mhz_regs)
68 + },
69 + [IMX708_LINK_FREQ_453MHZ] = {
70 + .regs = link_453Mhz_regs,
71 + .num_of_regs = ARRAY_SIZE(link_453Mhz_regs)
72 + },
73 +};
74 +
75 static const struct imx708_reg mode_common_regs[] = {
76 {0x0100, 0x00},
77 {0x0136, 0x18},
78 @@ -278,8 +320,6 @@ static const struct imx708_reg mode_4608
79 {0x0307, 0x7C},
80 {0x030B, 0x02},
81 {0x030D, 0x04},
82 - {0x030E, 0x01},
83 - {0x030F, 0x2C},
84 {0x0310, 0x01},
85 {0x3CA0, 0x00},
86 {0x3CA1, 0x64},
87 @@ -376,8 +416,6 @@ static const struct imx708_reg mode_2x2b
88 {0x0307, 0x7A},
89 {0x030B, 0x02},
90 {0x030D, 0x04},
91 - {0x030E, 0x01},
92 - {0x030F, 0x2C},
93 {0x0310, 0x01},
94 {0x3CA0, 0x00},
95 {0x3CA1, 0x3C},
96 @@ -472,8 +510,6 @@ static const struct imx708_reg mode_2x2b
97 {0x0307, 0x76},
98 {0x030B, 0x02},
99 {0x030D, 0x04},
100 - {0x030E, 0x01},
101 - {0x030F, 0x2C},
102 {0x0310, 0x01},
103 {0x3CA0, 0x00},
104 {0x3CA1, 0x3C},
105 @@ -568,8 +604,6 @@ static const struct imx708_reg mode_hdr_
106 {0x0307, 0xA2},
107 {0x030B, 0x02},
108 {0x030D, 0x04},
109 - {0x030E, 0x01},
110 - {0x030F, 0x2C},
111 {0x0310, 0x01},
112 {0x3CA0, 0x00},
113 {0x3CA1, 0x00},
114 @@ -795,6 +829,7 @@ struct imx708 {
115 struct v4l2_ctrl *blue_balance;
116 struct v4l2_ctrl *notify_gains;
117 struct v4l2_ctrl *hdr_mode;
118 + struct v4l2_ctrl *link_freq;
119
120 /* Current mode */
121 const struct imx708_mode *mode;
122 @@ -813,6 +848,8 @@ struct imx708 {
123
124 /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
125 unsigned int long_exp_shift;
126 +
127 + unsigned int link_freq_idx;
128 };
129
130 static inline struct imx708 *to_imx708(struct v4l2_subdev *_sd)
131 @@ -1428,7 +1465,7 @@ static int imx708_get_selection(struct v
132 static int imx708_start_streaming(struct imx708 *imx708)
133 {
134 struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
135 - const struct imx708_reg_list *reg_list;
136 + const struct imx708_reg_list *reg_list, *freq_regs;
137 int i, ret;
138 u32 val;
139
140 @@ -1474,6 +1511,16 @@ static int imx708_start_streaming(struct
141 return ret;
142 }
143
144 + /* Update the link frequency registers */
145 + freq_regs = &link_freq_regs[imx708->link_freq_idx];
146 + ret = imx708_write_regs(imx708, freq_regs->regs,
147 + freq_regs->num_of_regs);
148 + if (ret) {
149 + dev_err(&client->dev, "%s failed to set link frequency registers\n",
150 + __func__);
151 + return ret;
152 + }
153 +
154 /* Apply customized values from user */
155 ret = __v4l2_ctrl_handler_setup(imx708->sd.ctrl_handler);
156 if (ret)
157 @@ -1720,6 +1767,7 @@ static int imx708_init_controls(struct i
158 struct v4l2_ctrl_handler *ctrl_hdlr;
159 struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
160 struct v4l2_fwnode_device_properties props;
161 + struct v4l2_ctrl *ctrl;
162 unsigned int i;
163 int ret;
164
165 @@ -1738,6 +1786,12 @@ static int imx708_init_controls(struct i
166 IMX708_INITIAL_PIXEL_RATE, 1,
167 IMX708_INITIAL_PIXEL_RATE);
168
169 + ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx708_ctrl_ops,
170 + V4L2_CID_LINK_FREQ, 0, 0,
171 + &link_freqs[imx708->link_freq_idx]);
172 + if (ctrl)
173 + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
174 +
175 /*
176 * Create the controls here, but mode specific limits are setup
177 * in the imx708_set_framing_limits() call below.
178 @@ -1833,13 +1887,14 @@ static void imx708_free_controls(struct
179 mutex_destroy(&imx708->mutex);
180 }
181
182 -static int imx708_check_hwcfg(struct device *dev)
183 +static int imx708_check_hwcfg(struct device *dev, struct imx708 *imx708)
184 {
185 struct fwnode_handle *endpoint;
186 struct v4l2_fwnode_endpoint ep_cfg = {
187 .bus_type = V4L2_MBUS_CSI2_DPHY
188 };
189 int ret = -EINVAL;
190 + int i;
191
192 endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
193 if (!endpoint) {
194 @@ -1864,11 +1919,18 @@ static int imx708_check_hwcfg(struct dev
195 goto error_out;
196 }
197
198 - if (ep_cfg.nr_of_link_frequencies != 1 ||
199 - ep_cfg.link_frequencies[0] != IMX708_DEFAULT_LINK_FREQ) {
200 + for (i = 0; i < ARRAY_SIZE(link_freqs); i++) {
201 + if (link_freqs[i] == ep_cfg.link_frequencies[0]) {
202 + imx708->link_freq_idx = i;
203 + break;
204 + }
205 + }
206 +
207 + if (i == ARRAY_SIZE(link_freqs)) {
208 dev_err(dev, "Link frequency not supported: %lld\n",
209 ep_cfg.link_frequencies[0]);
210 - goto error_out;
211 + ret = -EINVAL;
212 + goto error_out;
213 }
214
215 ret = 0;
216 @@ -1893,7 +1955,7 @@ static int imx708_probe(struct i2c_clien
217 v4l2_i2c_subdev_init(&imx708->sd, client, &imx708_subdev_ops);
218
219 /* Check the hardware configuration in device tree */
220 - if (imx708_check_hwcfg(dev))
221 + if (imx708_check_hwcfg(dev, imx708))
222 return -EINVAL;
223
224 /* Get system clock (xclk) */