Commit | Line | Data |
---|---|---|
e58f3082 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
3e89586a KB |
2 | /* |
3 | * Driver for Analog Devices ADV748X HDMI receiver with AFE | |
4 | * | |
5 | * Copyright (C) 2017 Renesas Electronics Corp. | |
6 | * | |
3e89586a KB |
7 | * Authors: |
8 | * Koji Matsuoka <koji.matsuoka.xm@renesas.com> | |
9 | * Niklas Söderlund <niklas.soderlund@ragnatech.se> | |
10 | * Kieran Bingham <kieran.bingham@ideasonboard.com> | |
11 | */ | |
12 | ||
13 | #include <linux/delay.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/i2c.h> | |
16 | #include <linux/module.h> | |
17 | #include <linux/mutex.h> | |
18 | #include <linux/of_graph.h> | |
19 | #include <linux/regmap.h> | |
20 | #include <linux/slab.h> | |
21 | #include <linux/v4l2-dv-timings.h> | |
22 | ||
23 | #include <media/v4l2-ctrls.h> | |
24 | #include <media/v4l2-device.h> | |
25 | #include <media/v4l2-dv-timings.h> | |
6a18865d | 26 | #include <media/v4l2-fwnode.h> |
3e89586a KB |
27 | #include <media/v4l2-ioctl.h> |
28 | ||
29 | #include "adv748x.h" | |
30 | ||
31 | /* ----------------------------------------------------------------------------- | |
32 | * Register manipulation | |
33 | */ | |
34 | ||
06aa8f3a KB |
35 | #define ADV748X_REGMAP_CONF(n) \ |
36 | { \ | |
37 | .name = n, \ | |
38 | .reg_bits = 8, \ | |
39 | .val_bits = 8, \ | |
40 | .max_register = 0xff, \ | |
41 | .cache_type = REGCACHE_NONE, \ | |
42 | } | |
3e89586a | 43 | |
06aa8f3a KB |
44 | static const struct regmap_config adv748x_regmap_cnf[] = { |
45 | ADV748X_REGMAP_CONF("io"), | |
46 | ADV748X_REGMAP_CONF("dpll"), | |
47 | ADV748X_REGMAP_CONF("cp"), | |
48 | ADV748X_REGMAP_CONF("hdmi"), | |
49 | ADV748X_REGMAP_CONF("edid"), | |
50 | ADV748X_REGMAP_CONF("repeater"), | |
51 | ADV748X_REGMAP_CONF("infoframe"), | |
71569850 | 52 | ADV748X_REGMAP_CONF("cbus"), |
06aa8f3a KB |
53 | ADV748X_REGMAP_CONF("cec"), |
54 | ADV748X_REGMAP_CONF("sdp"), | |
55 | ADV748X_REGMAP_CONF("txa"), | |
56 | ADV748X_REGMAP_CONF("txb"), | |
3e89586a KB |
57 | }; |
58 | ||
59 | static int adv748x_configure_regmap(struct adv748x_state *state, int region) | |
60 | { | |
61 | int err; | |
62 | ||
63 | if (!state->i2c_clients[region]) | |
64 | return -ENODEV; | |
65 | ||
66 | state->regmap[region] = | |
67 | devm_regmap_init_i2c(state->i2c_clients[region], | |
68 | &adv748x_regmap_cnf[region]); | |
69 | ||
70 | if (IS_ERR(state->regmap[region])) { | |
71 | err = PTR_ERR(state->regmap[region]); | |
72 | adv_err(state, | |
73 | "Error initializing regmap %d with error %d\n", | |
74 | region, err); | |
75 | return -EINVAL; | |
76 | } | |
77 | ||
78 | return 0; | |
79 | } | |
67537fe9 KB |
80 | struct adv748x_register_map { |
81 | const char *name; | |
82 | u8 default_addr; | |
83 | }; | |
3e89586a | 84 | |
67537fe9 KB |
85 | static const struct adv748x_register_map adv748x_default_addresses[] = { |
86 | [ADV748X_PAGE_IO] = { "main", 0x70 }, | |
87 | [ADV748X_PAGE_DPLL] = { "dpll", 0x26 }, | |
88 | [ADV748X_PAGE_CP] = { "cp", 0x22 }, | |
89 | [ADV748X_PAGE_HDMI] = { "hdmi", 0x34 }, | |
90 | [ADV748X_PAGE_EDID] = { "edid", 0x36 }, | |
91 | [ADV748X_PAGE_REPEATER] = { "repeater", 0x32 }, | |
92 | [ADV748X_PAGE_INFOFRAME] = { "infoframe", 0x31 }, | |
93 | [ADV748X_PAGE_CBUS] = { "cbus", 0x30 }, | |
94 | [ADV748X_PAGE_CEC] = { "cec", 0x41 }, | |
95 | [ADV748X_PAGE_SDP] = { "sdp", 0x79 }, | |
96 | [ADV748X_PAGE_TXB] = { "txb", 0x48 }, | |
97 | [ADV748X_PAGE_TXA] = { "txa", 0x4a }, | |
3e89586a KB |
98 | }; |
99 | ||
100 | static int adv748x_read_check(struct adv748x_state *state, | |
101 | int client_page, u8 reg) | |
102 | { | |
103 | struct i2c_client *client = state->i2c_clients[client_page]; | |
104 | int err; | |
105 | unsigned int val; | |
106 | ||
107 | err = regmap_read(state->regmap[client_page], reg, &val); | |
108 | ||
109 | if (err) { | |
110 | adv_err(state, "error reading %02x, %02x\n", | |
111 | client->addr, reg); | |
112 | return err; | |
113 | } | |
114 | ||
115 | return val; | |
116 | } | |
117 | ||
118 | int adv748x_read(struct adv748x_state *state, u8 page, u8 reg) | |
119 | { | |
120 | return adv748x_read_check(state, page, reg); | |
121 | } | |
122 | ||
123 | int adv748x_write(struct adv748x_state *state, u8 page, u8 reg, u8 value) | |
124 | { | |
125 | return regmap_write(state->regmap[page], reg, value); | |
126 | } | |
127 | ||
0ad5b80c NS |
128 | static int adv748x_write_check(struct adv748x_state *state, u8 page, u8 reg, |
129 | u8 value, int *error) | |
130 | { | |
131 | if (*error) | |
132 | return *error; | |
133 | ||
134 | *error = adv748x_write(state, page, reg, value); | |
135 | return *error; | |
136 | } | |
137 | ||
3e89586a KB |
138 | /* adv748x_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX |
139 | * size to one or more registers. | |
140 | * | |
141 | * A value of zero will be returned on success, a negative errno will | |
142 | * be returned in error cases. | |
143 | */ | |
144 | int adv748x_write_block(struct adv748x_state *state, int client_page, | |
145 | unsigned int init_reg, const void *val, | |
146 | size_t val_len) | |
147 | { | |
148 | struct regmap *regmap = state->regmap[client_page]; | |
149 | ||
150 | if (val_len > I2C_SMBUS_BLOCK_MAX) | |
151 | val_len = I2C_SMBUS_BLOCK_MAX; | |
152 | ||
153 | return regmap_raw_write(regmap, init_reg, val, val_len); | |
154 | } | |
155 | ||
67537fe9 | 156 | static int adv748x_set_slave_addresses(struct adv748x_state *state) |
3e89586a | 157 | { |
67537fe9 KB |
158 | struct i2c_client *client; |
159 | unsigned int i; | |
160 | u8 io_reg; | |
161 | ||
162 | for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { | |
163 | io_reg = ADV748X_IO_SLAVE_ADDR_BASE + i; | |
164 | client = state->i2c_clients[i]; | |
3e89586a | 165 | |
67537fe9 KB |
166 | io_write(state, io_reg, client->addr << 1); |
167 | } | |
3e89586a | 168 | |
67537fe9 | 169 | return 0; |
3e89586a KB |
170 | } |
171 | ||
172 | static void adv748x_unregister_clients(struct adv748x_state *state) | |
173 | { | |
174 | unsigned int i; | |
175 | ||
5195978f AS |
176 | for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) |
177 | i2c_unregister_device(state->i2c_clients[i]); | |
3e89586a KB |
178 | } |
179 | ||
180 | static int adv748x_initialise_clients(struct adv748x_state *state) | |
181 | { | |
67537fe9 | 182 | unsigned int i; |
3e89586a KB |
183 | int ret; |
184 | ||
185 | for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { | |
af80559b | 186 | state->i2c_clients[i] = i2c_new_ancillary_device( |
67537fe9 KB |
187 | state->client, |
188 | adv748x_default_addresses[i].name, | |
189 | adv748x_default_addresses[i].default_addr); | |
190 | ||
af80559b | 191 | if (IS_ERR(state->i2c_clients[i])) { |
3e89586a | 192 | adv_err(state, "failed to create i2c client %u\n", i); |
af80559b | 193 | return PTR_ERR(state->i2c_clients[i]); |
3e89586a KB |
194 | } |
195 | ||
196 | ret = adv748x_configure_regmap(state, i); | |
197 | if (ret) | |
198 | return ret; | |
199 | } | |
200 | ||
67537fe9 | 201 | return adv748x_set_slave_addresses(state); |
3e89586a KB |
202 | } |
203 | ||
204 | /** | |
205 | * struct adv748x_reg_value - Register write instruction | |
206 | * @page: Regmap page identifier | |
207 | * @reg: I2C register | |
208 | * @value: value to write to @page at @reg | |
209 | */ | |
210 | struct adv748x_reg_value { | |
211 | u8 page; | |
212 | u8 reg; | |
213 | u8 value; | |
214 | }; | |
215 | ||
216 | static int adv748x_write_regs(struct adv748x_state *state, | |
217 | const struct adv748x_reg_value *regs) | |
218 | { | |
219 | int ret; | |
220 | ||
16597c27 KB |
221 | for (; regs->page != ADV748X_PAGE_EOR; regs++) { |
222 | ret = adv748x_write(state, regs->page, regs->reg, regs->value); | |
223 | if (ret < 0) { | |
224 | adv_err(state, "Error regs page: 0x%02x reg: 0x%02x\n", | |
225 | regs->page, regs->reg); | |
226 | return ret; | |
3e89586a | 227 | } |
3e89586a KB |
228 | } |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | /* ----------------------------------------------------------------------------- | |
234 | * TXA and TXB | |
235 | */ | |
236 | ||
0ad5b80c NS |
237 | static int adv748x_power_up_tx(struct adv748x_csi2 *tx) |
238 | { | |
239 | struct adv748x_state *state = tx->state; | |
240 | u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; | |
241 | int ret = 0; | |
3e89586a | 242 | |
0ad5b80c | 243 | /* Enable n-lane MIPI */ |
147d5ea1 | 244 | adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); |
3e89586a | 245 | |
0ad5b80c | 246 | /* Set Auto DPHY Timing */ |
147d5ea1 | 247 | adv748x_write_check(state, page, 0x00, 0xa0 | tx->active_lanes, &ret); |
3e89586a | 248 | |
0ad5b80c | 249 | /* ADI Required Write */ |
3361b9c4 | 250 | if (tx->src == &state->hdmi.sd) { |
0ad5b80c NS |
251 | adv748x_write_check(state, page, 0xdb, 0x10, &ret); |
252 | adv748x_write_check(state, page, 0xd6, 0x07, &ret); | |
253 | } else { | |
254 | adv748x_write_check(state, page, 0xd2, 0x40, &ret); | |
255 | } | |
3e89586a | 256 | |
0ad5b80c NS |
257 | adv748x_write_check(state, page, 0xc4, 0x0a, &ret); |
258 | adv748x_write_check(state, page, 0x71, 0x33, &ret); | |
259 | adv748x_write_check(state, page, 0x72, 0x11, &ret); | |
3e89586a | 260 | |
0ad5b80c NS |
261 | /* i2c_dphy_pwdn - 1'b0 */ |
262 | adv748x_write_check(state, page, 0xf0, 0x00, &ret); | |
3e89586a | 263 | |
0ad5b80c NS |
264 | /* ADI Required Writes*/ |
265 | adv748x_write_check(state, page, 0x31, 0x82, &ret); | |
266 | adv748x_write_check(state, page, 0x1e, 0x40, &ret); | |
3e89586a | 267 | |
0ad5b80c NS |
268 | /* i2c_mipi_pll_en - 1'b1 */ |
269 | adv748x_write_check(state, page, 0xda, 0x01, &ret); | |
270 | usleep_range(2000, 2500); | |
3e89586a | 271 | |
0ad5b80c | 272 | /* Power-up CSI-TX */ |
147d5ea1 | 273 | adv748x_write_check(state, page, 0x00, 0x20 | tx->active_lanes, &ret); |
0ad5b80c NS |
274 | usleep_range(1000, 1500); |
275 | ||
276 | /* ADI Required Writes */ | |
277 | adv748x_write_check(state, page, 0xc1, 0x2b, &ret); | |
278 | usleep_range(1000, 1500); | |
279 | adv748x_write_check(state, page, 0x31, 0x80, &ret); | |
280 | ||
281 | return ret; | |
282 | } | |
283 | ||
284 | static int adv748x_power_down_tx(struct adv748x_csi2 *tx) | |
3e89586a | 285 | { |
6bc3ea7a | 286 | struct adv748x_state *state = tx->state; |
0ad5b80c NS |
287 | u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; |
288 | int ret = 0; | |
289 | ||
290 | /* ADI Required Writes */ | |
291 | adv748x_write_check(state, page, 0x31, 0x82, &ret); | |
292 | adv748x_write_check(state, page, 0x1e, 0x00, &ret); | |
293 | ||
294 | /* Enable n-lane MIPI */ | |
147d5ea1 | 295 | adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); |
0ad5b80c NS |
296 | |
297 | /* i2c_mipi_pll_en - 1'b1 */ | |
298 | adv748x_write_check(state, page, 0xda, 0x01, &ret); | |
299 | ||
300 | /* ADI Required Write */ | |
301 | adv748x_write_check(state, page, 0xc1, 0x3b, &ret); | |
302 | ||
303 | return ret; | |
304 | } | |
305 | ||
306 | int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) | |
307 | { | |
3e89586a KB |
308 | int val; |
309 | ||
6bc3ea7a JM |
310 | if (!is_tx_enabled(tx)) |
311 | return 0; | |
3e89586a | 312 | |
6bc3ea7a | 313 | val = tx_read(tx, ADV748X_CSI_FS_AS_LS); |
3e89586a KB |
314 | if (val < 0) |
315 | return val; | |
316 | ||
317 | /* | |
318 | * This test against BIT(6) is not documented by the datasheet, but was | |
319 | * specified in the downstream driver. | |
320 | * Track with a WARN_ONCE to determine if it is ever set by HW. | |
321 | */ | |
322 | WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), | |
323 | "Enabling with unknown bit set"); | |
324 | ||
0ad5b80c | 325 | return on ? adv748x_power_up_tx(tx) : adv748x_power_down_tx(tx); |
3e89586a KB |
326 | } |
327 | ||
328 | /* ----------------------------------------------------------------------------- | |
329 | * Media Operations | |
330 | */ | |
9423ca35 JM |
331 | static int adv748x_link_setup(struct media_entity *entity, |
332 | const struct media_pad *local, | |
333 | const struct media_pad *remote, u32 flags) | |
334 | { | |
335 | struct v4l2_subdev *rsd = media_entity_to_v4l2_subdev(remote->entity); | |
336 | struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); | |
337 | struct adv748x_state *state = v4l2_get_subdevdata(sd); | |
338 | struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); | |
339 | bool enable = flags & MEDIA_LNK_FL_ENABLED; | |
340 | u8 io10_mask = ADV748X_IO_10_CSI1_EN | | |
341 | ADV748X_IO_10_CSI4_EN | | |
342 | ADV748X_IO_10_CSI4_IN_SEL_AFE; | |
343 | u8 io10 = 0; | |
344 | ||
345 | /* Refuse to enable multiple links to the same TX at the same time. */ | |
346 | if (enable && tx->src) | |
347 | return -EINVAL; | |
348 | ||
349 | /* Set or clear the source (HDMI or AFE) and the current TX. */ | |
350 | if (rsd == &state->afe.sd) | |
351 | state->afe.tx = enable ? tx : NULL; | |
352 | else | |
353 | state->hdmi.tx = enable ? tx : NULL; | |
354 | ||
355 | tx->src = enable ? rsd : NULL; | |
356 | ||
357 | if (state->afe.tx) { | |
358 | /* AFE Requires TXA enabled, even when output to TXB */ | |
359 | io10 |= ADV748X_IO_10_CSI4_EN; | |
147d5ea1 JM |
360 | if (is_txa(tx)) { |
361 | /* | |
362 | * Output from the SD-core (480i and 576i) from the TXA | |
363 | * interface requires reducing the number of enabled | |
364 | * data lanes in order to guarantee a valid link | |
365 | * frequency. | |
366 | */ | |
367 | tx->active_lanes = min(tx->num_lanes, 2U); | |
9423ca35 | 368 | io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE; |
147d5ea1 JM |
369 | } else { |
370 | /* TXB has a single data lane, no need to adjust. */ | |
9423ca35 | 371 | io10 |= ADV748X_IO_10_CSI1_EN; |
147d5ea1 | 372 | } |
9423ca35 JM |
373 | } |
374 | ||
147d5ea1 JM |
375 | if (state->hdmi.tx) { |
376 | /* | |
377 | * Restore the number of active lanes, in case we have gone | |
378 | * through an AFE->TXA streaming sessions. | |
379 | */ | |
380 | tx->active_lanes = tx->num_lanes; | |
9423ca35 | 381 | io10 |= ADV748X_IO_10_CSI4_EN; |
147d5ea1 | 382 | } |
9423ca35 JM |
383 | |
384 | return io_clrset(state, ADV748X_IO_10, io10_mask, io10); | |
385 | } | |
386 | ||
387 | static const struct media_entity_operations adv748x_tx_media_ops = { | |
388 | .link_setup = adv748x_link_setup, | |
389 | .link_validate = v4l2_subdev_link_validate, | |
390 | }; | |
3e89586a KB |
391 | |
392 | static const struct media_entity_operations adv748x_media_ops = { | |
393 | .link_validate = v4l2_subdev_link_validate, | |
394 | }; | |
395 | ||
396 | /* ----------------------------------------------------------------------------- | |
397 | * HW setup | |
398 | */ | |
399 | ||
29166e0f JM |
400 | /* Initialize CP Core with RGB888 format. */ |
401 | static const struct adv748x_reg_value adv748x_init_hdmi[] = { | |
3e89586a KB |
402 | /* Disable chip powerdown & Enable HDMI Rx block */ |
403 | {ADV748X_PAGE_IO, 0x00, 0x40}, | |
404 | ||
405 | {ADV748X_PAGE_REPEATER, 0x40, 0x83}, /* Enable HDCP 1.1 */ | |
406 | ||
407 | {ADV748X_PAGE_HDMI, 0x00, 0x08},/* Foreground Channel = A */ | |
408 | {ADV748X_PAGE_HDMI, 0x98, 0xff},/* ADI Required Write */ | |
409 | {ADV748X_PAGE_HDMI, 0x99, 0xa3},/* ADI Required Write */ | |
410 | {ADV748X_PAGE_HDMI, 0x9a, 0x00},/* ADI Required Write */ | |
411 | {ADV748X_PAGE_HDMI, 0x9b, 0x0a},/* ADI Required Write */ | |
412 | {ADV748X_PAGE_HDMI, 0x9d, 0x40},/* ADI Required Write */ | |
413 | {ADV748X_PAGE_HDMI, 0xcb, 0x09},/* ADI Required Write */ | |
414 | {ADV748X_PAGE_HDMI, 0x3d, 0x10},/* ADI Required Write */ | |
415 | {ADV748X_PAGE_HDMI, 0x3e, 0x7b},/* ADI Required Write */ | |
416 | {ADV748X_PAGE_HDMI, 0x3f, 0x5e},/* ADI Required Write */ | |
417 | {ADV748X_PAGE_HDMI, 0x4e, 0xfe},/* ADI Required Write */ | |
418 | {ADV748X_PAGE_HDMI, 0x4f, 0x18},/* ADI Required Write */ | |
419 | {ADV748X_PAGE_HDMI, 0x57, 0xa3},/* ADI Required Write */ | |
420 | {ADV748X_PAGE_HDMI, 0x58, 0x04},/* ADI Required Write */ | |
421 | {ADV748X_PAGE_HDMI, 0x85, 0x10},/* ADI Required Write */ | |
422 | ||
423 | {ADV748X_PAGE_HDMI, 0x83, 0x00},/* Enable All Terminations */ | |
424 | {ADV748X_PAGE_HDMI, 0xa3, 0x01},/* ADI Required Write */ | |
425 | {ADV748X_PAGE_HDMI, 0xbe, 0x00},/* ADI Required Write */ | |
426 | ||
427 | {ADV748X_PAGE_HDMI, 0x6c, 0x01},/* HPA Manual Enable */ | |
428 | {ADV748X_PAGE_HDMI, 0xf8, 0x01},/* HPA Asserted */ | |
429 | {ADV748X_PAGE_HDMI, 0x0f, 0x00},/* Audio Mute Speed Set to Fastest */ | |
430 | /* (Smallest Step Size) */ | |
431 | ||
432 | {ADV748X_PAGE_IO, 0x04, 0x02}, /* RGB Out of CP */ | |
433 | {ADV748X_PAGE_IO, 0x12, 0xf0}, /* CSC Depends on ip Packets, SDR 444 */ | |
434 | {ADV748X_PAGE_IO, 0x17, 0x80}, /* Luma & Chroma can reach 254d */ | |
435 | {ADV748X_PAGE_IO, 0x03, 0x86}, /* CP-Insert_AV_Code */ | |
436 | ||
437 | {ADV748X_PAGE_CP, 0x7c, 0x00}, /* ADI Required Write */ | |
438 | ||
439 | {ADV748X_PAGE_IO, 0x0c, 0xe0}, /* Enable LLC_DLL & Double LLC Timing */ | |
440 | {ADV748X_PAGE_IO, 0x0e, 0xdd}, /* LLC/PIX/SPI PINS TRISTATED AUD */ | |
3e89586a | 441 | |
3e89586a KB |
442 | {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ |
443 | }; | |
444 | ||
29166e0f JM |
445 | /* Initialize AFE core with YUV8 format. */ |
446 | static const struct adv748x_reg_value adv748x_init_afe[] = { | |
3e89586a KB |
447 | {ADV748X_PAGE_IO, 0x00, 0x30}, /* Disable chip powerdown Rx */ |
448 | {ADV748X_PAGE_IO, 0xf2, 0x01}, /* Enable I2C Read Auto-Increment */ | |
449 | ||
450 | {ADV748X_PAGE_IO, 0x0e, 0xff}, /* LLC/PIX/AUD/SPI PINS TRISTATED */ | |
451 | ||
452 | {ADV748X_PAGE_SDP, 0x0f, 0x00}, /* Exit Power Down Mode */ | |
453 | {ADV748X_PAGE_SDP, 0x52, 0xcd}, /* ADI Required Write */ | |
454 | ||
455 | {ADV748X_PAGE_SDP, 0x0e, 0x80}, /* ADI Required Write */ | |
456 | {ADV748X_PAGE_SDP, 0x9c, 0x00}, /* ADI Required Write */ | |
457 | {ADV748X_PAGE_SDP, 0x9c, 0xff}, /* ADI Required Write */ | |
458 | {ADV748X_PAGE_SDP, 0x0e, 0x00}, /* ADI Required Write */ | |
459 | ||
460 | /* ADI recommended writes for improved video quality */ | |
461 | {ADV748X_PAGE_SDP, 0x80, 0x51}, /* ADI Required Write */ | |
462 | {ADV748X_PAGE_SDP, 0x81, 0x51}, /* ADI Required Write */ | |
463 | {ADV748X_PAGE_SDP, 0x82, 0x68}, /* ADI Required Write */ | |
464 | ||
465 | {ADV748X_PAGE_SDP, 0x03, 0x42}, /* Tri-S Output , PwrDwn 656 pads */ | |
466 | {ADV748X_PAGE_SDP, 0x04, 0xb5}, /* ITU-R BT.656-4 compatible */ | |
467 | {ADV748X_PAGE_SDP, 0x13, 0x00}, /* ADI Required Write */ | |
468 | ||
469 | {ADV748X_PAGE_SDP, 0x17, 0x41}, /* Select SH1 */ | |
470 | {ADV748X_PAGE_SDP, 0x31, 0x12}, /* ADI Required Write */ | |
471 | {ADV748X_PAGE_SDP, 0xe6, 0x4f}, /* V bit end pos manually in NTSC */ | |
472 | ||
3e89586a KB |
473 | {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ |
474 | }; | |
475 | ||
ac105ab2 KB |
476 | static int adv748x_sw_reset(struct adv748x_state *state) |
477 | { | |
478 | int ret; | |
479 | ||
480 | ret = io_write(state, ADV748X_IO_REG_FF, ADV748X_IO_REG_FF_MAIN_RESET); | |
481 | if (ret) | |
482 | return ret; | |
483 | ||
484 | usleep_range(5000, 6000); | |
485 | ||
486 | /* Disable CEC Wakeup from power-down mode */ | |
487 | ret = io_clrset(state, ADV748X_IO_REG_01, ADV748X_IO_REG_01_PWRDN_MASK, | |
488 | ADV748X_IO_REG_01_PWRDNB); | |
489 | if (ret) | |
490 | return ret; | |
491 | ||
492 | /* Enable I2C Read Auto-Increment for consecutive reads */ | |
493 | return io_write(state, ADV748X_IO_REG_F2, | |
494 | ADV748X_IO_REG_F2_READ_AUTO_INC); | |
495 | } | |
496 | ||
3e89586a KB |
497 | static int adv748x_reset(struct adv748x_state *state) |
498 | { | |
499 | int ret; | |
a7f9d21e | 500 | u8 regval = 0; |
3e89586a | 501 | |
ac105ab2 | 502 | ret = adv748x_sw_reset(state); |
3e89586a KB |
503 | if (ret < 0) |
504 | return ret; | |
505 | ||
67537fe9 | 506 | ret = adv748x_set_slave_addresses(state); |
3e89586a KB |
507 | if (ret < 0) |
508 | return ret; | |
509 | ||
29166e0f JM |
510 | /* Initialize CP and AFE cores. */ |
511 | ret = adv748x_write_regs(state, adv748x_init_hdmi); | |
3e89586a KB |
512 | if (ret) |
513 | return ret; | |
514 | ||
29166e0f | 515 | ret = adv748x_write_regs(state, adv748x_init_afe); |
3e89586a KB |
516 | if (ret) |
517 | return ret; | |
518 | ||
29166e0f JM |
519 | /* Reset TXA and TXB */ |
520 | adv748x_tx_power(&state->txa, 1); | |
521 | adv748x_tx_power(&state->txa, 0); | |
90917bc8 | 522 | adv748x_tx_power(&state->txb, 1); |
6bc3ea7a | 523 | adv748x_tx_power(&state->txb, 0); |
3e89586a KB |
524 | |
525 | /* Disable chip powerdown & Enable HDMI Rx block */ | |
526 | io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN); | |
527 | ||
6bc3ea7a JM |
528 | /* Conditionally enable TXa and TXb. */ |
529 | if (is_tx_enabled(&state->txa)) | |
530 | regval |= ADV748X_IO_10_CSI4_EN; | |
531 | if (is_tx_enabled(&state->txb)) | |
532 | regval |= ADV748X_IO_10_CSI1_EN; | |
533 | io_write(state, ADV748X_IO_10, regval); | |
3e89586a KB |
534 | |
535 | /* Use vid_std and v_freq as freerun resolution for CP */ | |
536 | cp_clrset(state, ADV748X_CP_CLMP_POS, ADV748X_CP_CLMP_POS_DIS_AUTO, | |
537 | ADV748X_CP_CLMP_POS_DIS_AUTO); | |
538 | ||
539 | return 0; | |
540 | } | |
541 | ||
542 | static int adv748x_identify_chip(struct adv748x_state *state) | |
543 | { | |
544 | int msb, lsb; | |
545 | ||
546 | lsb = io_read(state, ADV748X_IO_CHIP_REV_ID_1); | |
547 | msb = io_read(state, ADV748X_IO_CHIP_REV_ID_2); | |
548 | ||
549 | if (lsb < 0 || msb < 0) { | |
550 | adv_err(state, "Failed to read chip revision\n"); | |
551 | return -EIO; | |
552 | } | |
553 | ||
554 | adv_info(state, "chip found @ 0x%02x revision %02x%02x\n", | |
555 | state->client->addr << 1, lsb, msb); | |
556 | ||
557 | return 0; | |
558 | } | |
559 | ||
560 | /* ----------------------------------------------------------------------------- | |
561 | * i2c driver | |
562 | */ | |
563 | ||
564 | void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state, | |
565 | const struct v4l2_subdev_ops *ops, u32 function, | |
566 | const char *ident) | |
567 | { | |
568 | v4l2_subdev_init(sd, ops); | |
569 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
570 | ||
571 | /* the owner is the same as the i2c_client's driver owner */ | |
572 | sd->owner = state->dev->driver->owner; | |
573 | sd->dev = state->dev; | |
574 | ||
575 | v4l2_set_subdevdata(sd, state); | |
576 | ||
577 | /* initialize name */ | |
578 | snprintf(sd->name, sizeof(sd->name), "%s %d-%04x %s", | |
579 | state->dev->driver->name, | |
580 | i2c_adapter_id(state->client->adapter), | |
581 | state->client->addr, ident); | |
582 | ||
583 | sd->entity.function = function; | |
9423ca35 JM |
584 | sd->entity.ops = is_tx(adv748x_sd_to_csi2(sd)) ? |
585 | &adv748x_tx_media_ops : &adv748x_media_ops; | |
3e89586a KB |
586 | } |
587 | ||
6a18865d NS |
588 | static int adv748x_parse_csi2_lanes(struct adv748x_state *state, |
589 | unsigned int port, | |
590 | struct device_node *ep) | |
591 | { | |
592 | struct v4l2_fwnode_endpoint vep; | |
593 | unsigned int num_lanes; | |
594 | int ret; | |
595 | ||
596 | if (port != ADV748X_PORT_TXA && port != ADV748X_PORT_TXB) | |
597 | return 0; | |
598 | ||
599 | vep.bus_type = V4L2_MBUS_CSI2_DPHY; | |
600 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &vep); | |
601 | if (ret) | |
602 | return ret; | |
603 | ||
604 | num_lanes = vep.bus.mipi_csi2.num_data_lanes; | |
605 | ||
606 | if (vep.base.port == ADV748X_PORT_TXA) { | |
607 | if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4) { | |
608 | adv_err(state, "TXA: Invalid number (%u) of lanes\n", | |
609 | num_lanes); | |
610 | return -EINVAL; | |
611 | } | |
612 | ||
613 | state->txa.num_lanes = num_lanes; | |
147d5ea1 | 614 | state->txa.active_lanes = num_lanes; |
6a18865d NS |
615 | adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes); |
616 | } | |
617 | ||
618 | if (vep.base.port == ADV748X_PORT_TXB) { | |
619 | if (num_lanes != 1) { | |
620 | adv_err(state, "TXB: Invalid number (%u) of lanes\n", | |
621 | num_lanes); | |
622 | return -EINVAL; | |
623 | } | |
624 | ||
625 | state->txb.num_lanes = num_lanes; | |
147d5ea1 | 626 | state->txb.active_lanes = num_lanes; |
6a18865d NS |
627 | adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes); |
628 | } | |
629 | ||
630 | return 0; | |
631 | } | |
632 | ||
3e89586a KB |
633 | static int adv748x_parse_dt(struct adv748x_state *state) |
634 | { | |
635 | struct device_node *ep_np = NULL; | |
636 | struct of_endpoint ep; | |
eccf442c JM |
637 | bool out_found = false; |
638 | bool in_found = false; | |
6a18865d | 639 | int ret; |
3e89586a KB |
640 | |
641 | for_each_endpoint_of_node(state->dev->of_node, ep_np) { | |
642 | of_graph_parse_endpoint(ep_np, &ep); | |
0ff6c131 GU |
643 | adv_info(state, "Endpoint %pOF on port %d", ep.local_node, |
644 | ep.port); | |
3e89586a KB |
645 | |
646 | if (ep.port >= ADV748X_PORT_MAX) { | |
0ff6c131 GU |
647 | adv_err(state, "Invalid endpoint %pOF on port %d", |
648 | ep.local_node, ep.port); | |
3e89586a KB |
649 | |
650 | continue; | |
651 | } | |
652 | ||
653 | if (state->endpoints[ep.port]) { | |
654 | adv_err(state, | |
655 | "Multiple port endpoints are not supported"); | |
656 | continue; | |
657 | } | |
658 | ||
659 | of_node_get(ep_np); | |
660 | state->endpoints[ep.port] = ep_np; | |
661 | ||
eccf442c JM |
662 | /* |
663 | * At least one input endpoint and one output endpoint shall | |
664 | * be defined. | |
665 | */ | |
666 | if (ep.port < ADV748X_PORT_TXA) | |
667 | in_found = true; | |
668 | else | |
669 | out_found = true; | |
6a18865d NS |
670 | |
671 | /* Store number of CSI-2 lanes used for TXA and TXB. */ | |
672 | ret = adv748x_parse_csi2_lanes(state, ep.port, ep_np); | |
673 | if (ret) | |
674 | return ret; | |
3e89586a KB |
675 | } |
676 | ||
eccf442c | 677 | return in_found && out_found ? 0 : -ENODEV; |
3e89586a KB |
678 | } |
679 | ||
680 | static void adv748x_dt_cleanup(struct adv748x_state *state) | |
681 | { | |
682 | unsigned int i; | |
683 | ||
684 | for (i = 0; i < ADV748X_PORT_MAX; i++) | |
685 | of_node_put(state->endpoints[i]); | |
686 | } | |
687 | ||
9deff920 | 688 | static int adv748x_probe(struct i2c_client *client) |
3e89586a KB |
689 | { |
690 | struct adv748x_state *state; | |
691 | int ret; | |
692 | ||
693 | /* Check if the adapter supports the needed features */ | |
694 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
695 | return -EIO; | |
696 | ||
fb517583 | 697 | state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); |
3e89586a KB |
698 | if (!state) |
699 | return -ENOMEM; | |
700 | ||
701 | mutex_init(&state->mutex); | |
702 | ||
703 | state->dev = &client->dev; | |
704 | state->client = client; | |
705 | state->i2c_clients[ADV748X_PAGE_IO] = client; | |
706 | i2c_set_clientdata(client, state); | |
707 | ||
eccf442c JM |
708 | /* |
709 | * We can not use container_of to get back to the state with two TXs; | |
710 | * Initialize the TXs's fields unconditionally on the endpoint | |
711 | * presence to access them later. | |
712 | */ | |
713 | state->txa.state = state->txb.state = state; | |
714 | state->txa.page = ADV748X_PAGE_TXA; | |
715 | state->txb.page = ADV748X_PAGE_TXB; | |
716 | state->txa.port = ADV748X_PORT_TXA; | |
717 | state->txb.port = ADV748X_PORT_TXB; | |
718 | ||
3e89586a KB |
719 | /* Discover and process ports declared by the Device tree endpoints */ |
720 | ret = adv748x_parse_dt(state); | |
721 | if (ret) { | |
722 | adv_err(state, "Failed to parse device tree"); | |
723 | goto err_free_mutex; | |
724 | } | |
725 | ||
726 | /* Configure IO Regmap region */ | |
727 | ret = adv748x_configure_regmap(state, ADV748X_PAGE_IO); | |
728 | if (ret) { | |
729 | adv_err(state, "Error configuring IO regmap region"); | |
730 | goto err_cleanup_dt; | |
731 | } | |
732 | ||
733 | ret = adv748x_identify_chip(state); | |
734 | if (ret) { | |
735 | adv_err(state, "Failed to identify chip"); | |
e0019f71 | 736 | goto err_cleanup_dt; |
3e89586a KB |
737 | } |
738 | ||
739 | /* Configure remaining pages as I2C clients with regmap access */ | |
740 | ret = adv748x_initialise_clients(state); | |
741 | if (ret) { | |
742 | adv_err(state, "Failed to setup client regmap pages"); | |
743 | goto err_cleanup_clients; | |
744 | } | |
745 | ||
746 | /* SW reset ADV748X to its default values */ | |
747 | ret = adv748x_reset(state); | |
748 | if (ret) { | |
749 | adv_err(state, "Failed to reset hardware"); | |
750 | goto err_cleanup_clients; | |
751 | } | |
752 | ||
753 | /* Initialise HDMI */ | |
754 | ret = adv748x_hdmi_init(&state->hdmi); | |
755 | if (ret) { | |
756 | adv_err(state, "Failed to probe HDMI"); | |
757 | goto err_cleanup_clients; | |
758 | } | |
759 | ||
760 | /* Initialise AFE */ | |
761 | ret = adv748x_afe_init(&state->afe); | |
762 | if (ret) { | |
763 | adv_err(state, "Failed to probe AFE"); | |
764 | goto err_cleanup_hdmi; | |
765 | } | |
766 | ||
767 | /* Initialise TXA */ | |
768 | ret = adv748x_csi2_init(state, &state->txa); | |
769 | if (ret) { | |
770 | adv_err(state, "Failed to probe TXA"); | |
771 | goto err_cleanup_afe; | |
772 | } | |
773 | ||
774 | /* Initialise TXB */ | |
775 | ret = adv748x_csi2_init(state, &state->txb); | |
776 | if (ret) { | |
777 | adv_err(state, "Failed to probe TXB"); | |
778 | goto err_cleanup_txa; | |
779 | } | |
780 | ||
781 | return 0; | |
782 | ||
783 | err_cleanup_txa: | |
784 | adv748x_csi2_cleanup(&state->txa); | |
785 | err_cleanup_afe: | |
786 | adv748x_afe_cleanup(&state->afe); | |
787 | err_cleanup_hdmi: | |
788 | adv748x_hdmi_cleanup(&state->hdmi); | |
789 | err_cleanup_clients: | |
790 | adv748x_unregister_clients(state); | |
791 | err_cleanup_dt: | |
792 | adv748x_dt_cleanup(state); | |
793 | err_free_mutex: | |
794 | mutex_destroy(&state->mutex); | |
3e89586a KB |
795 | |
796 | return ret; | |
797 | } | |
798 | ||
799 | static int adv748x_remove(struct i2c_client *client) | |
800 | { | |
801 | struct adv748x_state *state = i2c_get_clientdata(client); | |
802 | ||
803 | adv748x_afe_cleanup(&state->afe); | |
804 | adv748x_hdmi_cleanup(&state->hdmi); | |
805 | ||
806 | adv748x_csi2_cleanup(&state->txa); | |
807 | adv748x_csi2_cleanup(&state->txb); | |
808 | ||
809 | adv748x_unregister_clients(state); | |
810 | adv748x_dt_cleanup(state); | |
811 | mutex_destroy(&state->mutex); | |
812 | ||
3e89586a KB |
813 | return 0; |
814 | } | |
815 | ||
3e89586a KB |
816 | static const struct of_device_id adv748x_of_table[] = { |
817 | { .compatible = "adi,adv7481", }, | |
818 | { .compatible = "adi,adv7482", }, | |
819 | { } | |
820 | }; | |
821 | MODULE_DEVICE_TABLE(of, adv748x_of_table); | |
822 | ||
823 | static struct i2c_driver adv748x_driver = { | |
824 | .driver = { | |
825 | .name = "adv748x", | |
826 | .of_match_table = adv748x_of_table, | |
827 | }, | |
9deff920 | 828 | .probe_new = adv748x_probe, |
3e89586a | 829 | .remove = adv748x_remove, |
3e89586a KB |
830 | }; |
831 | ||
832 | module_i2c_driver(adv748x_driver); | |
833 | ||
834 | MODULE_AUTHOR("Kieran Bingham <kieran.bingham@ideasonboard.com>"); | |
835 | MODULE_DESCRIPTION("ADV748X video decoder"); | |
e58f3082 | 836 | MODULE_LICENSE("GPL"); |