diff options
23 files changed, 1893 insertions, 594 deletions
diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt new file mode 100644 index 000000000000..c27cede3bd68 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt | |||
@@ -0,0 +1,70 @@ | |||
1 | * Analog Devices ADV7604/11 video decoder with HDMI receiver | ||
2 | |||
3 | The ADV7604 and ADV7611 are multiformat video decoders with an integrated HDMI | ||
4 | receiver. The ADV7604 has four multiplexed HDMI inputs and one analog input, | ||
5 | and the ADV7611 has one HDMI input and no analog input. | ||
6 | |||
7 | These device tree bindings support the ADV7611 only at the moment. | ||
8 | |||
9 | Required Properties: | ||
10 | |||
11 | - compatible: Must contain one of the following | ||
12 | - "adi,adv7611" for the ADV7611 | ||
13 | |||
14 | - reg: I2C slave address | ||
15 | |||
16 | - hpd-gpios: References to the GPIOs that control the HDMI hot-plug | ||
17 | detection pins, one per HDMI input. The active flag indicates the GPIO | ||
18 | level that enables hot-plug detection. | ||
19 | |||
20 | The device node must contain one 'port' child node per device input and output | ||
21 | port, in accordance with the video interface bindings defined in | ||
22 | Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes | ||
23 | are numbered as follows. | ||
24 | |||
25 | Port ADV7611 | ||
26 | ------------------------------------------------------------ | ||
27 | HDMI 0 | ||
28 | Digital output 1 | ||
29 | |||
30 | The digital output port node must contain at least one endpoint. | ||
31 | |||
32 | Optional Properties: | ||
33 | |||
34 | - reset-gpios: Reference to the GPIO connected to the device's reset pin. | ||
35 | |||
36 | Optional Endpoint Properties: | ||
37 | |||
38 | The following three properties are defined in video-interfaces.txt and are | ||
39 | valid for source endpoints only. | ||
40 | |||
41 | - hsync-active: Horizontal synchronization polarity. Defaults to active low. | ||
42 | - vsync-active: Vertical synchronization polarity. Defaults to active low. | ||
43 | - pclk-sample: Pixel clock polarity. Defaults to output on the falling edge. | ||
44 | |||
45 | If none of hsync-active, vsync-active and pclk-sample is specified the | ||
46 | endpoint will use embedded BT.656 synchronization. | ||
47 | |||
48 | |||
49 | Example: | ||
50 | |||
51 | hdmi_receiver@4c { | ||
52 | compatible = "adi,adv7611"; | ||
53 | reg = <0x4c>; | ||
54 | |||
55 | reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; | ||
56 | hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; | ||
57 | |||
58 | #address-cells = <1>; | ||
59 | #size-cells = <0>; | ||
60 | |||
61 | port@0 { | ||
62 | reg = <0>; | ||
63 | }; | ||
64 | port@1 { | ||
65 | reg = <1>; | ||
66 | hdmi_in: endpoint { | ||
67 | remote-endpoint = <&ccdc_in>; | ||
68 | }; | ||
69 | }; | ||
70 | }; | ||
diff --git a/Documentation/devicetree/bindings/media/renesas,vsp1.txt b/Documentation/devicetree/bindings/media/renesas,vsp1.txt new file mode 100644 index 000000000000..87fe08abf36d --- /dev/null +++ b/Documentation/devicetree/bindings/media/renesas,vsp1.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | * Renesas VSP1 Video Processing Engine | ||
2 | |||
3 | The VSP1 is a video processing engine that supports up-/down-scaling, alpha | ||
4 | blending, color space conversion and various other image processing features. | ||
5 | It can be found in the Renesas R-Car second generation SoCs. | ||
6 | |||
7 | Required properties: | ||
8 | |||
9 | - compatible: Must contain "renesas,vsp1" | ||
10 | |||
11 | - reg: Base address and length of the registers block for the VSP1. | ||
12 | - interrupts: VSP1 interrupt specifier. | ||
13 | - clocks: A phandle + clock-specifier pair for the VSP1 functional clock. | ||
14 | |||
15 | - renesas,#rpf: Number of Read Pixel Formatter (RPF) modules in the VSP1. | ||
16 | - renesas,#uds: Number of Up Down Scaler (UDS) modules in the VSP1. | ||
17 | - renesas,#wpf: Number of Write Pixel Formatter (WPF) modules in the VSP1. | ||
18 | |||
19 | |||
20 | Optional properties: | ||
21 | |||
22 | - renesas,has-lif: Boolean, indicates that the LCD Interface (LIF) module is | ||
23 | available. | ||
24 | - renesas,has-lut: Boolean, indicates that the Look Up Table (LUT) module is | ||
25 | available. | ||
26 | - renesas,has-sru: Boolean, indicates that the Super Resolution Unit (SRU) | ||
27 | module is available. | ||
28 | |||
29 | |||
30 | Example: R8A7790 (R-Car H2) VSP1-S node | ||
31 | |||
32 | vsp1@fe928000 { | ||
33 | compatible = "renesas,vsp1"; | ||
34 | reg = <0 0xfe928000 0 0x8000>; | ||
35 | interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; | ||
36 | clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>; | ||
37 | |||
38 | renesas,has-lut; | ||
39 | renesas,has-sru; | ||
40 | renesas,#rpf = <5>; | ||
41 | renesas,#uds = <3>; | ||
42 | renesas,#wpf = <4>; | ||
43 | }; | ||
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 338baa4c23ef..1778d320272e 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c | |||
@@ -27,19 +27,21 @@ | |||
27 | * REF_03 - Analog devices, ADV7604, Hardware Manual, Rev. F, August 2010 | 27 | * REF_03 - Analog devices, ADV7604, Hardware Manual, Rev. F, August 2010 |
28 | */ | 28 | */ |
29 | 29 | ||
30 | 30 | #include <linux/delay.h> | |
31 | #include <linux/gpio/consumer.h> | ||
32 | #include <linux/i2c.h> | ||
31 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
32 | #include <linux/module.h> | 34 | #include <linux/module.h> |
33 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
34 | #include <linux/i2c.h> | 36 | #include <linux/v4l2-dv-timings.h> |
35 | #include <linux/delay.h> | ||
36 | #include <linux/videodev2.h> | 37 | #include <linux/videodev2.h> |
37 | #include <linux/workqueue.h> | 38 | #include <linux/workqueue.h> |
38 | #include <linux/v4l2-dv-timings.h> | 39 | |
39 | #include <media/v4l2-device.h> | 40 | #include <media/adv7604.h> |
40 | #include <media/v4l2-ctrls.h> | 41 | #include <media/v4l2-ctrls.h> |
42 | #include <media/v4l2-device.h> | ||
41 | #include <media/v4l2-dv-timings.h> | 43 | #include <media/v4l2-dv-timings.h> |
42 | #include <media/adv7604.h> | 44 | #include <media/v4l2-of.h> |
43 | 45 | ||
44 | static int debug; | 46 | static int debug; |
45 | module_param(debug, int, 0644); | 47 | module_param(debug, int, 0644); |
@@ -53,6 +55,76 @@ MODULE_LICENSE("GPL"); | |||
53 | /* ADV7604 system clock frequency */ | 55 | /* ADV7604 system clock frequency */ |
54 | #define ADV7604_fsc (28636360) | 56 | #define ADV7604_fsc (28636360) |
55 | 57 | ||
58 | #define ADV7604_RGB_OUT (1 << 1) | ||
59 | |||
60 | #define ADV7604_OP_FORMAT_SEL_8BIT (0 << 0) | ||
61 | #define ADV7604_OP_FORMAT_SEL_10BIT (1 << 0) | ||
62 | #define ADV7604_OP_FORMAT_SEL_12BIT (2 << 0) | ||
63 | |||
64 | #define ADV7604_OP_MODE_SEL_SDR_422 (0 << 5) | ||
65 | #define ADV7604_OP_MODE_SEL_DDR_422 (1 << 5) | ||
66 | #define ADV7604_OP_MODE_SEL_SDR_444 (2 << 5) | ||
67 | #define ADV7604_OP_MODE_SEL_DDR_444 (3 << 5) | ||
68 | #define ADV7604_OP_MODE_SEL_SDR_422_2X (4 << 5) | ||
69 | #define ADV7604_OP_MODE_SEL_ADI_CM (5 << 5) | ||
70 | |||
71 | #define ADV7604_OP_CH_SEL_GBR (0 << 5) | ||
72 | #define ADV7604_OP_CH_SEL_GRB (1 << 5) | ||
73 | #define ADV7604_OP_CH_SEL_BGR (2 << 5) | ||
74 | #define ADV7604_OP_CH_SEL_RGB (3 << 5) | ||
75 | #define ADV7604_OP_CH_SEL_BRG (4 << 5) | ||
76 | #define ADV7604_OP_CH_SEL_RBG (5 << 5) | ||
77 | |||
78 | #define ADV7604_OP_SWAP_CB_CR (1 << 0) | ||
79 | |||
80 | enum adv7604_type { | ||
81 | ADV7604, | ||
82 | ADV7611, | ||
83 | }; | ||
84 | |||
85 | struct adv7604_reg_seq { | ||
86 | unsigned int reg; | ||
87 | u8 val; | ||
88 | }; | ||
89 | |||
90 | struct adv7604_format_info { | ||
91 | enum v4l2_mbus_pixelcode code; | ||
92 | u8 op_ch_sel; | ||
93 | bool rgb_out; | ||
94 | bool swap_cb_cr; | ||
95 | u8 op_format_sel; | ||
96 | }; | ||
97 | |||
98 | struct adv7604_chip_info { | ||
99 | enum adv7604_type type; | ||
100 | |||
101 | bool has_afe; | ||
102 | unsigned int max_port; | ||
103 | unsigned int num_dv_ports; | ||
104 | |||
105 | unsigned int edid_enable_reg; | ||
106 | unsigned int edid_status_reg; | ||
107 | unsigned int lcf_reg; | ||
108 | |||
109 | unsigned int cable_det_mask; | ||
110 | unsigned int tdms_lock_mask; | ||
111 | unsigned int fmt_change_digital_mask; | ||
112 | |||
113 | const struct adv7604_format_info *formats; | ||
114 | unsigned int nformats; | ||
115 | |||
116 | void (*set_termination)(struct v4l2_subdev *sd, bool enable); | ||
117 | void (*setup_irqs)(struct v4l2_subdev *sd); | ||
118 | unsigned int (*read_hdmi_pixelclock)(struct v4l2_subdev *sd); | ||
119 | unsigned int (*read_cable_det)(struct v4l2_subdev *sd); | ||
120 | |||
121 | /* 0 = AFE, 1 = HDMI */ | ||
122 | const struct adv7604_reg_seq *recommended_settings[2]; | ||
123 | unsigned int num_recommended_settings[2]; | ||
124 | |||
125 | unsigned long page_mask; | ||
126 | }; | ||
127 | |||
56 | /* | 128 | /* |
57 | ********************************************************************** | 129 | ********************************************************************** |
58 | * | 130 | * |
@@ -60,13 +132,24 @@ MODULE_LICENSE("GPL"); | |||
60 | * | 132 | * |
61 | ********************************************************************** | 133 | ********************************************************************** |
62 | */ | 134 | */ |
135 | |||
63 | struct adv7604_state { | 136 | struct adv7604_state { |
137 | const struct adv7604_chip_info *info; | ||
64 | struct adv7604_platform_data pdata; | 138 | struct adv7604_platform_data pdata; |
139 | |||
140 | struct gpio_desc *hpd_gpio[4]; | ||
141 | |||
65 | struct v4l2_subdev sd; | 142 | struct v4l2_subdev sd; |
66 | struct media_pad pad; | 143 | struct media_pad pads[ADV7604_PAD_MAX]; |
144 | unsigned int source_pad; | ||
145 | |||
67 | struct v4l2_ctrl_handler hdl; | 146 | struct v4l2_ctrl_handler hdl; |
68 | enum adv7604_input_port selected_input; | 147 | |
148 | enum adv7604_pad selected_input; | ||
149 | |||
69 | struct v4l2_dv_timings timings; | 150 | struct v4l2_dv_timings timings; |
151 | const struct adv7604_format_info *format; | ||
152 | |||
70 | struct { | 153 | struct { |
71 | u8 edid[256]; | 154 | u8 edid[256]; |
72 | u32 present; | 155 | u32 present; |
@@ -80,18 +163,7 @@ struct adv7604_state { | |||
80 | bool restart_stdi_once; | 163 | bool restart_stdi_once; |
81 | 164 | ||
82 | /* i2c clients */ | 165 | /* i2c clients */ |
83 | struct i2c_client *i2c_avlink; | 166 | struct i2c_client *i2c_clients[ADV7604_PAGE_MAX]; |
84 | struct i2c_client *i2c_cec; | ||
85 | struct i2c_client *i2c_infoframe; | ||
86 | struct i2c_client *i2c_esdp; | ||
87 | struct i2c_client *i2c_dpp; | ||
88 | struct i2c_client *i2c_afe; | ||
89 | struct i2c_client *i2c_repeater; | ||
90 | struct i2c_client *i2c_edid; | ||
91 | struct i2c_client *i2c_hdmi; | ||
92 | struct i2c_client *i2c_test; | ||
93 | struct i2c_client *i2c_cp; | ||
94 | struct i2c_client *i2c_vdp; | ||
95 | 167 | ||
96 | /* controls */ | 168 | /* controls */ |
97 | struct v4l2_ctrl *detect_tx_5v_ctrl; | 169 | struct v4l2_ctrl *detect_tx_5v_ctrl; |
@@ -101,6 +173,11 @@ struct adv7604_state { | |||
101 | struct v4l2_ctrl *rgb_quantization_range_ctrl; | 173 | struct v4l2_ctrl *rgb_quantization_range_ctrl; |
102 | }; | 174 | }; |
103 | 175 | ||
176 | static bool adv7604_has_afe(struct adv7604_state *state) | ||
177 | { | ||
178 | return state->info->has_afe; | ||
179 | } | ||
180 | |||
104 | /* Supported CEA and DMT timings */ | 181 | /* Supported CEA and DMT timings */ |
105 | static const struct v4l2_dv_timings adv7604_timings[] = { | 182 | static const struct v4l2_dv_timings adv7604_timings[] = { |
106 | V4L2_DV_BT_CEA_720X480P59_94, | 183 | V4L2_DV_BT_CEA_720X480P59_94, |
@@ -256,11 +333,6 @@ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) | |||
256 | return container_of(sd, struct adv7604_state, sd); | 333 | return container_of(sd, struct adv7604_state, sd); |
257 | } | 334 | } |
258 | 335 | ||
259 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
260 | { | ||
261 | return &container_of(ctrl->handler, struct adv7604_state, hdl)->sd; | ||
262 | } | ||
263 | |||
264 | static inline unsigned hblanking(const struct v4l2_bt_timings *t) | 336 | static inline unsigned hblanking(const struct v4l2_bt_timings *t) |
265 | { | 337 | { |
266 | return V4L2_DV_BT_BLANKING_WIDTH(t); | 338 | return V4L2_DV_BT_BLANKING_WIDTH(t); |
@@ -298,14 +370,18 @@ static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, | |||
298 | return -EIO; | 370 | return -EIO; |
299 | } | 371 | } |
300 | 372 | ||
301 | static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command) | 373 | static s32 adv_smbus_read_byte_data(struct adv7604_state *state, |
374 | enum adv7604_page page, u8 command) | ||
302 | { | 375 | { |
303 | return adv_smbus_read_byte_data_check(client, command, true); | 376 | return adv_smbus_read_byte_data_check(state->i2c_clients[page], |
377 | command, true); | ||
304 | } | 378 | } |
305 | 379 | ||
306 | static s32 adv_smbus_write_byte_data(struct i2c_client *client, | 380 | static s32 adv_smbus_write_byte_data(struct adv7604_state *state, |
307 | u8 command, u8 value) | 381 | enum adv7604_page page, u8 command, |
382 | u8 value) | ||
308 | { | 383 | { |
384 | struct i2c_client *client = state->i2c_clients[page]; | ||
309 | union i2c_smbus_data data; | 385 | union i2c_smbus_data data; |
310 | int err; | 386 | int err; |
311 | int i; | 387 | int i; |
@@ -325,9 +401,11 @@ static s32 adv_smbus_write_byte_data(struct i2c_client *client, | |||
325 | return err; | 401 | return err; |
326 | } | 402 | } |
327 | 403 | ||
328 | static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, | 404 | static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state, |
329 | u8 command, unsigned length, const u8 *values) | 405 | enum adv7604_page page, u8 command, |
406 | unsigned length, const u8 *values) | ||
330 | { | 407 | { |
408 | struct i2c_client *client = state->i2c_clients[page]; | ||
331 | union i2c_smbus_data data; | 409 | union i2c_smbus_data data; |
332 | 410 | ||
333 | if (length > I2C_SMBUS_BLOCK_MAX) | 411 | if (length > I2C_SMBUS_BLOCK_MAX) |
@@ -343,149 +421,150 @@ static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, | |||
343 | 421 | ||
344 | static inline int io_read(struct v4l2_subdev *sd, u8 reg) | 422 | static inline int io_read(struct v4l2_subdev *sd, u8 reg) |
345 | { | 423 | { |
346 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 424 | struct adv7604_state *state = to_state(sd); |
347 | 425 | ||
348 | return adv_smbus_read_byte_data(client, reg); | 426 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_IO, reg); |
349 | } | 427 | } |
350 | 428 | ||
351 | static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 429 | static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
352 | { | 430 | { |
353 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 431 | struct adv7604_state *state = to_state(sd); |
354 | 432 | ||
355 | return adv_smbus_write_byte_data(client, reg, val); | 433 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_IO, reg, val); |
356 | } | 434 | } |
357 | 435 | ||
358 | static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | 436 | static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) |
359 | { | 437 | { |
360 | return io_write(sd, reg, (io_read(sd, reg) & mask) | val); | 438 | return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); |
361 | } | 439 | } |
362 | 440 | ||
363 | static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) | 441 | static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) |
364 | { | 442 | { |
365 | struct adv7604_state *state = to_state(sd); | 443 | struct adv7604_state *state = to_state(sd); |
366 | 444 | ||
367 | return adv_smbus_read_byte_data(state->i2c_avlink, reg); | 445 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); |
368 | } | 446 | } |
369 | 447 | ||
370 | static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 448 | static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
371 | { | 449 | { |
372 | struct adv7604_state *state = to_state(sd); | 450 | struct adv7604_state *state = to_state(sd); |
373 | 451 | ||
374 | return adv_smbus_write_byte_data(state->i2c_avlink, reg, val); | 452 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); |
375 | } | 453 | } |
376 | 454 | ||
377 | static inline int cec_read(struct v4l2_subdev *sd, u8 reg) | 455 | static inline int cec_read(struct v4l2_subdev *sd, u8 reg) |
378 | { | 456 | { |
379 | struct adv7604_state *state = to_state(sd); | 457 | struct adv7604_state *state = to_state(sd); |
380 | 458 | ||
381 | return adv_smbus_read_byte_data(state->i2c_cec, reg); | 459 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_CEC, reg); |
382 | } | 460 | } |
383 | 461 | ||
384 | static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 462 | static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
385 | { | 463 | { |
386 | struct adv7604_state *state = to_state(sd); | 464 | struct adv7604_state *state = to_state(sd); |
387 | 465 | ||
388 | return adv_smbus_write_byte_data(state->i2c_cec, reg, val); | 466 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val); |
389 | } | 467 | } |
390 | 468 | ||
391 | static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | 469 | static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) |
392 | { | 470 | { |
393 | return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val); | 471 | return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); |
394 | } | 472 | } |
395 | 473 | ||
396 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) | 474 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) |
397 | { | 475 | { |
398 | struct adv7604_state *state = to_state(sd); | 476 | struct adv7604_state *state = to_state(sd); |
399 | 477 | ||
400 | return adv_smbus_read_byte_data(state->i2c_infoframe, reg); | 478 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_INFOFRAME, reg); |
401 | } | 479 | } |
402 | 480 | ||
403 | static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 481 | static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
404 | { | 482 | { |
405 | struct adv7604_state *state = to_state(sd); | 483 | struct adv7604_state *state = to_state(sd); |
406 | 484 | ||
407 | return adv_smbus_write_byte_data(state->i2c_infoframe, reg, val); | 485 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_INFOFRAME, |
486 | reg, val); | ||
408 | } | 487 | } |
409 | 488 | ||
410 | static inline int esdp_read(struct v4l2_subdev *sd, u8 reg) | 489 | static inline int esdp_read(struct v4l2_subdev *sd, u8 reg) |
411 | { | 490 | { |
412 | struct adv7604_state *state = to_state(sd); | 491 | struct adv7604_state *state = to_state(sd); |
413 | 492 | ||
414 | return adv_smbus_read_byte_data(state->i2c_esdp, reg); | 493 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_ESDP, reg); |
415 | } | 494 | } |
416 | 495 | ||
417 | static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 496 | static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
418 | { | 497 | { |
419 | struct adv7604_state *state = to_state(sd); | 498 | struct adv7604_state *state = to_state(sd); |
420 | 499 | ||
421 | return adv_smbus_write_byte_data(state->i2c_esdp, reg, val); | 500 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_ESDP, reg, val); |
422 | } | 501 | } |
423 | 502 | ||
424 | static inline int dpp_read(struct v4l2_subdev *sd, u8 reg) | 503 | static inline int dpp_read(struct v4l2_subdev *sd, u8 reg) |
425 | { | 504 | { |
426 | struct adv7604_state *state = to_state(sd); | 505 | struct adv7604_state *state = to_state(sd); |
427 | 506 | ||
428 | return adv_smbus_read_byte_data(state->i2c_dpp, reg); | 507 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_DPP, reg); |
429 | } | 508 | } |
430 | 509 | ||
431 | static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 510 | static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
432 | { | 511 | { |
433 | struct adv7604_state *state = to_state(sd); | 512 | struct adv7604_state *state = to_state(sd); |
434 | 513 | ||
435 | return adv_smbus_write_byte_data(state->i2c_dpp, reg, val); | 514 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_DPP, reg, val); |
436 | } | 515 | } |
437 | 516 | ||
438 | static inline int afe_read(struct v4l2_subdev *sd, u8 reg) | 517 | static inline int afe_read(struct v4l2_subdev *sd, u8 reg) |
439 | { | 518 | { |
440 | struct adv7604_state *state = to_state(sd); | 519 | struct adv7604_state *state = to_state(sd); |
441 | 520 | ||
442 | return adv_smbus_read_byte_data(state->i2c_afe, reg); | 521 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_AFE, reg); |
443 | } | 522 | } |
444 | 523 | ||
445 | static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 524 | static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
446 | { | 525 | { |
447 | struct adv7604_state *state = to_state(sd); | 526 | struct adv7604_state *state = to_state(sd); |
448 | 527 | ||
449 | return adv_smbus_write_byte_data(state->i2c_afe, reg, val); | 528 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_AFE, reg, val); |
450 | } | 529 | } |
451 | 530 | ||
452 | static inline int rep_read(struct v4l2_subdev *sd, u8 reg) | 531 | static inline int rep_read(struct v4l2_subdev *sd, u8 reg) |
453 | { | 532 | { |
454 | struct adv7604_state *state = to_state(sd); | 533 | struct adv7604_state *state = to_state(sd); |
455 | 534 | ||
456 | return adv_smbus_read_byte_data(state->i2c_repeater, reg); | 535 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_REP, reg); |
457 | } | 536 | } |
458 | 537 | ||
459 | static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 538 | static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
460 | { | 539 | { |
461 | struct adv7604_state *state = to_state(sd); | 540 | struct adv7604_state *state = to_state(sd); |
462 | 541 | ||
463 | return adv_smbus_write_byte_data(state->i2c_repeater, reg, val); | 542 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_REP, reg, val); |
464 | } | 543 | } |
465 | 544 | ||
466 | static inline int rep_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | 545 | static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) |
467 | { | 546 | { |
468 | return rep_write(sd, reg, (rep_read(sd, reg) & mask) | val); | 547 | return rep_write(sd, reg, (rep_read(sd, reg) & ~mask) | val); |
469 | } | 548 | } |
470 | 549 | ||
471 | static inline int edid_read(struct v4l2_subdev *sd, u8 reg) | 550 | static inline int edid_read(struct v4l2_subdev *sd, u8 reg) |
472 | { | 551 | { |
473 | struct adv7604_state *state = to_state(sd); | 552 | struct adv7604_state *state = to_state(sd); |
474 | 553 | ||
475 | return adv_smbus_read_byte_data(state->i2c_edid, reg); | 554 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_EDID, reg); |
476 | } | 555 | } |
477 | 556 | ||
478 | static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 557 | static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
479 | { | 558 | { |
480 | struct adv7604_state *state = to_state(sd); | 559 | struct adv7604_state *state = to_state(sd); |
481 | 560 | ||
482 | return adv_smbus_write_byte_data(state->i2c_edid, reg, val); | 561 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val); |
483 | } | 562 | } |
484 | 563 | ||
485 | static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) | 564 | static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) |
486 | { | 565 | { |
487 | struct adv7604_state *state = to_state(sd); | 566 | struct adv7604_state *state = to_state(sd); |
488 | struct i2c_client *client = state->i2c_edid; | 567 | struct i2c_client *client = state->i2c_clients[ADV7604_PAGE_EDID]; |
489 | u8 msgbuf0[1] = { 0 }; | 568 | u8 msgbuf0[1] = { 0 }; |
490 | u8 msgbuf1[256]; | 569 | u8 msgbuf1[256]; |
491 | struct i2c_msg msg[2] = { | 570 | struct i2c_msg msg[2] = { |
@@ -518,11 +597,25 @@ static inline int edid_write_block(struct v4l2_subdev *sd, | |||
518 | v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); | 597 | v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); |
519 | 598 | ||
520 | for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) | 599 | for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) |
521 | err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, | 600 | err = adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_EDID, |
522 | I2C_SMBUS_BLOCK_MAX, val + i); | 601 | i, I2C_SMBUS_BLOCK_MAX, val + i); |
523 | return err; | 602 | return err; |
524 | } | 603 | } |
525 | 604 | ||
605 | static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd) | ||
606 | { | ||
607 | unsigned int i; | ||
608 | |||
609 | for (i = 0; i < state->info->num_dv_ports; ++i) { | ||
610 | if (IS_ERR(state->hpd_gpio[i])) | ||
611 | continue; | ||
612 | |||
613 | gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i)); | ||
614 | } | ||
615 | |||
616 | v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd); | ||
617 | } | ||
618 | |||
526 | static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) | 619 | static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) |
527 | { | 620 | { |
528 | struct delayed_work *dwork = to_delayed_work(work); | 621 | struct delayed_work *dwork = to_delayed_work(work); |
@@ -532,73 +625,210 @@ static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) | |||
532 | 625 | ||
533 | v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); | 626 | v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); |
534 | 627 | ||
535 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); | 628 | adv7604_set_hpd(state, state->edid.present); |
536 | } | 629 | } |
537 | 630 | ||
538 | static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) | 631 | static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) |
539 | { | 632 | { |
540 | struct adv7604_state *state = to_state(sd); | 633 | struct adv7604_state *state = to_state(sd); |
541 | 634 | ||
542 | return adv_smbus_read_byte_data(state->i2c_hdmi, reg); | 635 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_HDMI, reg); |
636 | } | ||
637 | |||
638 | static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) | ||
639 | { | ||
640 | return ((hdmi_read(sd, reg) << 8) | hdmi_read(sd, reg + 1)) & mask; | ||
543 | } | 641 | } |
544 | 642 | ||
545 | static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 643 | static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
546 | { | 644 | { |
547 | struct adv7604_state *state = to_state(sd); | 645 | struct adv7604_state *state = to_state(sd); |
548 | 646 | ||
549 | return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); | 647 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_HDMI, reg, val); |
550 | } | 648 | } |
551 | 649 | ||
552 | static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | 650 | static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) |
553 | { | 651 | { |
554 | return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); | 652 | return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val); |
555 | } | 653 | } |
556 | 654 | ||
557 | static inline int test_read(struct v4l2_subdev *sd, u8 reg) | 655 | static inline int test_read(struct v4l2_subdev *sd, u8 reg) |
558 | { | 656 | { |
559 | struct adv7604_state *state = to_state(sd); | 657 | struct adv7604_state *state = to_state(sd); |
560 | 658 | ||
561 | return adv_smbus_read_byte_data(state->i2c_test, reg); | 659 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_TEST, reg); |
562 | } | 660 | } |
563 | 661 | ||
564 | static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 662 | static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
565 | { | 663 | { |
566 | struct adv7604_state *state = to_state(sd); | 664 | struct adv7604_state *state = to_state(sd); |
567 | 665 | ||
568 | return adv_smbus_write_byte_data(state->i2c_test, reg, val); | 666 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_TEST, reg, val); |
569 | } | 667 | } |
570 | 668 | ||
571 | static inline int cp_read(struct v4l2_subdev *sd, u8 reg) | 669 | static inline int cp_read(struct v4l2_subdev *sd, u8 reg) |
572 | { | 670 | { |
573 | struct adv7604_state *state = to_state(sd); | 671 | struct adv7604_state *state = to_state(sd); |
574 | 672 | ||
575 | return adv_smbus_read_byte_data(state->i2c_cp, reg); | 673 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_CP, reg); |
674 | } | ||
675 | |||
676 | static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) | ||
677 | { | ||
678 | return ((cp_read(sd, reg) << 8) | cp_read(sd, reg + 1)) & mask; | ||
576 | } | 679 | } |
577 | 680 | ||
578 | static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 681 | static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
579 | { | 682 | { |
580 | struct adv7604_state *state = to_state(sd); | 683 | struct adv7604_state *state = to_state(sd); |
581 | 684 | ||
582 | return adv_smbus_write_byte_data(state->i2c_cp, reg, val); | 685 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_CP, reg, val); |
583 | } | 686 | } |
584 | 687 | ||
585 | static inline int cp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | 688 | static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) |
586 | { | 689 | { |
587 | return cp_write(sd, reg, (cp_read(sd, reg) & mask) | val); | 690 | return cp_write(sd, reg, (cp_read(sd, reg) & ~mask) | val); |
588 | } | 691 | } |
589 | 692 | ||
590 | static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) | 693 | static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) |
591 | { | 694 | { |
592 | struct adv7604_state *state = to_state(sd); | 695 | struct adv7604_state *state = to_state(sd); |
593 | 696 | ||
594 | return adv_smbus_read_byte_data(state->i2c_vdp, reg); | 697 | return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); |
595 | } | 698 | } |
596 | 699 | ||
597 | static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) | 700 | static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) |
598 | { | 701 | { |
599 | struct adv7604_state *state = to_state(sd); | 702 | struct adv7604_state *state = to_state(sd); |
600 | 703 | ||
601 | return adv_smbus_write_byte_data(state->i2c_vdp, reg, val); | 704 | return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); |
705 | } | ||
706 | |||
707 | #define ADV7604_REG(page, offset) (((page) << 8) | (offset)) | ||
708 | #define ADV7604_REG_SEQ_TERM 0xffff | ||
709 | |||
710 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
711 | static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg) | ||
712 | { | ||
713 | struct adv7604_state *state = to_state(sd); | ||
714 | unsigned int page = reg >> 8; | ||
715 | |||
716 | if (!(BIT(page) & state->info->page_mask)) | ||
717 | return -EINVAL; | ||
718 | |||
719 | reg &= 0xff; | ||
720 | |||
721 | return adv_smbus_read_byte_data(state, page, reg); | ||
722 | } | ||
723 | #endif | ||
724 | |||
725 | static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) | ||
726 | { | ||
727 | struct adv7604_state *state = to_state(sd); | ||
728 | unsigned int page = reg >> 8; | ||
729 | |||
730 | if (!(BIT(page) & state->info->page_mask)) | ||
731 | return -EINVAL; | ||
732 | |||
733 | reg &= 0xff; | ||
734 | |||
735 | return adv_smbus_write_byte_data(state, page, reg, val); | ||
736 | } | ||
737 | |||
738 | static void adv7604_write_reg_seq(struct v4l2_subdev *sd, | ||
739 | const struct adv7604_reg_seq *reg_seq) | ||
740 | { | ||
741 | unsigned int i; | ||
742 | |||
743 | for (i = 0; reg_seq[i].reg != ADV7604_REG_SEQ_TERM; i++) | ||
744 | adv7604_write_reg(sd, reg_seq[i].reg, reg_seq[i].val); | ||
745 | } | ||
746 | |||
747 | /* ----------------------------------------------------------------------------- | ||
748 | * Format helpers | ||
749 | */ | ||
750 | |||
751 | static const struct adv7604_format_info adv7604_formats[] = { | ||
752 | { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, | ||
753 | ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
754 | { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, | ||
755 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
756 | { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, | ||
757 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
758 | { V4L2_MBUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false, | ||
759 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, | ||
760 | { V4L2_MBUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true, | ||
761 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, | ||
762 | { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, | ||
763 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
764 | { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, | ||
765 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
766 | { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, | ||
767 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
768 | { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, | ||
769 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
770 | { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, | ||
771 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
772 | { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, | ||
773 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
774 | { V4L2_MBUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false, | ||
775 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, | ||
776 | { V4L2_MBUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true, | ||
777 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, | ||
778 | { V4L2_MBUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false, | ||
779 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, | ||
780 | { V4L2_MBUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true, | ||
781 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, | ||
782 | { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, | ||
783 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
784 | { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, | ||
785 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
786 | { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, | ||
787 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
788 | { V4L2_MBUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, | ||
789 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
790 | }; | ||
791 | |||
792 | static const struct adv7604_format_info adv7611_formats[] = { | ||
793 | { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, | ||
794 | ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
795 | { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, | ||
796 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
797 | { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, | ||
798 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
799 | { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, | ||
800 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
801 | { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, | ||
802 | ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
803 | { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, | ||
804 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
805 | { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, | ||
806 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
807 | { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, | ||
808 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
809 | { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, | ||
810 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, | ||
811 | { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, | ||
812 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
813 | { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, | ||
814 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
815 | { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, | ||
816 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
817 | { V4L2_MBUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, | ||
818 | ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, | ||
819 | }; | ||
820 | |||
821 | static const struct adv7604_format_info * | ||
822 | adv7604_format_info(struct adv7604_state *state, enum v4l2_mbus_pixelcode code) | ||
823 | { | ||
824 | unsigned int i; | ||
825 | |||
826 | for (i = 0; i < state->info->nformats; ++i) { | ||
827 | if (state->info->formats[i].code == code) | ||
828 | return &state->info->formats[i]; | ||
829 | } | ||
830 | |||
831 | return NULL; | ||
602 | } | 832 | } |
603 | 833 | ||
604 | /* ----------------------------------------------------------------------- */ | 834 | /* ----------------------------------------------------------------------- */ |
@@ -607,18 +837,18 @@ static inline bool is_analog_input(struct v4l2_subdev *sd) | |||
607 | { | 837 | { |
608 | struct adv7604_state *state = to_state(sd); | 838 | struct adv7604_state *state = to_state(sd); |
609 | 839 | ||
610 | return state->selected_input == ADV7604_INPUT_VGA_RGB || | 840 | return state->selected_input == ADV7604_PAD_VGA_RGB || |
611 | state->selected_input == ADV7604_INPUT_VGA_COMP; | 841 | state->selected_input == ADV7604_PAD_VGA_COMP; |
612 | } | 842 | } |
613 | 843 | ||
614 | static inline bool is_digital_input(struct v4l2_subdev *sd) | 844 | static inline bool is_digital_input(struct v4l2_subdev *sd) |
615 | { | 845 | { |
616 | struct adv7604_state *state = to_state(sd); | 846 | struct adv7604_state *state = to_state(sd); |
617 | 847 | ||
618 | return state->selected_input == ADV7604_INPUT_HDMI_PORT_A || | 848 | return state->selected_input == ADV7604_PAD_HDMI_PORT_A || |
619 | state->selected_input == ADV7604_INPUT_HDMI_PORT_B || | 849 | state->selected_input == ADV7604_PAD_HDMI_PORT_B || |
620 | state->selected_input == ADV7604_INPUT_HDMI_PORT_C || | 850 | state->selected_input == ADV7604_PAD_HDMI_PORT_C || |
621 | state->selected_input == ADV7604_INPUT_HDMI_PORT_D; | 851 | state->selected_input == ADV7604_PAD_HDMI_PORT_D; |
622 | } | 852 | } |
623 | 853 | ||
624 | /* ----------------------------------------------------------------------- */ | 854 | /* ----------------------------------------------------------------------- */ |
@@ -644,119 +874,61 @@ static void adv7604_inv_register(struct v4l2_subdev *sd) | |||
644 | static int adv7604_g_register(struct v4l2_subdev *sd, | 874 | static int adv7604_g_register(struct v4l2_subdev *sd, |
645 | struct v4l2_dbg_register *reg) | 875 | struct v4l2_dbg_register *reg) |
646 | { | 876 | { |
647 | reg->size = 1; | 877 | int ret; |
648 | switch (reg->reg >> 8) { | 878 | |
649 | case 0: | 879 | ret = adv7604_read_reg(sd, reg->reg); |
650 | reg->val = io_read(sd, reg->reg & 0xff); | 880 | if (ret < 0) { |
651 | break; | ||
652 | case 1: | ||
653 | reg->val = avlink_read(sd, reg->reg & 0xff); | ||
654 | break; | ||
655 | case 2: | ||
656 | reg->val = cec_read(sd, reg->reg & 0xff); | ||
657 | break; | ||
658 | case 3: | ||
659 | reg->val = infoframe_read(sd, reg->reg & 0xff); | ||
660 | break; | ||
661 | case 4: | ||
662 | reg->val = esdp_read(sd, reg->reg & 0xff); | ||
663 | break; | ||
664 | case 5: | ||
665 | reg->val = dpp_read(sd, reg->reg & 0xff); | ||
666 | break; | ||
667 | case 6: | ||
668 | reg->val = afe_read(sd, reg->reg & 0xff); | ||
669 | break; | ||
670 | case 7: | ||
671 | reg->val = rep_read(sd, reg->reg & 0xff); | ||
672 | break; | ||
673 | case 8: | ||
674 | reg->val = edid_read(sd, reg->reg & 0xff); | ||
675 | break; | ||
676 | case 9: | ||
677 | reg->val = hdmi_read(sd, reg->reg & 0xff); | ||
678 | break; | ||
679 | case 0xa: | ||
680 | reg->val = test_read(sd, reg->reg & 0xff); | ||
681 | break; | ||
682 | case 0xb: | ||
683 | reg->val = cp_read(sd, reg->reg & 0xff); | ||
684 | break; | ||
685 | case 0xc: | ||
686 | reg->val = vdp_read(sd, reg->reg & 0xff); | ||
687 | break; | ||
688 | default: | ||
689 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); | 881 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
690 | adv7604_inv_register(sd); | 882 | adv7604_inv_register(sd); |
691 | break; | 883 | return ret; |
692 | } | 884 | } |
885 | |||
886 | reg->size = 1; | ||
887 | reg->val = ret; | ||
888 | |||
693 | return 0; | 889 | return 0; |
694 | } | 890 | } |
695 | 891 | ||
696 | static int adv7604_s_register(struct v4l2_subdev *sd, | 892 | static int adv7604_s_register(struct v4l2_subdev *sd, |
697 | const struct v4l2_dbg_register *reg) | 893 | const struct v4l2_dbg_register *reg) |
698 | { | 894 | { |
699 | u8 val = reg->val & 0xff; | 895 | int ret; |
700 | 896 | ||
701 | switch (reg->reg >> 8) { | 897 | ret = adv7604_write_reg(sd, reg->reg, reg->val); |
702 | case 0: | 898 | if (ret < 0) { |
703 | io_write(sd, reg->reg & 0xff, val); | ||
704 | break; | ||
705 | case 1: | ||
706 | avlink_write(sd, reg->reg & 0xff, val); | ||
707 | break; | ||
708 | case 2: | ||
709 | cec_write(sd, reg->reg & 0xff, val); | ||
710 | break; | ||
711 | case 3: | ||
712 | infoframe_write(sd, reg->reg & 0xff, val); | ||
713 | break; | ||
714 | case 4: | ||
715 | esdp_write(sd, reg->reg & 0xff, val); | ||
716 | break; | ||
717 | case 5: | ||
718 | dpp_write(sd, reg->reg & 0xff, val); | ||
719 | break; | ||
720 | case 6: | ||
721 | afe_write(sd, reg->reg & 0xff, val); | ||
722 | break; | ||
723 | case 7: | ||
724 | rep_write(sd, reg->reg & 0xff, val); | ||
725 | break; | ||
726 | case 8: | ||
727 | edid_write(sd, reg->reg & 0xff, val); | ||
728 | break; | ||
729 | case 9: | ||
730 | hdmi_write(sd, reg->reg & 0xff, val); | ||
731 | break; | ||
732 | case 0xa: | ||
733 | test_write(sd, reg->reg & 0xff, val); | ||
734 | break; | ||
735 | case 0xb: | ||
736 | cp_write(sd, reg->reg & 0xff, val); | ||
737 | break; | ||
738 | case 0xc: | ||
739 | vdp_write(sd, reg->reg & 0xff, val); | ||
740 | break; | ||
741 | default: | ||
742 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); | 899 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
743 | adv7604_inv_register(sd); | 900 | adv7604_inv_register(sd); |
744 | break; | 901 | return ret; |
745 | } | 902 | } |
903 | |||
746 | return 0; | 904 | return 0; |
747 | } | 905 | } |
748 | #endif | 906 | #endif |
749 | 907 | ||
908 | static unsigned int adv7604_read_cable_det(struct v4l2_subdev *sd) | ||
909 | { | ||
910 | u8 value = io_read(sd, 0x6f); | ||
911 | |||
912 | return ((value & 0x10) >> 4) | ||
913 | | ((value & 0x08) >> 2) | ||
914 | | ((value & 0x04) << 0) | ||
915 | | ((value & 0x02) << 2); | ||
916 | } | ||
917 | |||
918 | static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd) | ||
919 | { | ||
920 | u8 value = io_read(sd, 0x6f); | ||
921 | |||
922 | return value & 1; | ||
923 | } | ||
924 | |||
750 | static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) | 925 | static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) |
751 | { | 926 | { |
752 | struct adv7604_state *state = to_state(sd); | 927 | struct adv7604_state *state = to_state(sd); |
753 | u8 reg_io_6f = io_read(sd, 0x6f); | 928 | const struct adv7604_chip_info *info = state->info; |
754 | 929 | ||
755 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, | 930 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, |
756 | ((reg_io_6f & 0x10) >> 4) | | 931 | info->read_cable_det(sd)); |
757 | ((reg_io_6f & 0x08) >> 2) | | ||
758 | (reg_io_6f & 0x04) | | ||
759 | ((reg_io_6f & 0x02) << 2)); | ||
760 | } | 932 | } |
761 | 933 | ||
762 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, | 934 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, |
@@ -787,11 +959,13 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, | |||
787 | 959 | ||
788 | v4l2_dbg(1, debug, sd, "%s", __func__); | 960 | v4l2_dbg(1, debug, sd, "%s", __func__); |
789 | 961 | ||
790 | /* reset to default values */ | 962 | if (adv7604_has_afe(state)) { |
791 | io_write(sd, 0x16, 0x43); | 963 | /* reset to default values */ |
792 | io_write(sd, 0x17, 0x5a); | 964 | io_write(sd, 0x16, 0x43); |
965 | io_write(sd, 0x17, 0x5a); | ||
966 | } | ||
793 | /* disable embedded syncs for auto graphics mode */ | 967 | /* disable embedded syncs for auto graphics mode */ |
794 | cp_write_and_or(sd, 0x81, 0xef, 0x00); | 968 | cp_write_clr_set(sd, 0x81, 0x10, 0x00); |
795 | cp_write(sd, 0x8f, 0x00); | 969 | cp_write(sd, 0x8f, 0x00); |
796 | cp_write(sd, 0x90, 0x00); | 970 | cp_write(sd, 0x90, 0x00); |
797 | cp_write(sd, 0xa2, 0x00); | 971 | cp_write(sd, 0xa2, 0x00); |
@@ -829,7 +1003,6 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, | |||
829 | const struct v4l2_bt_timings *bt) | 1003 | const struct v4l2_bt_timings *bt) |
830 | { | 1004 | { |
831 | struct adv7604_state *state = to_state(sd); | 1005 | struct adv7604_state *state = to_state(sd); |
832 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
833 | u32 width = htotal(bt); | 1006 | u32 width = htotal(bt); |
834 | u32 height = vtotal(bt); | 1007 | u32 height = vtotal(bt); |
835 | u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; | 1008 | u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; |
@@ -850,12 +1023,13 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, | |||
850 | io_write(sd, 0x00, 0x07); /* video std */ | 1023 | io_write(sd, 0x00, 0x07); /* video std */ |
851 | io_write(sd, 0x01, 0x02); /* prim mode */ | 1024 | io_write(sd, 0x01, 0x02); /* prim mode */ |
852 | /* enable embedded syncs for auto graphics mode */ | 1025 | /* enable embedded syncs for auto graphics mode */ |
853 | cp_write_and_or(sd, 0x81, 0xef, 0x10); | 1026 | cp_write_clr_set(sd, 0x81, 0x10, 0x10); |
854 | 1027 | ||
855 | /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ | 1028 | /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ |
856 | /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ | 1029 | /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ |
857 | /* IO-map reg. 0x16 and 0x17 should be written in sequence */ | 1030 | /* IO-map reg. 0x16 and 0x17 should be written in sequence */ |
858 | if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) | 1031 | if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_IO, |
1032 | 0x16, 2, pll)) | ||
859 | v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); | 1033 | v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); |
860 | 1034 | ||
861 | /* active video - horizontal timing */ | 1035 | /* active video - horizontal timing */ |
@@ -906,7 +1080,8 @@ static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off | |||
906 | offset_buf[3] = offset_c & 0x0ff; | 1080 | offset_buf[3] = offset_c & 0x0ff; |
907 | 1081 | ||
908 | /* Registers must be written in this order with no i2c access in between */ | 1082 | /* Registers must be written in this order with no i2c access in between */ |
909 | if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) | 1083 | if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, |
1084 | 0x77, 4, offset_buf)) | ||
910 | v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); | 1085 | v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); |
911 | } | 1086 | } |
912 | 1087 | ||
@@ -935,7 +1110,8 @@ static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, | |||
935 | gain_buf[3] = ((gain_c & 0x0ff)); | 1110 | gain_buf[3] = ((gain_c & 0x0ff)); |
936 | 1111 | ||
937 | /* Registers must be written in this order with no i2c access in between */ | 1112 | /* Registers must be written in this order with no i2c access in between */ |
938 | if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) | 1113 | if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, |
1114 | 0x73, 4, gain_buf)) | ||
939 | v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); | 1115 | v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); |
940 | } | 1116 | } |
941 | 1117 | ||
@@ -954,24 +1130,24 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
954 | 1130 | ||
955 | switch (state->rgb_quantization_range) { | 1131 | switch (state->rgb_quantization_range) { |
956 | case V4L2_DV_RGB_RANGE_AUTO: | 1132 | case V4L2_DV_RGB_RANGE_AUTO: |
957 | if (state->selected_input == ADV7604_INPUT_VGA_RGB) { | 1133 | if (state->selected_input == ADV7604_PAD_VGA_RGB) { |
958 | /* Receiving analog RGB signal | 1134 | /* Receiving analog RGB signal |
959 | * Set RGB full range (0-255) */ | 1135 | * Set RGB full range (0-255) */ |
960 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 1136 | io_write_clr_set(sd, 0x02, 0xf0, 0x10); |
961 | break; | 1137 | break; |
962 | } | 1138 | } |
963 | 1139 | ||
964 | if (state->selected_input == ADV7604_INPUT_VGA_COMP) { | 1140 | if (state->selected_input == ADV7604_PAD_VGA_COMP) { |
965 | /* Receiving analog YPbPr signal | 1141 | /* Receiving analog YPbPr signal |
966 | * Set automode */ | 1142 | * Set automode */ |
967 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | 1143 | io_write_clr_set(sd, 0x02, 0xf0, 0xf0); |
968 | break; | 1144 | break; |
969 | } | 1145 | } |
970 | 1146 | ||
971 | if (hdmi_signal) { | 1147 | if (hdmi_signal) { |
972 | /* Receiving HDMI signal | 1148 | /* Receiving HDMI signal |
973 | * Set automode */ | 1149 | * Set automode */ |
974 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | 1150 | io_write_clr_set(sd, 0x02, 0xf0, 0xf0); |
975 | break; | 1151 | break; |
976 | } | 1152 | } |
977 | 1153 | ||
@@ -980,10 +1156,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
980 | * input format (CE/IT) in automatic mode */ | 1156 | * input format (CE/IT) in automatic mode */ |
981 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { | 1157 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { |
982 | /* RGB limited range (16-235) */ | 1158 | /* RGB limited range (16-235) */ |
983 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 1159 | io_write_clr_set(sd, 0x02, 0xf0, 0x00); |
984 | } else { | 1160 | } else { |
985 | /* RGB full range (0-255) */ | 1161 | /* RGB full range (0-255) */ |
986 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 1162 | io_write_clr_set(sd, 0x02, 0xf0, 0x10); |
987 | 1163 | ||
988 | if (is_digital_input(sd) && rgb_output) { | 1164 | if (is_digital_input(sd) && rgb_output) { |
989 | adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); | 1165 | adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); |
@@ -994,25 +1170,25 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
994 | } | 1170 | } |
995 | break; | 1171 | break; |
996 | case V4L2_DV_RGB_RANGE_LIMITED: | 1172 | case V4L2_DV_RGB_RANGE_LIMITED: |
997 | if (state->selected_input == ADV7604_INPUT_VGA_COMP) { | 1173 | if (state->selected_input == ADV7604_PAD_VGA_COMP) { |
998 | /* YCrCb limited range (16-235) */ | 1174 | /* YCrCb limited range (16-235) */ |
999 | io_write_and_or(sd, 0x02, 0x0f, 0x20); | 1175 | io_write_clr_set(sd, 0x02, 0xf0, 0x20); |
1000 | break; | 1176 | break; |
1001 | } | 1177 | } |
1002 | 1178 | ||
1003 | /* RGB limited range (16-235) */ | 1179 | /* RGB limited range (16-235) */ |
1004 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 1180 | io_write_clr_set(sd, 0x02, 0xf0, 0x00); |
1005 | 1181 | ||
1006 | break; | 1182 | break; |
1007 | case V4L2_DV_RGB_RANGE_FULL: | 1183 | case V4L2_DV_RGB_RANGE_FULL: |
1008 | if (state->selected_input == ADV7604_INPUT_VGA_COMP) { | 1184 | if (state->selected_input == ADV7604_PAD_VGA_COMP) { |
1009 | /* YCrCb full range (0-255) */ | 1185 | /* YCrCb full range (0-255) */ |
1010 | io_write_and_or(sd, 0x02, 0x0f, 0x60); | 1186 | io_write_clr_set(sd, 0x02, 0xf0, 0x60); |
1011 | break; | 1187 | break; |
1012 | } | 1188 | } |
1013 | 1189 | ||
1014 | /* RGB full range (0-255) */ | 1190 | /* RGB full range (0-255) */ |
1015 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 1191 | io_write_clr_set(sd, 0x02, 0xf0, 0x10); |
1016 | 1192 | ||
1017 | if (is_analog_input(sd) || hdmi_signal) | 1193 | if (is_analog_input(sd) || hdmi_signal) |
1018 | break; | 1194 | break; |
@@ -1030,7 +1206,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
1030 | 1206 | ||
1031 | static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) | 1207 | static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) |
1032 | { | 1208 | { |
1033 | struct v4l2_subdev *sd = to_sd(ctrl); | 1209 | struct v4l2_subdev *sd = |
1210 | &container_of(ctrl->handler, struct adv7604_state, hdl)->sd; | ||
1211 | |||
1034 | struct adv7604_state *state = to_state(sd); | 1212 | struct adv7604_state *state = to_state(sd); |
1035 | 1213 | ||
1036 | switch (ctrl->id) { | 1214 | switch (ctrl->id) { |
@@ -1051,6 +1229,8 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) | |||
1051 | set_rgb_quantization_range(sd); | 1229 | set_rgb_quantization_range(sd); |
1052 | return 0; | 1230 | return 0; |
1053 | case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: | 1231 | case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: |
1232 | if (!adv7604_has_afe(state)) | ||
1233 | return -EINVAL; | ||
1054 | /* Set the analog sampling phase. This is needed to find the | 1234 | /* Set the analog sampling phase. This is needed to find the |
1055 | best sampling phase for analog video: an application or | 1235 | best sampling phase for analog video: an application or |
1056 | driver has to try a number of phases and analyze the picture | 1236 | driver has to try a number of phases and analyze the picture |
@@ -1060,7 +1240,7 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) | |||
1060 | case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL: | 1240 | case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL: |
1061 | /* Use the default blue color for free running mode, | 1241 | /* Use the default blue color for free running mode, |
1062 | or supply your own. */ | 1242 | or supply your own. */ |
1063 | cp_write_and_or(sd, 0xbf, ~0x04, (ctrl->val << 2)); | 1243 | cp_write_clr_set(sd, 0xbf, 0x04, ctrl->val << 2); |
1064 | return 0; | 1244 | return 0; |
1065 | case V4L2_CID_ADV_RX_FREE_RUN_COLOR: | 1245 | case V4L2_CID_ADV_RX_FREE_RUN_COLOR: |
1066 | cp_write(sd, 0xc0, (ctrl->val & 0xff0000) >> 16); | 1246 | cp_write(sd, 0xc0, (ctrl->val & 0xff0000) >> 16); |
@@ -1088,7 +1268,10 @@ static inline bool no_signal_tmds(struct v4l2_subdev *sd) | |||
1088 | 1268 | ||
1089 | static inline bool no_lock_tmds(struct v4l2_subdev *sd) | 1269 | static inline bool no_lock_tmds(struct v4l2_subdev *sd) |
1090 | { | 1270 | { |
1091 | return (io_read(sd, 0x6a) & 0xe0) != 0xe0; | 1271 | struct adv7604_state *state = to_state(sd); |
1272 | const struct adv7604_chip_info *info = state->info; | ||
1273 | |||
1274 | return (io_read(sd, 0x6a) & info->tdms_lock_mask) != info->tdms_lock_mask; | ||
1092 | } | 1275 | } |
1093 | 1276 | ||
1094 | static inline bool is_hdmi(struct v4l2_subdev *sd) | 1277 | static inline bool is_hdmi(struct v4l2_subdev *sd) |
@@ -1098,6 +1281,15 @@ static inline bool is_hdmi(struct v4l2_subdev *sd) | |||
1098 | 1281 | ||
1099 | static inline bool no_lock_sspd(struct v4l2_subdev *sd) | 1282 | static inline bool no_lock_sspd(struct v4l2_subdev *sd) |
1100 | { | 1283 | { |
1284 | struct adv7604_state *state = to_state(sd); | ||
1285 | |||
1286 | /* | ||
1287 | * Chips without a AFE don't expose registers for the SSPD, so just assume | ||
1288 | * that we have a lock. | ||
1289 | */ | ||
1290 | if (adv7604_has_afe(state)) | ||
1291 | return false; | ||
1292 | |||
1101 | /* TODO channel 2 */ | 1293 | /* TODO channel 2 */ |
1102 | return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0); | 1294 | return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0); |
1103 | } | 1295 | } |
@@ -1127,6 +1319,11 @@ static inline bool no_signal(struct v4l2_subdev *sd) | |||
1127 | 1319 | ||
1128 | static inline bool no_lock_cp(struct v4l2_subdev *sd) | 1320 | static inline bool no_lock_cp(struct v4l2_subdev *sd) |
1129 | { | 1321 | { |
1322 | struct adv7604_state *state = to_state(sd); | ||
1323 | |||
1324 | if (!adv7604_has_afe(state)) | ||
1325 | return false; | ||
1326 | |||
1130 | /* CP has detected a non standard number of lines on the incoming | 1327 | /* CP has detected a non standard number of lines on the incoming |
1131 | video compared to what it is configured to receive by s_dv_timings */ | 1328 | video compared to what it is configured to receive by s_dv_timings */ |
1132 | return io_read(sd, 0x12) & 0x01; | 1329 | return io_read(sd, 0x12) & 0x01; |
@@ -1195,28 +1392,40 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, | |||
1195 | return -1; | 1392 | return -1; |
1196 | } | 1393 | } |
1197 | 1394 | ||
1395 | |||
1198 | static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) | 1396 | static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) |
1199 | { | 1397 | { |
1398 | struct adv7604_state *state = to_state(sd); | ||
1399 | const struct adv7604_chip_info *info = state->info; | ||
1400 | u8 polarity; | ||
1401 | |||
1200 | if (no_lock_stdi(sd) || no_lock_sspd(sd)) { | 1402 | if (no_lock_stdi(sd) || no_lock_sspd(sd)) { |
1201 | v4l2_dbg(2, debug, sd, "%s: STDI and/or SSPD not locked\n", __func__); | 1403 | v4l2_dbg(2, debug, sd, "%s: STDI and/or SSPD not locked\n", __func__); |
1202 | return -1; | 1404 | return -1; |
1203 | } | 1405 | } |
1204 | 1406 | ||
1205 | /* read STDI */ | 1407 | /* read STDI */ |
1206 | stdi->bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); | 1408 | stdi->bl = cp_read16(sd, 0xb1, 0x3fff); |
1207 | stdi->lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); | 1409 | stdi->lcf = cp_read16(sd, info->lcf_reg, 0x7ff); |
1208 | stdi->lcvs = cp_read(sd, 0xb3) >> 3; | 1410 | stdi->lcvs = cp_read(sd, 0xb3) >> 3; |
1209 | stdi->interlaced = io_read(sd, 0x12) & 0x10; | 1411 | stdi->interlaced = io_read(sd, 0x12) & 0x10; |
1210 | 1412 | ||
1211 | /* read SSPD */ | 1413 | if (adv7604_has_afe(state)) { |
1212 | if ((cp_read(sd, 0xb5) & 0x03) == 0x01) { | 1414 | /* read SSPD */ |
1213 | stdi->hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? | 1415 | polarity = cp_read(sd, 0xb5); |
1214 | ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); | 1416 | if ((polarity & 0x03) == 0x01) { |
1215 | stdi->vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? | 1417 | stdi->hs_pol = polarity & 0x10 |
1216 | ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x'); | 1418 | ? (polarity & 0x08 ? '+' : '-') : 'x'; |
1419 | stdi->vs_pol = polarity & 0x40 | ||
1420 | ? (polarity & 0x20 ? '+' : '-') : 'x'; | ||
1421 | } else { | ||
1422 | stdi->hs_pol = 'x'; | ||
1423 | stdi->vs_pol = 'x'; | ||
1424 | } | ||
1217 | } else { | 1425 | } else { |
1218 | stdi->hs_pol = 'x'; | 1426 | polarity = hdmi_read(sd, 0x05); |
1219 | stdi->vs_pol = 'x'; | 1427 | stdi->hs_pol = polarity & 0x20 ? '+' : '-'; |
1428 | stdi->vs_pol = polarity & 0x10 ? '+' : '-'; | ||
1220 | } | 1429 | } |
1221 | 1430 | ||
1222 | if (no_lock_stdi(sd) || no_lock_sspd(sd)) { | 1431 | if (no_lock_stdi(sd) || no_lock_sspd(sd)) { |
@@ -1243,8 +1452,14 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) | |||
1243 | static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, | 1452 | static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, |
1244 | struct v4l2_enum_dv_timings *timings) | 1453 | struct v4l2_enum_dv_timings *timings) |
1245 | { | 1454 | { |
1455 | struct adv7604_state *state = to_state(sd); | ||
1456 | |||
1246 | if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1) | 1457 | if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1) |
1247 | return -EINVAL; | 1458 | return -EINVAL; |
1459 | |||
1460 | if (timings->pad >= state->source_pad) | ||
1461 | return -EINVAL; | ||
1462 | |||
1248 | memset(timings->reserved, 0, sizeof(timings->reserved)); | 1463 | memset(timings->reserved, 0, sizeof(timings->reserved)); |
1249 | timings->timings = adv7604_timings[timings->index]; | 1464 | timings->timings = adv7604_timings[timings->index]; |
1250 | return 0; | 1465 | return 0; |
@@ -1253,14 +1468,30 @@ static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, | |||
1253 | static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, | 1468 | static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, |
1254 | struct v4l2_dv_timings_cap *cap) | 1469 | struct v4l2_dv_timings_cap *cap) |
1255 | { | 1470 | { |
1471 | struct adv7604_state *state = to_state(sd); | ||
1472 | |||
1473 | if (cap->pad >= state->source_pad) | ||
1474 | return -EINVAL; | ||
1475 | |||
1256 | cap->type = V4L2_DV_BT_656_1120; | 1476 | cap->type = V4L2_DV_BT_656_1120; |
1257 | cap->bt.max_width = 1920; | 1477 | cap->bt.max_width = 1920; |
1258 | cap->bt.max_height = 1200; | 1478 | cap->bt.max_height = 1200; |
1259 | cap->bt.min_pixelclock = 25000000; | 1479 | cap->bt.min_pixelclock = 25000000; |
1260 | if (is_digital_input(sd)) | 1480 | |
1481 | switch (cap->pad) { | ||
1482 | case ADV7604_PAD_HDMI_PORT_A: | ||
1483 | case ADV7604_PAD_HDMI_PORT_B: | ||
1484 | case ADV7604_PAD_HDMI_PORT_C: | ||
1485 | case ADV7604_PAD_HDMI_PORT_D: | ||
1261 | cap->bt.max_pixelclock = 225000000; | 1486 | cap->bt.max_pixelclock = 225000000; |
1262 | else | 1487 | break; |
1488 | case ADV7604_PAD_VGA_RGB: | ||
1489 | case ADV7604_PAD_VGA_COMP: | ||
1490 | default: | ||
1263 | cap->bt.max_pixelclock = 170000000; | 1491 | cap->bt.max_pixelclock = 170000000; |
1492 | break; | ||
1493 | } | ||
1494 | |||
1264 | cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | | 1495 | cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | |
1265 | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT; | 1496 | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT; |
1266 | cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | | 1497 | cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | |
@@ -1284,10 +1515,43 @@ static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, | |||
1284 | } | 1515 | } |
1285 | } | 1516 | } |
1286 | 1517 | ||
1518 | static unsigned int adv7604_read_hdmi_pixelclock(struct v4l2_subdev *sd) | ||
1519 | { | ||
1520 | unsigned int freq; | ||
1521 | int a, b; | ||
1522 | |||
1523 | a = hdmi_read(sd, 0x06); | ||
1524 | b = hdmi_read(sd, 0x3b); | ||
1525 | if (a < 0 || b < 0) | ||
1526 | return 0; | ||
1527 | freq = a * 1000000 + ((b & 0x30) >> 4) * 250000; | ||
1528 | |||
1529 | if (is_hdmi(sd)) { | ||
1530 | /* adjust for deep color mode */ | ||
1531 | unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8; | ||
1532 | |||
1533 | freq = freq * 8 / bits_per_channel; | ||
1534 | } | ||
1535 | |||
1536 | return freq; | ||
1537 | } | ||
1538 | |||
1539 | static unsigned int adv7611_read_hdmi_pixelclock(struct v4l2_subdev *sd) | ||
1540 | { | ||
1541 | int a, b; | ||
1542 | |||
1543 | a = hdmi_read(sd, 0x51); | ||
1544 | b = hdmi_read(sd, 0x52); | ||
1545 | if (a < 0 || b < 0) | ||
1546 | return 0; | ||
1547 | return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128; | ||
1548 | } | ||
1549 | |||
1287 | static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | 1550 | static int adv7604_query_dv_timings(struct v4l2_subdev *sd, |
1288 | struct v4l2_dv_timings *timings) | 1551 | struct v4l2_dv_timings *timings) |
1289 | { | 1552 | { |
1290 | struct adv7604_state *state = to_state(sd); | 1553 | struct adv7604_state *state = to_state(sd); |
1554 | const struct adv7604_chip_info *info = state->info; | ||
1291 | struct v4l2_bt_timings *bt = &timings->bt; | 1555 | struct v4l2_bt_timings *bt = &timings->bt; |
1292 | struct stdi_readback stdi; | 1556 | struct stdi_readback stdi; |
1293 | 1557 | ||
@@ -1311,44 +1575,25 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | |||
1311 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; | 1575 | V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; |
1312 | 1576 | ||
1313 | if (is_digital_input(sd)) { | 1577 | if (is_digital_input(sd)) { |
1314 | uint32_t freq; | ||
1315 | |||
1316 | timings->type = V4L2_DV_BT_656_1120; | 1578 | timings->type = V4L2_DV_BT_656_1120; |
1317 | 1579 | ||
1318 | bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08); | 1580 | /* FIXME: All masks are incorrect for ADV7611 */ |
1319 | bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a); | 1581 | bt->width = hdmi_read16(sd, 0x07, 0xfff); |
1320 | freq = (hdmi_read(sd, 0x06) * 1000000) + | 1582 | bt->height = hdmi_read16(sd, 0x09, 0xfff); |
1321 | ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000; | 1583 | bt->pixelclock = info->read_hdmi_pixelclock(sd); |
1322 | if (is_hdmi(sd)) { | 1584 | bt->hfrontporch = hdmi_read16(sd, 0x20, 0x3ff); |
1323 | /* adjust for deep color mode */ | 1585 | bt->hsync = hdmi_read16(sd, 0x22, 0x3ff); |
1324 | unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8; | 1586 | bt->hbackporch = hdmi_read16(sd, 0x24, 0x3ff); |
1325 | 1587 | bt->vfrontporch = hdmi_read16(sd, 0x2a, 0x1fff) / 2; | |
1326 | freq = freq * 8 / bits_per_channel; | 1588 | bt->vsync = hdmi_read16(sd, 0x2e, 0x1fff) / 2; |
1327 | } | 1589 | bt->vbackporch = hdmi_read16(sd, 0x32, 0x1fff) / 2; |
1328 | bt->pixelclock = freq; | ||
1329 | bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 + | ||
1330 | hdmi_read(sd, 0x21); | ||
1331 | bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 + | ||
1332 | hdmi_read(sd, 0x23); | ||
1333 | bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 + | ||
1334 | hdmi_read(sd, 0x25); | ||
1335 | bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 + | ||
1336 | hdmi_read(sd, 0x2b)) / 2; | ||
1337 | bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 + | ||
1338 | hdmi_read(sd, 0x2f)) / 2; | ||
1339 | bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 + | ||
1340 | hdmi_read(sd, 0x33)) / 2; | ||
1341 | bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | | 1590 | bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | |
1342 | ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); | 1591 | ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); |
1343 | if (bt->interlaced == V4L2_DV_INTERLACED) { | 1592 | if (bt->interlaced == V4L2_DV_INTERLACED) { |
1344 | bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 + | 1593 | bt->height += hdmi_read16(sd, 0x0b, 0xfff); |
1345 | hdmi_read(sd, 0x0c); | 1594 | bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2; |
1346 | bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 + | 1595 | bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; |
1347 | hdmi_read(sd, 0x2d)) / 2; | 1596 | bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; |
1348 | bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + | ||
1349 | hdmi_read(sd, 0x31)) / 2; | ||
1350 | bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + | ||
1351 | hdmi_read(sd, 0x35)) / 2; | ||
1352 | } | 1597 | } |
1353 | adv7604_fill_optional_dv_timings_fields(sd, timings); | 1598 | adv7604_fill_optional_dv_timings_fields(sd, timings); |
1354 | } else { | 1599 | } else { |
@@ -1378,11 +1623,11 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | |||
1378 | v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); | 1623 | v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); |
1379 | /* TODO restart STDI for Sync Channel 2 */ | 1624 | /* TODO restart STDI for Sync Channel 2 */ |
1380 | /* enter one-shot mode */ | 1625 | /* enter one-shot mode */ |
1381 | cp_write_and_or(sd, 0x86, 0xf9, 0x00); | 1626 | cp_write_clr_set(sd, 0x86, 0x06, 0x00); |
1382 | /* trigger STDI restart */ | 1627 | /* trigger STDI restart */ |
1383 | cp_write_and_or(sd, 0x86, 0xf9, 0x04); | 1628 | cp_write_clr_set(sd, 0x86, 0x06, 0x04); |
1384 | /* reset to continuous mode */ | 1629 | /* reset to continuous mode */ |
1385 | cp_write_and_or(sd, 0x86, 0xf9, 0x02); | 1630 | cp_write_clr_set(sd, 0x86, 0x06, 0x02); |
1386 | state->restart_stdi_once = false; | 1631 | state->restart_stdi_once = false; |
1387 | return -ENOLINK; | 1632 | return -ENOLINK; |
1388 | } | 1633 | } |
@@ -1441,7 +1686,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, | |||
1441 | 1686 | ||
1442 | state->timings = *timings; | 1687 | state->timings = *timings; |
1443 | 1688 | ||
1444 | cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10); | 1689 | cp_write_clr_set(sd, 0x91, 0x40, bt->interlaced ? 0x40 : 0x00); |
1445 | 1690 | ||
1446 | /* Use prim_mode and vid_std when available */ | 1691 | /* Use prim_mode and vid_std when available */ |
1447 | err = configure_predefined_video_timings(sd, timings); | 1692 | err = configure_predefined_video_timings(sd, timings); |
@@ -1468,6 +1713,16 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd, | |||
1468 | return 0; | 1713 | return 0; |
1469 | } | 1714 | } |
1470 | 1715 | ||
1716 | static void adv7604_set_termination(struct v4l2_subdev *sd, bool enable) | ||
1717 | { | ||
1718 | hdmi_write(sd, 0x01, enable ? 0x00 : 0x78); | ||
1719 | } | ||
1720 | |||
1721 | static void adv7611_set_termination(struct v4l2_subdev *sd, bool enable) | ||
1722 | { | ||
1723 | hdmi_write(sd, 0x83, enable ? 0xfe : 0xff); | ||
1724 | } | ||
1725 | |||
1471 | static void enable_input(struct v4l2_subdev *sd) | 1726 | static void enable_input(struct v4l2_subdev *sd) |
1472 | { | 1727 | { |
1473 | struct adv7604_state *state = to_state(sd); | 1728 | struct adv7604_state *state = to_state(sd); |
@@ -1475,10 +1730,10 @@ static void enable_input(struct v4l2_subdev *sd) | |||
1475 | if (is_analog_input(sd)) { | 1730 | if (is_analog_input(sd)) { |
1476 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ | 1731 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ |
1477 | } else if (is_digital_input(sd)) { | 1732 | } else if (is_digital_input(sd)) { |
1478 | hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input); | 1733 | hdmi_write_clr_set(sd, 0x00, 0x03, state->selected_input); |
1479 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ | 1734 | state->info->set_termination(sd, true); |
1480 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ | 1735 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ |
1481 | hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ | 1736 | hdmi_write_clr_set(sd, 0x1a, 0x10, 0x00); /* Unmute audio */ |
1482 | } else { | 1737 | } else { |
1483 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", | 1738 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", |
1484 | __func__, state->selected_input); | 1739 | __func__, state->selected_input); |
@@ -1487,67 +1742,36 @@ static void enable_input(struct v4l2_subdev *sd) | |||
1487 | 1742 | ||
1488 | static void disable_input(struct v4l2_subdev *sd) | 1743 | static void disable_input(struct v4l2_subdev *sd) |
1489 | { | 1744 | { |
1490 | hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio */ | 1745 | struct adv7604_state *state = to_state(sd); |
1746 | |||
1747 | hdmi_write_clr_set(sd, 0x1a, 0x10, 0x10); /* Mute audio */ | ||
1491 | msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ | 1748 | msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ |
1492 | io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ | 1749 | io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ |
1493 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ | 1750 | state->info->set_termination(sd, false); |
1494 | } | 1751 | } |
1495 | 1752 | ||
1496 | static void select_input(struct v4l2_subdev *sd) | 1753 | static void select_input(struct v4l2_subdev *sd) |
1497 | { | 1754 | { |
1498 | struct adv7604_state *state = to_state(sd); | 1755 | struct adv7604_state *state = to_state(sd); |
1756 | const struct adv7604_chip_info *info = state->info; | ||
1499 | 1757 | ||
1500 | if (is_analog_input(sd)) { | 1758 | if (is_analog_input(sd)) { |
1501 | /* reset ADI recommended settings for HDMI: */ | 1759 | adv7604_write_reg_seq(sd, info->recommended_settings[0]); |
1502 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | ||
1503 | hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ | ||
1504 | hdmi_write(sd, 0x3d, 0x00); /* DDC bus active pull-up control */ | ||
1505 | hdmi_write(sd, 0x3e, 0x74); /* TMDS PLL optimization */ | ||
1506 | hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */ | ||
1507 | hdmi_write(sd, 0x57, 0x74); /* TMDS PLL optimization */ | ||
1508 | hdmi_write(sd, 0x58, 0x63); /* TMDS PLL optimization */ | ||
1509 | hdmi_write(sd, 0x8d, 0x18); /* equaliser */ | ||
1510 | hdmi_write(sd, 0x8e, 0x34); /* equaliser */ | ||
1511 | hdmi_write(sd, 0x93, 0x88); /* equaliser */ | ||
1512 | hdmi_write(sd, 0x94, 0x2e); /* equaliser */ | ||
1513 | hdmi_write(sd, 0x96, 0x00); /* enable automatic EQ changing */ | ||
1514 | 1760 | ||
1515 | afe_write(sd, 0x00, 0x08); /* power up ADC */ | 1761 | afe_write(sd, 0x00, 0x08); /* power up ADC */ |
1516 | afe_write(sd, 0x01, 0x06); /* power up Analog Front End */ | 1762 | afe_write(sd, 0x01, 0x06); /* power up Analog Front End */ |
1517 | afe_write(sd, 0xc8, 0x00); /* phase control */ | 1763 | afe_write(sd, 0xc8, 0x00); /* phase control */ |
1518 | |||
1519 | /* set ADI recommended settings for digitizer */ | ||
1520 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ | ||
1521 | afe_write(sd, 0x12, 0x7b); /* ADC noise shaping filter controls */ | ||
1522 | afe_write(sd, 0x0c, 0x1f); /* CP core gain controls */ | ||
1523 | cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ | ||
1524 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ | ||
1525 | cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ | ||
1526 | } else if (is_digital_input(sd)) { | 1764 | } else if (is_digital_input(sd)) { |
1527 | hdmi_write(sd, 0x00, state->selected_input & 0x03); | 1765 | hdmi_write(sd, 0x00, state->selected_input & 0x03); |
1528 | 1766 | ||
1529 | /* set ADI recommended settings for HDMI: */ | 1767 | adv7604_write_reg_seq(sd, info->recommended_settings[1]); |
1530 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | 1768 | |
1531 | hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ | 1769 | if (adv7604_has_afe(state)) { |
1532 | hdmi_write(sd, 0x3d, 0x10); /* DDC bus active pull-up control */ | 1770 | afe_write(sd, 0x00, 0xff); /* power down ADC */ |
1533 | hdmi_write(sd, 0x3e, 0x39); /* TMDS PLL optimization */ | 1771 | afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */ |
1534 | hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */ | 1772 | afe_write(sd, 0xc8, 0x40); /* phase control */ |
1535 | hdmi_write(sd, 0x57, 0xb6); /* TMDS PLL optimization */ | 1773 | } |
1536 | hdmi_write(sd, 0x58, 0x03); /* TMDS PLL optimization */ | 1774 | |
1537 | hdmi_write(sd, 0x8d, 0x18); /* equaliser */ | ||
1538 | hdmi_write(sd, 0x8e, 0x34); /* equaliser */ | ||
1539 | hdmi_write(sd, 0x93, 0x8b); /* equaliser */ | ||
1540 | hdmi_write(sd, 0x94, 0x2d); /* equaliser */ | ||
1541 | hdmi_write(sd, 0x96, 0x01); /* enable automatic EQ changing */ | ||
1542 | |||
1543 | afe_write(sd, 0x00, 0xff); /* power down ADC */ | ||
1544 | afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */ | ||
1545 | afe_write(sd, 0xc8, 0x40); /* phase control */ | ||
1546 | |||
1547 | /* reset ADI recommended settings for digitizer */ | ||
1548 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ | ||
1549 | afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */ | ||
1550 | afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */ | ||
1551 | cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ | 1775 | cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ |
1552 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ | 1776 | cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ |
1553 | cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */ | 1777 | cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */ |
@@ -1568,6 +1792,9 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, | |||
1568 | if (input == state->selected_input) | 1792 | if (input == state->selected_input) |
1569 | return 0; | 1793 | return 0; |
1570 | 1794 | ||
1795 | if (input > state->info->max_port) | ||
1796 | return -EINVAL; | ||
1797 | |||
1571 | state->selected_input = input; | 1798 | state->selected_input = input; |
1572 | 1799 | ||
1573 | disable_input(sd); | 1800 | disable_input(sd); |
@@ -1579,34 +1806,139 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, | |||
1579 | return 0; | 1806 | return 0; |
1580 | } | 1807 | } |
1581 | 1808 | ||
1582 | static int adv7604_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, | 1809 | static int adv7604_enum_mbus_code(struct v4l2_subdev *sd, |
1583 | enum v4l2_mbus_pixelcode *code) | 1810 | struct v4l2_subdev_fh *fh, |
1811 | struct v4l2_subdev_mbus_code_enum *code) | ||
1812 | { | ||
1813 | struct adv7604_state *state = to_state(sd); | ||
1814 | |||
1815 | if (code->index >= state->info->nformats) | ||
1816 | return -EINVAL; | ||
1817 | |||
1818 | code->code = state->info->formats[code->index].code; | ||
1819 | |||
1820 | return 0; | ||
1821 | } | ||
1822 | |||
1823 | static void adv7604_fill_format(struct adv7604_state *state, | ||
1824 | struct v4l2_mbus_framefmt *format) | ||
1825 | { | ||
1826 | memset(format, 0, sizeof(*format)); | ||
1827 | |||
1828 | format->width = state->timings.bt.width; | ||
1829 | format->height = state->timings.bt.height; | ||
1830 | format->field = V4L2_FIELD_NONE; | ||
1831 | |||
1832 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) | ||
1833 | format->colorspace = (state->timings.bt.height <= 576) ? | ||
1834 | V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; | ||
1835 | } | ||
1836 | |||
1837 | /* | ||
1838 | * Compute the op_ch_sel value required to obtain on the bus the component order | ||
1839 | * corresponding to the selected format taking into account bus reordering | ||
1840 | * applied by the board at the output of the device. | ||
1841 | * | ||
1842 | * The following table gives the op_ch_value from the format component order | ||
1843 | * (expressed as op_ch_sel value in column) and the bus reordering (expressed as | ||
1844 | * adv7604_bus_order value in row). | ||
1845 | * | ||
1846 | * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5) | ||
1847 | * ----------+------------------------------------------------- | ||
1848 | * RGB (NOP) | GBR GRB BGR RGB BRG RBG | ||
1849 | * GRB (1-2) | BGR RGB GBR GRB RBG BRG | ||
1850 | * RBG (2-3) | GRB GBR BRG RBG BGR RGB | ||
1851 | * BGR (1-3) | RBG BRG RGB BGR GRB GBR | ||
1852 | * BRG (ROR) | BRG RBG GRB GBR RGB BGR | ||
1853 | * GBR (ROL) | RGB BGR RBG BRG GBR GRB | ||
1854 | */ | ||
1855 | static unsigned int adv7604_op_ch_sel(struct adv7604_state *state) | ||
1856 | { | ||
1857 | #define _SEL(a,b,c,d,e,f) { \ | ||
1858 | ADV7604_OP_CH_SEL_##a, ADV7604_OP_CH_SEL_##b, ADV7604_OP_CH_SEL_##c, \ | ||
1859 | ADV7604_OP_CH_SEL_##d, ADV7604_OP_CH_SEL_##e, ADV7604_OP_CH_SEL_##f } | ||
1860 | #define _BUS(x) [ADV7604_BUS_ORDER_##x] | ||
1861 | |||
1862 | static const unsigned int op_ch_sel[6][6] = { | ||
1863 | _BUS(RGB) /* NOP */ = _SEL(GBR, GRB, BGR, RGB, BRG, RBG), | ||
1864 | _BUS(GRB) /* 1-2 */ = _SEL(BGR, RGB, GBR, GRB, RBG, BRG), | ||
1865 | _BUS(RBG) /* 2-3 */ = _SEL(GRB, GBR, BRG, RBG, BGR, RGB), | ||
1866 | _BUS(BGR) /* 1-3 */ = _SEL(RBG, BRG, RGB, BGR, GRB, GBR), | ||
1867 | _BUS(BRG) /* ROR */ = _SEL(BRG, RBG, GRB, GBR, RGB, BGR), | ||
1868 | _BUS(GBR) /* ROL */ = _SEL(RGB, BGR, RBG, BRG, GBR, GRB), | ||
1869 | }; | ||
1870 | |||
1871 | return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5]; | ||
1872 | } | ||
1873 | |||
1874 | static void adv7604_setup_format(struct adv7604_state *state) | ||
1875 | { | ||
1876 | struct v4l2_subdev *sd = &state->sd; | ||
1877 | |||
1878 | io_write_clr_set(sd, 0x02, 0x02, | ||
1879 | state->format->rgb_out ? ADV7604_RGB_OUT : 0); | ||
1880 | io_write(sd, 0x03, state->format->op_format_sel | | ||
1881 | state->pdata.op_format_mode_sel); | ||
1882 | io_write_clr_set(sd, 0x04, 0xe0, adv7604_op_ch_sel(state)); | ||
1883 | io_write_clr_set(sd, 0x05, 0x01, | ||
1884 | state->format->swap_cb_cr ? ADV7604_OP_SWAP_CB_CR : 0); | ||
1885 | } | ||
1886 | |||
1887 | static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1888 | struct v4l2_subdev_format *format) | ||
1584 | { | 1889 | { |
1585 | if (index) | 1890 | struct adv7604_state *state = to_state(sd); |
1891 | |||
1892 | if (format->pad != state->source_pad) | ||
1586 | return -EINVAL; | 1893 | return -EINVAL; |
1587 | /* Good enough for now */ | 1894 | |
1588 | *code = V4L2_MBUS_FMT_FIXED; | 1895 | adv7604_fill_format(state, &format->format); |
1896 | |||
1897 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1898 | struct v4l2_mbus_framefmt *fmt; | ||
1899 | |||
1900 | fmt = v4l2_subdev_get_try_format(fh, format->pad); | ||
1901 | format->format.code = fmt->code; | ||
1902 | } else { | ||
1903 | format->format.code = state->format->code; | ||
1904 | } | ||
1905 | |||
1589 | return 0; | 1906 | return 0; |
1590 | } | 1907 | } |
1591 | 1908 | ||
1592 | static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd, | 1909 | static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, |
1593 | struct v4l2_mbus_framefmt *fmt) | 1910 | struct v4l2_subdev_format *format) |
1594 | { | 1911 | { |
1595 | struct adv7604_state *state = to_state(sd); | 1912 | struct adv7604_state *state = to_state(sd); |
1913 | const struct adv7604_format_info *info; | ||
1596 | 1914 | ||
1597 | fmt->width = state->timings.bt.width; | 1915 | if (format->pad != state->source_pad) |
1598 | fmt->height = state->timings.bt.height; | 1916 | return -EINVAL; |
1599 | fmt->code = V4L2_MBUS_FMT_FIXED; | 1917 | |
1600 | fmt->field = V4L2_FIELD_NONE; | 1918 | info = adv7604_format_info(state, format->format.code); |
1601 | if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { | 1919 | if (info == NULL) |
1602 | fmt->colorspace = (state->timings.bt.height <= 576) ? | 1920 | info = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8); |
1603 | V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; | 1921 | |
1922 | adv7604_fill_format(state, &format->format); | ||
1923 | format->format.code = info->code; | ||
1924 | |||
1925 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1926 | struct v4l2_mbus_framefmt *fmt; | ||
1927 | |||
1928 | fmt = v4l2_subdev_get_try_format(fh, format->pad); | ||
1929 | fmt->code = format->format.code; | ||
1930 | } else { | ||
1931 | state->format = info; | ||
1932 | adv7604_setup_format(state); | ||
1604 | } | 1933 | } |
1934 | |||
1605 | return 0; | 1935 | return 0; |
1606 | } | 1936 | } |
1607 | 1937 | ||
1608 | static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | 1938 | static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
1609 | { | 1939 | { |
1940 | struct adv7604_state *state = to_state(sd); | ||
1941 | const struct adv7604_chip_info *info = state->info; | ||
1610 | const u8 irq_reg_0x43 = io_read(sd, 0x43); | 1942 | const u8 irq_reg_0x43 = io_read(sd, 0x43); |
1611 | const u8 irq_reg_0x6b = io_read(sd, 0x6b); | 1943 | const u8 irq_reg_0x6b = io_read(sd, 0x6b); |
1612 | const u8 irq_reg_0x70 = io_read(sd, 0x70); | 1944 | const u8 irq_reg_0x70 = io_read(sd, 0x70); |
@@ -1625,7 +1957,9 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1625 | 1957 | ||
1626 | /* format change */ | 1958 | /* format change */ |
1627 | fmt_change = irq_reg_0x43 & 0x98; | 1959 | fmt_change = irq_reg_0x43 & 0x98; |
1628 | fmt_change_digital = is_digital_input(sd) ? (irq_reg_0x6b & 0xc0) : 0; | 1960 | fmt_change_digital = is_digital_input(sd) |
1961 | ? irq_reg_0x6b & info->fmt_change_digital_mask | ||
1962 | : 0; | ||
1629 | 1963 | ||
1630 | if (fmt_change || fmt_change_digital) { | 1964 | if (fmt_change || fmt_change_digital) { |
1631 | v4l2_dbg(1, debug, sd, | 1965 | v4l2_dbg(1, debug, sd, |
@@ -1647,7 +1981,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |||
1647 | } | 1981 | } |
1648 | 1982 | ||
1649 | /* tx 5v detect */ | 1983 | /* tx 5v detect */ |
1650 | tx_5v = io_read(sd, 0x70) & 0x1e; | 1984 | tx_5v = io_read(sd, 0x70) & info->cable_det_mask; |
1651 | if (tx_5v) { | 1985 | if (tx_5v) { |
1652 | v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); | 1986 | v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); |
1653 | io_write(sd, 0x71, tx_5v); | 1987 | io_write(sd, 0x71, tx_5v); |
@@ -1663,7 +1997,7 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | |||
1663 | struct adv7604_state *state = to_state(sd); | 1997 | struct adv7604_state *state = to_state(sd); |
1664 | u8 *data = NULL; | 1998 | u8 *data = NULL; |
1665 | 1999 | ||
1666 | if (edid->pad > ADV7604_EDID_PORT_D) | 2000 | if (edid->pad > ADV7604_PAD_HDMI_PORT_D) |
1667 | return -EINVAL; | 2001 | return -EINVAL; |
1668 | if (edid->blocks == 0) | 2002 | if (edid->blocks == 0) |
1669 | return -EINVAL; | 2003 | return -EINVAL; |
@@ -1678,10 +2012,10 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | |||
1678 | edid->blocks = state->edid.blocks; | 2012 | edid->blocks = state->edid.blocks; |
1679 | 2013 | ||
1680 | switch (edid->pad) { | 2014 | switch (edid->pad) { |
1681 | case ADV7604_EDID_PORT_A: | 2015 | case ADV7604_PAD_HDMI_PORT_A: |
1682 | case ADV7604_EDID_PORT_B: | 2016 | case ADV7604_PAD_HDMI_PORT_B: |
1683 | case ADV7604_EDID_PORT_C: | 2017 | case ADV7604_PAD_HDMI_PORT_C: |
1684 | case ADV7604_EDID_PORT_D: | 2018 | case ADV7604_PAD_HDMI_PORT_D: |
1685 | if (state->edid.present & (1 << edid->pad)) | 2019 | if (state->edid.present & (1 << edid->pad)) |
1686 | data = state->edid.edid; | 2020 | data = state->edid.edid; |
1687 | break; | 2021 | break; |
@@ -1729,20 +2063,20 @@ static int get_edid_spa_location(const u8 *edid) | |||
1729 | static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | 2063 | static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) |
1730 | { | 2064 | { |
1731 | struct adv7604_state *state = to_state(sd); | 2065 | struct adv7604_state *state = to_state(sd); |
2066 | const struct adv7604_chip_info *info = state->info; | ||
1732 | int spa_loc; | 2067 | int spa_loc; |
1733 | int tmp = 0; | ||
1734 | int err; | 2068 | int err; |
1735 | int i; | 2069 | int i; |
1736 | 2070 | ||
1737 | if (edid->pad > ADV7604_EDID_PORT_D) | 2071 | if (edid->pad > ADV7604_PAD_HDMI_PORT_D) |
1738 | return -EINVAL; | 2072 | return -EINVAL; |
1739 | if (edid->start_block != 0) | 2073 | if (edid->start_block != 0) |
1740 | return -EINVAL; | 2074 | return -EINVAL; |
1741 | if (edid->blocks == 0) { | 2075 | if (edid->blocks == 0) { |
1742 | /* Disable hotplug and I2C access to EDID RAM from DDC port */ | 2076 | /* Disable hotplug and I2C access to EDID RAM from DDC port */ |
1743 | state->edid.present &= ~(1 << edid->pad); | 2077 | state->edid.present &= ~(1 << edid->pad); |
1744 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); | 2078 | adv7604_set_hpd(state, state->edid.present); |
1745 | rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); | 2079 | rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); |
1746 | 2080 | ||
1747 | /* Fall back to a 16:9 aspect ratio */ | 2081 | /* Fall back to a 16:9 aspect ratio */ |
1748 | state->aspect_ratio.numerator = 16; | 2082 | state->aspect_ratio.numerator = 16; |
@@ -1765,35 +2099,41 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | |||
1765 | 2099 | ||
1766 | /* Disable hotplug and I2C access to EDID RAM from DDC port */ | 2100 | /* Disable hotplug and I2C access to EDID RAM from DDC port */ |
1767 | cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); | 2101 | cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); |
1768 | v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); | 2102 | adv7604_set_hpd(state, 0); |
1769 | rep_write_and_or(sd, 0x77, 0xf0, 0x00); | 2103 | rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); |
1770 | 2104 | ||
1771 | spa_loc = get_edid_spa_location(edid->edid); | 2105 | spa_loc = get_edid_spa_location(edid->edid); |
1772 | if (spa_loc < 0) | 2106 | if (spa_loc < 0) |
1773 | spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ | 2107 | spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ |
1774 | 2108 | ||
1775 | switch (edid->pad) { | 2109 | switch (edid->pad) { |
1776 | case ADV7604_EDID_PORT_A: | 2110 | case ADV7604_PAD_HDMI_PORT_A: |
1777 | state->spa_port_a[0] = edid->edid[spa_loc]; | 2111 | state->spa_port_a[0] = edid->edid[spa_loc]; |
1778 | state->spa_port_a[1] = edid->edid[spa_loc + 1]; | 2112 | state->spa_port_a[1] = edid->edid[spa_loc + 1]; |
1779 | break; | 2113 | break; |
1780 | case ADV7604_EDID_PORT_B: | 2114 | case ADV7604_PAD_HDMI_PORT_B: |
1781 | rep_write(sd, 0x70, edid->edid[spa_loc]); | 2115 | rep_write(sd, 0x70, edid->edid[spa_loc]); |
1782 | rep_write(sd, 0x71, edid->edid[spa_loc + 1]); | 2116 | rep_write(sd, 0x71, edid->edid[spa_loc + 1]); |
1783 | break; | 2117 | break; |
1784 | case ADV7604_EDID_PORT_C: | 2118 | case ADV7604_PAD_HDMI_PORT_C: |
1785 | rep_write(sd, 0x72, edid->edid[spa_loc]); | 2119 | rep_write(sd, 0x72, edid->edid[spa_loc]); |
1786 | rep_write(sd, 0x73, edid->edid[spa_loc + 1]); | 2120 | rep_write(sd, 0x73, edid->edid[spa_loc + 1]); |
1787 | break; | 2121 | break; |
1788 | case ADV7604_EDID_PORT_D: | 2122 | case ADV7604_PAD_HDMI_PORT_D: |
1789 | rep_write(sd, 0x74, edid->edid[spa_loc]); | 2123 | rep_write(sd, 0x74, edid->edid[spa_loc]); |
1790 | rep_write(sd, 0x75, edid->edid[spa_loc + 1]); | 2124 | rep_write(sd, 0x75, edid->edid[spa_loc + 1]); |
1791 | break; | 2125 | break; |
1792 | default: | 2126 | default: |
1793 | return -EINVAL; | 2127 | return -EINVAL; |
1794 | } | 2128 | } |
1795 | rep_write(sd, 0x76, spa_loc & 0xff); | 2129 | |
1796 | rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); | 2130 | if (info->type == ADV7604) { |
2131 | rep_write(sd, 0x76, spa_loc & 0xff); | ||
2132 | rep_write_clr_set(sd, 0x77, 0x40, (spa_loc & 0x100) >> 2); | ||
2133 | } else { | ||
2134 | /* FIXME: Where is the SPA location LSB register ? */ | ||
2135 | rep_write_clr_set(sd, 0x71, 0x01, (spa_loc & 0x100) >> 8); | ||
2136 | } | ||
1797 | 2137 | ||
1798 | edid->edid[spa_loc] = state->spa_port_a[0]; | 2138 | edid->edid[spa_loc] = state->spa_port_a[0]; |
1799 | edid->edid[spa_loc + 1] = state->spa_port_a[1]; | 2139 | edid->edid[spa_loc + 1] = state->spa_port_a[1]; |
@@ -1812,10 +2152,10 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | |||
1812 | 2152 | ||
1813 | /* adv7604 calculates the checksums and enables I2C access to internal | 2153 | /* adv7604 calculates the checksums and enables I2C access to internal |
1814 | EDID RAM from DDC port. */ | 2154 | EDID RAM from DDC port. */ |
1815 | rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); | 2155 | rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); |
1816 | 2156 | ||
1817 | for (i = 0; i < 1000; i++) { | 2157 | for (i = 0; i < 1000; i++) { |
1818 | if (rep_read(sd, 0x7d) & state->edid.present) | 2158 | if (rep_read(sd, info->edid_status_reg) & state->edid.present) |
1819 | break; | 2159 | break; |
1820 | mdelay(1); | 2160 | mdelay(1); |
1821 | } | 2161 | } |
@@ -1878,17 +2218,20 @@ static void print_avi_infoframe(struct v4l2_subdev *sd) | |||
1878 | static int adv7604_log_status(struct v4l2_subdev *sd) | 2218 | static int adv7604_log_status(struct v4l2_subdev *sd) |
1879 | { | 2219 | { |
1880 | struct adv7604_state *state = to_state(sd); | 2220 | struct adv7604_state *state = to_state(sd); |
2221 | const struct adv7604_chip_info *info = state->info; | ||
1881 | struct v4l2_dv_timings timings; | 2222 | struct v4l2_dv_timings timings; |
1882 | struct stdi_readback stdi; | 2223 | struct stdi_readback stdi; |
1883 | u8 reg_io_0x02 = io_read(sd, 0x02); | 2224 | u8 reg_io_0x02 = io_read(sd, 0x02); |
2225 | u8 edid_enabled; | ||
2226 | u8 cable_det; | ||
1884 | 2227 | ||
1885 | char *csc_coeff_sel_rb[16] = { | 2228 | static const char * const csc_coeff_sel_rb[16] = { |
1886 | "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", | 2229 | "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", |
1887 | "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", | 2230 | "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", |
1888 | "reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709", | 2231 | "reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709", |
1889 | "reserved", "reserved", "reserved", "reserved", "manual" | 2232 | "reserved", "reserved", "reserved", "reserved", "manual" |
1890 | }; | 2233 | }; |
1891 | char *input_color_space_txt[16] = { | 2234 | static const char * const input_color_space_txt[16] = { |
1892 | "RGB limited range (16-235)", "RGB full range (0-255)", | 2235 | "RGB limited range (16-235)", "RGB full range (0-255)", |
1893 | "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", | 2236 | "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", |
1894 | "xvYCC Bt.601", "xvYCC Bt.709", | 2237 | "xvYCC Bt.601", "xvYCC Bt.709", |
@@ -1896,12 +2239,12 @@ static int adv7604_log_status(struct v4l2_subdev *sd) | |||
1896 | "invalid", "invalid", "invalid", "invalid", "invalid", | 2239 | "invalid", "invalid", "invalid", "invalid", "invalid", |
1897 | "invalid", "invalid", "automatic" | 2240 | "invalid", "invalid", "automatic" |
1898 | }; | 2241 | }; |
1899 | char *rgb_quantization_range_txt[] = { | 2242 | static const char * const rgb_quantization_range_txt[] = { |
1900 | "Automatic", | 2243 | "Automatic", |
1901 | "RGB limited range (16-235)", | 2244 | "RGB limited range (16-235)", |
1902 | "RGB full range (0-255)", | 2245 | "RGB full range (0-255)", |
1903 | }; | 2246 | }; |
1904 | char *deep_color_mode_txt[4] = { | 2247 | static const char * const deep_color_mode_txt[4] = { |
1905 | "8-bits per channel", | 2248 | "8-bits per channel", |
1906 | "10-bits per channel", | 2249 | "10-bits per channel", |
1907 | "12-bits per channel", | 2250 | "12-bits per channel", |
@@ -1910,20 +2253,22 @@ static int adv7604_log_status(struct v4l2_subdev *sd) | |||
1910 | 2253 | ||
1911 | v4l2_info(sd, "-----Chip status-----\n"); | 2254 | v4l2_info(sd, "-----Chip status-----\n"); |
1912 | v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); | 2255 | v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); |
2256 | edid_enabled = rep_read(sd, info->edid_status_reg); | ||
1913 | v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n", | 2257 | v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n", |
1914 | ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"), | 2258 | ((edid_enabled & 0x01) ? "Yes" : "No"), |
1915 | ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"), | 2259 | ((edid_enabled & 0x02) ? "Yes" : "No"), |
1916 | ((rep_read(sd, 0x7d) & 0x04) ? "Yes" : "No"), | 2260 | ((edid_enabled & 0x04) ? "Yes" : "No"), |
1917 | ((rep_read(sd, 0x7d) & 0x08) ? "Yes" : "No")); | 2261 | ((edid_enabled & 0x08) ? "Yes" : "No")); |
1918 | v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? | 2262 | v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? |
1919 | "enabled" : "disabled"); | 2263 | "enabled" : "disabled"); |
1920 | 2264 | ||
1921 | v4l2_info(sd, "-----Signal status-----\n"); | 2265 | v4l2_info(sd, "-----Signal status-----\n"); |
2266 | cable_det = info->read_cable_det(sd); | ||
1922 | v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n", | 2267 | v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n", |
1923 | ((io_read(sd, 0x6f) & 0x10) ? "Yes" : "No"), | 2268 | ((cable_det & 0x01) ? "Yes" : "No"), |
1924 | ((io_read(sd, 0x6f) & 0x08) ? "Yes" : "No"), | 2269 | ((cable_det & 0x02) ? "Yes" : "No"), |
1925 | ((io_read(sd, 0x6f) & 0x04) ? "Yes" : "No"), | 2270 | ((cable_det & 0x04) ? "Yes" : "No"), |
1926 | ((io_read(sd, 0x6f) & 0x02) ? "Yes" : "No")); | 2271 | ((cable_det & 0x08) ? "Yes" : "No")); |
1927 | v4l2_info(sd, "TMDS signal detected: %s\n", | 2272 | v4l2_info(sd, "TMDS signal detected: %s\n", |
1928 | no_signal_tmds(sd) ? "false" : "true"); | 2273 | no_signal_tmds(sd) ? "false" : "true"); |
1929 | v4l2_info(sd, "TMDS signal locked: %s\n", | 2274 | v4l2_info(sd, "TMDS signal locked: %s\n", |
@@ -2017,13 +2362,6 @@ static const struct v4l2_ctrl_ops adv7604_ctrl_ops = { | |||
2017 | 2362 | ||
2018 | static const struct v4l2_subdev_core_ops adv7604_core_ops = { | 2363 | static const struct v4l2_subdev_core_ops adv7604_core_ops = { |
2019 | .log_status = adv7604_log_status, | 2364 | .log_status = adv7604_log_status, |
2020 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
2021 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
2022 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
2023 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
2024 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
2025 | .queryctrl = v4l2_subdev_queryctrl, | ||
2026 | .querymenu = v4l2_subdev_querymenu, | ||
2027 | .interrupt_service_routine = adv7604_isr, | 2365 | .interrupt_service_routine = adv7604_isr, |
2028 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 2366 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
2029 | .g_register = adv7604_g_register, | 2367 | .g_register = adv7604_g_register, |
@@ -2037,17 +2375,16 @@ static const struct v4l2_subdev_video_ops adv7604_video_ops = { | |||
2037 | .s_dv_timings = adv7604_s_dv_timings, | 2375 | .s_dv_timings = adv7604_s_dv_timings, |
2038 | .g_dv_timings = adv7604_g_dv_timings, | 2376 | .g_dv_timings = adv7604_g_dv_timings, |
2039 | .query_dv_timings = adv7604_query_dv_timings, | 2377 | .query_dv_timings = adv7604_query_dv_timings, |
2040 | .enum_dv_timings = adv7604_enum_dv_timings, | ||
2041 | .dv_timings_cap = adv7604_dv_timings_cap, | ||
2042 | .enum_mbus_fmt = adv7604_enum_mbus_fmt, | ||
2043 | .g_mbus_fmt = adv7604_g_mbus_fmt, | ||
2044 | .try_mbus_fmt = adv7604_g_mbus_fmt, | ||
2045 | .s_mbus_fmt = adv7604_g_mbus_fmt, | ||
2046 | }; | 2378 | }; |
2047 | 2379 | ||
2048 | static const struct v4l2_subdev_pad_ops adv7604_pad_ops = { | 2380 | static const struct v4l2_subdev_pad_ops adv7604_pad_ops = { |
2381 | .enum_mbus_code = adv7604_enum_mbus_code, | ||
2382 | .get_fmt = adv7604_get_format, | ||
2383 | .set_fmt = adv7604_set_format, | ||
2049 | .get_edid = adv7604_get_edid, | 2384 | .get_edid = adv7604_get_edid, |
2050 | .set_edid = adv7604_set_edid, | 2385 | .set_edid = adv7604_set_edid, |
2386 | .dv_timings_cap = adv7604_dv_timings_cap, | ||
2387 | .enum_dv_timings = adv7604_enum_dv_timings, | ||
2051 | }; | 2388 | }; |
2052 | 2389 | ||
2053 | static const struct v4l2_subdev_ops adv7604_ops = { | 2390 | static const struct v4l2_subdev_ops adv7604_ops = { |
@@ -2096,6 +2433,7 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = { | |||
2096 | static int adv7604_core_init(struct v4l2_subdev *sd) | 2433 | static int adv7604_core_init(struct v4l2_subdev *sd) |
2097 | { | 2434 | { |
2098 | struct adv7604_state *state = to_state(sd); | 2435 | struct adv7604_state *state = to_state(sd); |
2436 | const struct adv7604_chip_info *info = state->info; | ||
2099 | struct adv7604_platform_data *pdata = &state->pdata; | 2437 | struct adv7604_platform_data *pdata = &state->pdata; |
2100 | 2438 | ||
2101 | hdmi_write(sd, 0x48, | 2439 | hdmi_write(sd, 0x48, |
@@ -2104,28 +2442,33 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
2104 | 2442 | ||
2105 | disable_input(sd); | 2443 | disable_input(sd); |
2106 | 2444 | ||
2445 | if (pdata->default_input >= 0 && | ||
2446 | pdata->default_input < state->source_pad) { | ||
2447 | state->selected_input = pdata->default_input; | ||
2448 | select_input(sd); | ||
2449 | enable_input(sd); | ||
2450 | } | ||
2451 | |||
2107 | /* power */ | 2452 | /* power */ |
2108 | io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */ | 2453 | io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */ |
2109 | io_write(sd, 0x0b, 0x44); /* Power down ESDP block */ | 2454 | io_write(sd, 0x0b, 0x44); /* Power down ESDP block */ |
2110 | cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ | 2455 | cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ |
2111 | 2456 | ||
2112 | /* video format */ | 2457 | /* video format */ |
2113 | io_write_and_or(sd, 0x02, 0xf0, | 2458 | io_write_clr_set(sd, 0x02, 0x0f, |
2114 | pdata->alt_gamma << 3 | | 2459 | pdata->alt_gamma << 3 | |
2115 | pdata->op_656_range << 2 | | 2460 | pdata->op_656_range << 2 | |
2116 | pdata->rgb_out << 1 | | ||
2117 | pdata->alt_data_sat << 0); | 2461 | pdata->alt_data_sat << 0); |
2118 | io_write(sd, 0x03, pdata->op_format_sel); | 2462 | io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | |
2119 | io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5); | 2463 | pdata->insert_av_codes << 2 | |
2120 | io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | | 2464 | pdata->replicate_av_codes << 1); |
2121 | pdata->insert_av_codes << 2 | | 2465 | adv7604_setup_format(state); |
2122 | pdata->replicate_av_codes << 1 | | ||
2123 | pdata->invert_cbcr << 0); | ||
2124 | 2466 | ||
2125 | cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ | 2467 | cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ |
2126 | 2468 | ||
2127 | /* VS, HS polarities */ | 2469 | /* VS, HS polarities */ |
2128 | io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | pdata->inv_hs_pol << 1); | 2470 | io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | |
2471 | pdata->inv_hs_pol << 1 | pdata->inv_llc_pol); | ||
2129 | 2472 | ||
2130 | /* Adjust drive strength */ | 2473 | /* Adjust drive strength */ |
2131 | io_write(sd, 0x14, 0x40 | pdata->dr_str_data << 4 | | 2474 | io_write(sd, 0x14, 0x40 | pdata->dr_str_data << 4 | |
@@ -2142,52 +2485,46 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
2142 | for digital formats */ | 2485 | for digital formats */ |
2143 | 2486 | ||
2144 | /* HDMI audio */ | 2487 | /* HDMI audio */ |
2145 | hdmi_write_and_or(sd, 0x15, 0xfc, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */ | 2488 | hdmi_write_clr_set(sd, 0x15, 0x03, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */ |
2146 | hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ | 2489 | hdmi_write_clr_set(sd, 0x1a, 0x0e, 0x08); /* Wait 1 s before unmute */ |
2147 | hdmi_write_and_or(sd, 0x68, 0xf9, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */ | 2490 | hdmi_write_clr_set(sd, 0x68, 0x06, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */ |
2148 | 2491 | ||
2149 | /* TODO from platform data */ | 2492 | /* TODO from platform data */ |
2150 | afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ | 2493 | afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ |
2151 | 2494 | ||
2152 | afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ | 2495 | if (adv7604_has_afe(state)) { |
2153 | io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); | 2496 | afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ |
2497 | io_write_clr_set(sd, 0x30, 1 << 4, pdata->output_bus_lsb_to_msb << 4); | ||
2498 | } | ||
2154 | 2499 | ||
2155 | /* interrupts */ | 2500 | /* interrupts */ |
2156 | io_write(sd, 0x40, 0xc2); /* Configure INT1 */ | 2501 | io_write(sd, 0x40, 0xc0 | pdata->int1_config); /* Configure INT1 */ |
2157 | io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ | ||
2158 | io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ | 2502 | io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ |
2159 | io_write(sd, 0x6e, 0xc1); /* Enable V_LOCKED, DE_REGEN_LCK, HDMI_MODE interrupts */ | 2503 | io_write(sd, 0x6e, info->fmt_change_digital_mask); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ |
2160 | io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */ | 2504 | io_write(sd, 0x73, info->cable_det_mask); /* Enable cable detection (+5v) interrupts */ |
2505 | info->setup_irqs(sd); | ||
2161 | 2506 | ||
2162 | return v4l2_ctrl_handler_setup(sd->ctrl_handler); | 2507 | return v4l2_ctrl_handler_setup(sd->ctrl_handler); |
2163 | } | 2508 | } |
2164 | 2509 | ||
2510 | static void adv7604_setup_irqs(struct v4l2_subdev *sd) | ||
2511 | { | ||
2512 | io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ | ||
2513 | } | ||
2514 | |||
2515 | static void adv7611_setup_irqs(struct v4l2_subdev *sd) | ||
2516 | { | ||
2517 | io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ | ||
2518 | } | ||
2519 | |||
2165 | static void adv7604_unregister_clients(struct adv7604_state *state) | 2520 | static void adv7604_unregister_clients(struct adv7604_state *state) |
2166 | { | 2521 | { |
2167 | if (state->i2c_avlink) | 2522 | unsigned int i; |
2168 | i2c_unregister_device(state->i2c_avlink); | 2523 | |
2169 | if (state->i2c_cec) | 2524 | for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) { |
2170 | i2c_unregister_device(state->i2c_cec); | 2525 | if (state->i2c_clients[i]) |
2171 | if (state->i2c_infoframe) | 2526 | i2c_unregister_device(state->i2c_clients[i]); |
2172 | i2c_unregister_device(state->i2c_infoframe); | 2527 | } |
2173 | if (state->i2c_esdp) | ||
2174 | i2c_unregister_device(state->i2c_esdp); | ||
2175 | if (state->i2c_dpp) | ||
2176 | i2c_unregister_device(state->i2c_dpp); | ||
2177 | if (state->i2c_afe) | ||
2178 | i2c_unregister_device(state->i2c_afe); | ||
2179 | if (state->i2c_repeater) | ||
2180 | i2c_unregister_device(state->i2c_repeater); | ||
2181 | if (state->i2c_edid) | ||
2182 | i2c_unregister_device(state->i2c_edid); | ||
2183 | if (state->i2c_hdmi) | ||
2184 | i2c_unregister_device(state->i2c_hdmi); | ||
2185 | if (state->i2c_test) | ||
2186 | i2c_unregister_device(state->i2c_test); | ||
2187 | if (state->i2c_cp) | ||
2188 | i2c_unregister_device(state->i2c_cp); | ||
2189 | if (state->i2c_vdp) | ||
2190 | i2c_unregister_device(state->i2c_vdp); | ||
2191 | } | 2528 | } |
2192 | 2529 | ||
2193 | static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, | 2530 | static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, |
@@ -2200,15 +2537,219 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, | |||
2200 | return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); | 2537 | return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); |
2201 | } | 2538 | } |
2202 | 2539 | ||
2540 | static const struct adv7604_reg_seq adv7604_recommended_settings_afe[] = { | ||
2541 | /* reset ADI recommended settings for HDMI: */ | ||
2542 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | ||
2543 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ | ||
2544 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ | ||
2545 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */ | ||
2546 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */ | ||
2547 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ | ||
2548 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */ | ||
2549 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */ | ||
2550 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ | ||
2551 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ | ||
2552 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */ | ||
2553 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */ | ||
2554 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */ | ||
2555 | |||
2556 | /* set ADI recommended settings for digitizer */ | ||
2557 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ | ||
2558 | { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */ | ||
2559 | { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */ | ||
2560 | { ADV7604_REG(ADV7604_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */ | ||
2561 | { ADV7604_REG(ADV7604_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */ | ||
2562 | { ADV7604_REG(ADV7604_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */ | ||
2563 | |||
2564 | { ADV7604_REG_SEQ_TERM, 0 }, | ||
2565 | }; | ||
2566 | |||
2567 | static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = { | ||
2568 | /* set ADI recommended settings for HDMI: */ | ||
2569 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | ||
2570 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */ | ||
2571 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */ | ||
2572 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */ | ||
2573 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ | ||
2574 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */ | ||
2575 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */ | ||
2576 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ | ||
2577 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ | ||
2578 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */ | ||
2579 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */ | ||
2580 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */ | ||
2581 | |||
2582 | /* reset ADI recommended settings for digitizer */ | ||
2583 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ | ||
2584 | { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */ | ||
2585 | { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */ | ||
2586 | |||
2587 | { ADV7604_REG_SEQ_TERM, 0 }, | ||
2588 | }; | ||
2589 | |||
2590 | static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = { | ||
2591 | { ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 }, | ||
2592 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x0c }, | ||
2593 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 }, | ||
2594 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda }, | ||
2595 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 }, | ||
2596 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x03), 0x98 }, | ||
2597 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4c), 0x44 }, | ||
2598 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x04 }, | ||
2599 | { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x1e }, | ||
2600 | |||
2601 | { ADV7604_REG_SEQ_TERM, 0 }, | ||
2602 | }; | ||
2603 | |||
2604 | static const struct adv7604_chip_info adv7604_chip_info[] = { | ||
2605 | [ADV7604] = { | ||
2606 | .type = ADV7604, | ||
2607 | .has_afe = true, | ||
2608 | .max_port = ADV7604_PAD_VGA_COMP, | ||
2609 | .num_dv_ports = 4, | ||
2610 | .edid_enable_reg = 0x77, | ||
2611 | .edid_status_reg = 0x7d, | ||
2612 | .lcf_reg = 0xb3, | ||
2613 | .tdms_lock_mask = 0xe0, | ||
2614 | .cable_det_mask = 0x1e, | ||
2615 | .fmt_change_digital_mask = 0xc1, | ||
2616 | .formats = adv7604_formats, | ||
2617 | .nformats = ARRAY_SIZE(adv7604_formats), | ||
2618 | .set_termination = adv7604_set_termination, | ||
2619 | .setup_irqs = adv7604_setup_irqs, | ||
2620 | .read_hdmi_pixelclock = adv7604_read_hdmi_pixelclock, | ||
2621 | .read_cable_det = adv7604_read_cable_det, | ||
2622 | .recommended_settings = { | ||
2623 | [0] = adv7604_recommended_settings_afe, | ||
2624 | [1] = adv7604_recommended_settings_hdmi, | ||
2625 | }, | ||
2626 | .num_recommended_settings = { | ||
2627 | [0] = ARRAY_SIZE(adv7604_recommended_settings_afe), | ||
2628 | [1] = ARRAY_SIZE(adv7604_recommended_settings_hdmi), | ||
2629 | }, | ||
2630 | .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) | | ||
2631 | BIT(ADV7604_PAGE_CEC) | BIT(ADV7604_PAGE_INFOFRAME) | | ||
2632 | BIT(ADV7604_PAGE_ESDP) | BIT(ADV7604_PAGE_DPP) | | ||
2633 | BIT(ADV7604_PAGE_AFE) | BIT(ADV7604_PAGE_REP) | | ||
2634 | BIT(ADV7604_PAGE_EDID) | BIT(ADV7604_PAGE_HDMI) | | ||
2635 | BIT(ADV7604_PAGE_TEST) | BIT(ADV7604_PAGE_CP) | | ||
2636 | BIT(ADV7604_PAGE_VDP), | ||
2637 | }, | ||
2638 | [ADV7611] = { | ||
2639 | .type = ADV7611, | ||
2640 | .has_afe = false, | ||
2641 | .max_port = ADV7604_PAD_HDMI_PORT_A, | ||
2642 | .num_dv_ports = 1, | ||
2643 | .edid_enable_reg = 0x74, | ||
2644 | .edid_status_reg = 0x76, | ||
2645 | .lcf_reg = 0xa3, | ||
2646 | .tdms_lock_mask = 0x43, | ||
2647 | .cable_det_mask = 0x01, | ||
2648 | .fmt_change_digital_mask = 0x03, | ||
2649 | .formats = adv7611_formats, | ||
2650 | .nformats = ARRAY_SIZE(adv7611_formats), | ||
2651 | .set_termination = adv7611_set_termination, | ||
2652 | .setup_irqs = adv7611_setup_irqs, | ||
2653 | .read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock, | ||
2654 | .read_cable_det = adv7611_read_cable_det, | ||
2655 | .recommended_settings = { | ||
2656 | [1] = adv7611_recommended_settings_hdmi, | ||
2657 | }, | ||
2658 | .num_recommended_settings = { | ||
2659 | [1] = ARRAY_SIZE(adv7611_recommended_settings_hdmi), | ||
2660 | }, | ||
2661 | .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_CEC) | | ||
2662 | BIT(ADV7604_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_AFE) | | ||
2663 | BIT(ADV7604_PAGE_REP) | BIT(ADV7604_PAGE_EDID) | | ||
2664 | BIT(ADV7604_PAGE_HDMI) | BIT(ADV7604_PAGE_CP), | ||
2665 | }, | ||
2666 | }; | ||
2667 | |||
2668 | static struct i2c_device_id adv7604_i2c_id[] = { | ||
2669 | { "adv7604", (kernel_ulong_t)&adv7604_chip_info[ADV7604] }, | ||
2670 | { "adv7611", (kernel_ulong_t)&adv7604_chip_info[ADV7611] }, | ||
2671 | { } | ||
2672 | }; | ||
2673 | MODULE_DEVICE_TABLE(i2c, adv7604_i2c_id); | ||
2674 | |||
2675 | static struct of_device_id adv7604_of_id[] __maybe_unused = { | ||
2676 | { .compatible = "adi,adv7611", .data = &adv7604_chip_info[ADV7611] }, | ||
2677 | { } | ||
2678 | }; | ||
2679 | MODULE_DEVICE_TABLE(of, adv7604_of_id); | ||
2680 | |||
2681 | static int adv7604_parse_dt(struct adv7604_state *state) | ||
2682 | { | ||
2683 | struct v4l2_of_endpoint bus_cfg; | ||
2684 | struct device_node *endpoint; | ||
2685 | struct device_node *np; | ||
2686 | unsigned int flags; | ||
2687 | |||
2688 | np = state->i2c_clients[ADV7604_PAGE_IO]->dev.of_node; | ||
2689 | |||
2690 | /* Parse the endpoint. */ | ||
2691 | endpoint = of_graph_get_next_endpoint(np, NULL); | ||
2692 | if (!endpoint) | ||
2693 | return -EINVAL; | ||
2694 | |||
2695 | v4l2_of_parse_endpoint(endpoint, &bus_cfg); | ||
2696 | of_node_put(endpoint); | ||
2697 | |||
2698 | flags = bus_cfg.bus.parallel.flags; | ||
2699 | |||
2700 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) | ||
2701 | state->pdata.inv_hs_pol = 1; | ||
2702 | |||
2703 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | ||
2704 | state->pdata.inv_vs_pol = 1; | ||
2705 | |||
2706 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
2707 | state->pdata.inv_llc_pol = 1; | ||
2708 | |||
2709 | if (bus_cfg.bus_type == V4L2_MBUS_BT656) { | ||
2710 | state->pdata.insert_av_codes = 1; | ||
2711 | state->pdata.op_656_range = 1; | ||
2712 | } | ||
2713 | |||
2714 | /* Disable the interrupt for now as no DT-based board uses it. */ | ||
2715 | state->pdata.int1_config = ADV7604_INT1_CONFIG_DISABLED; | ||
2716 | |||
2717 | /* Use the default I2C addresses. */ | ||
2718 | state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42; | ||
2719 | state->pdata.i2c_addresses[ADV7604_PAGE_CEC] = 0x40; | ||
2720 | state->pdata.i2c_addresses[ADV7604_PAGE_INFOFRAME] = 0x3e; | ||
2721 | state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38; | ||
2722 | state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c; | ||
2723 | state->pdata.i2c_addresses[ADV7604_PAGE_AFE] = 0x26; | ||
2724 | state->pdata.i2c_addresses[ADV7604_PAGE_REP] = 0x32; | ||
2725 | state->pdata.i2c_addresses[ADV7604_PAGE_EDID] = 0x36; | ||
2726 | state->pdata.i2c_addresses[ADV7604_PAGE_HDMI] = 0x34; | ||
2727 | state->pdata.i2c_addresses[ADV7604_PAGE_TEST] = 0x30; | ||
2728 | state->pdata.i2c_addresses[ADV7604_PAGE_CP] = 0x22; | ||
2729 | state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24; | ||
2730 | |||
2731 | /* Hardcode the remaining platform data fields. */ | ||
2732 | state->pdata.disable_pwrdnb = 0; | ||
2733 | state->pdata.disable_cable_det_rst = 0; | ||
2734 | state->pdata.default_input = -1; | ||
2735 | state->pdata.blank_data = 1; | ||
2736 | state->pdata.alt_data_sat = 1; | ||
2737 | state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; | ||
2738 | state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; | ||
2739 | |||
2740 | return 0; | ||
2741 | } | ||
2742 | |||
2203 | static int adv7604_probe(struct i2c_client *client, | 2743 | static int adv7604_probe(struct i2c_client *client, |
2204 | const struct i2c_device_id *id) | 2744 | const struct i2c_device_id *id) |
2205 | { | 2745 | { |
2206 | static const struct v4l2_dv_timings cea640x480 = | 2746 | static const struct v4l2_dv_timings cea640x480 = |
2207 | V4L2_DV_BT_CEA_640X480P59_94; | 2747 | V4L2_DV_BT_CEA_640X480P59_94; |
2208 | struct adv7604_state *state; | 2748 | struct adv7604_state *state; |
2209 | struct adv7604_platform_data *pdata = client->dev.platform_data; | ||
2210 | struct v4l2_ctrl_handler *hdl; | 2749 | struct v4l2_ctrl_handler *hdl; |
2211 | struct v4l2_subdev *sd; | 2750 | struct v4l2_subdev *sd; |
2751 | unsigned int i; | ||
2752 | u16 val; | ||
2212 | int err; | 2753 | int err; |
2213 | 2754 | ||
2214 | /* Check if the adapter supports the needed features */ | 2755 | /* Check if the adapter supports the needed features */ |
@@ -2223,32 +2764,80 @@ static int adv7604_probe(struct i2c_client *client, | |||
2223 | return -ENOMEM; | 2764 | return -ENOMEM; |
2224 | } | 2765 | } |
2225 | 2766 | ||
2767 | state->i2c_clients[ADV7604_PAGE_IO] = client; | ||
2768 | |||
2226 | /* initialize variables */ | 2769 | /* initialize variables */ |
2227 | state->restart_stdi_once = true; | 2770 | state->restart_stdi_once = true; |
2228 | state->selected_input = ~0; | 2771 | state->selected_input = ~0; |
2229 | 2772 | ||
2230 | /* platform data */ | 2773 | if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) { |
2231 | if (!pdata) { | 2774 | const struct of_device_id *oid; |
2775 | |||
2776 | oid = of_match_node(adv7604_of_id, client->dev.of_node); | ||
2777 | state->info = oid->data; | ||
2778 | |||
2779 | err = adv7604_parse_dt(state); | ||
2780 | if (err < 0) { | ||
2781 | v4l_err(client, "DT parsing error\n"); | ||
2782 | return err; | ||
2783 | } | ||
2784 | } else if (client->dev.platform_data) { | ||
2785 | struct adv7604_platform_data *pdata = client->dev.platform_data; | ||
2786 | |||
2787 | state->info = (const struct adv7604_chip_info *)id->driver_data; | ||
2788 | state->pdata = *pdata; | ||
2789 | } else { | ||
2232 | v4l_err(client, "No platform data!\n"); | 2790 | v4l_err(client, "No platform data!\n"); |
2233 | return -ENODEV; | 2791 | return -ENODEV; |
2234 | } | 2792 | } |
2235 | state->pdata = *pdata; | 2793 | |
2794 | /* Request GPIOs. */ | ||
2795 | for (i = 0; i < state->info->num_dv_ports; ++i) { | ||
2796 | state->hpd_gpio[i] = | ||
2797 | devm_gpiod_get_index(&client->dev, "hpd", i); | ||
2798 | if (IS_ERR(state->hpd_gpio[i])) | ||
2799 | continue; | ||
2800 | |||
2801 | gpiod_direction_output(state->hpd_gpio[i], 0); | ||
2802 | |||
2803 | v4l_info(client, "Handling HPD %u GPIO\n", i); | ||
2804 | } | ||
2805 | |||
2236 | state->timings = cea640x480; | 2806 | state->timings = cea640x480; |
2807 | state->format = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8); | ||
2237 | 2808 | ||
2238 | sd = &state->sd; | 2809 | sd = &state->sd; |
2239 | v4l2_i2c_subdev_init(sd, client, &adv7604_ops); | 2810 | v4l2_i2c_subdev_init(sd, client, &adv7604_ops); |
2811 | snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", | ||
2812 | id->name, i2c_adapter_id(client->adapter), | ||
2813 | client->addr); | ||
2240 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 2814 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
2241 | 2815 | ||
2242 | /* i2c access to adv7604? */ | 2816 | /* |
2243 | if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) { | 2817 | * Verify that the chip is present. On ADV7604 the RD_INFO register only |
2244 | v4l2_info(sd, "not an adv7604 on address 0x%x\n", | 2818 | * identifies the revision, while on ADV7611 it identifies the model as |
2245 | client->addr << 1); | 2819 | * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. |
2246 | return -ENODEV; | 2820 | */ |
2821 | if (state->info->type == ADV7604) { | ||
2822 | val = adv_smbus_read_byte_data_check(client, 0xfb, false); | ||
2823 | if (val != 0x68) { | ||
2824 | v4l2_info(sd, "not an adv7604 on address 0x%x\n", | ||
2825 | client->addr << 1); | ||
2826 | return -ENODEV; | ||
2827 | } | ||
2828 | } else { | ||
2829 | val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8) | ||
2830 | | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0); | ||
2831 | if (val != 0x2051) { | ||
2832 | v4l2_info(sd, "not an adv7611 on address 0x%x\n", | ||
2833 | client->addr << 1); | ||
2834 | return -ENODEV; | ||
2835 | } | ||
2247 | } | 2836 | } |
2248 | 2837 | ||
2249 | /* control handlers */ | 2838 | /* control handlers */ |
2250 | hdl = &state->hdl; | 2839 | hdl = &state->hdl; |
2251 | v4l2_ctrl_handler_init(hdl, 9); | 2840 | v4l2_ctrl_handler_init(hdl, adv7604_has_afe(state) ? 9 : 8); |
2252 | 2841 | ||
2253 | v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, | 2842 | v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, |
2254 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); | 2843 | V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); |
@@ -2261,15 +2850,17 @@ static int adv7604_probe(struct i2c_client *client, | |||
2261 | 2850 | ||
2262 | /* private controls */ | 2851 | /* private controls */ |
2263 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, | 2852 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, |
2264 | V4L2_CID_DV_RX_POWER_PRESENT, 0, 0x0f, 0, 0); | 2853 | V4L2_CID_DV_RX_POWER_PRESENT, 0, |
2854 | (1 << state->info->num_dv_ports) - 1, 0, 0); | ||
2265 | state->rgb_quantization_range_ctrl = | 2855 | state->rgb_quantization_range_ctrl = |
2266 | v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, | 2856 | v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, |
2267 | V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, | 2857 | V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, |
2268 | 0, V4L2_DV_RGB_RANGE_AUTO); | 2858 | 0, V4L2_DV_RGB_RANGE_AUTO); |
2269 | 2859 | ||
2270 | /* custom controls */ | 2860 | /* custom controls */ |
2271 | state->analog_sampling_phase_ctrl = | 2861 | if (adv7604_has_afe(state)) |
2272 | v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL); | 2862 | state->analog_sampling_phase_ctrl = |
2863 | v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL); | ||
2273 | state->free_run_color_manual_ctrl = | 2864 | state->free_run_color_manual_ctrl = |
2274 | v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL); | 2865 | v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL); |
2275 | state->free_run_color_ctrl = | 2866 | state->free_run_color_ctrl = |
@@ -2282,7 +2873,8 @@ static int adv7604_probe(struct i2c_client *client, | |||
2282 | } | 2873 | } |
2283 | state->detect_tx_5v_ctrl->is_private = true; | 2874 | state->detect_tx_5v_ctrl->is_private = true; |
2284 | state->rgb_quantization_range_ctrl->is_private = true; | 2875 | state->rgb_quantization_range_ctrl->is_private = true; |
2285 | state->analog_sampling_phase_ctrl->is_private = true; | 2876 | if (adv7604_has_afe(state)) |
2877 | state->analog_sampling_phase_ctrl->is_private = true; | ||
2286 | state->free_run_color_manual_ctrl->is_private = true; | 2878 | state->free_run_color_manual_ctrl->is_private = true; |
2287 | state->free_run_color_ctrl->is_private = true; | 2879 | state->free_run_color_ctrl->is_private = true; |
2288 | 2880 | ||
@@ -2291,25 +2883,18 @@ static int adv7604_probe(struct i2c_client *client, | |||
2291 | goto err_hdl; | 2883 | goto err_hdl; |
2292 | } | 2884 | } |
2293 | 2885 | ||
2294 | state->i2c_avlink = adv7604_dummy_client(sd, pdata->i2c_avlink, 0xf3); | 2886 | for (i = 1; i < ADV7604_PAGE_MAX; ++i) { |
2295 | state->i2c_cec = adv7604_dummy_client(sd, pdata->i2c_cec, 0xf4); | 2887 | if (!(BIT(i) & state->info->page_mask)) |
2296 | state->i2c_infoframe = adv7604_dummy_client(sd, pdata->i2c_infoframe, 0xf5); | 2888 | continue; |
2297 | state->i2c_esdp = adv7604_dummy_client(sd, pdata->i2c_esdp, 0xf6); | 2889 | |
2298 | state->i2c_dpp = adv7604_dummy_client(sd, pdata->i2c_dpp, 0xf7); | 2890 | state->i2c_clients[i] = |
2299 | state->i2c_afe = adv7604_dummy_client(sd, pdata->i2c_afe, 0xf8); | 2891 | adv7604_dummy_client(sd, state->pdata.i2c_addresses[i], |
2300 | state->i2c_repeater = adv7604_dummy_client(sd, pdata->i2c_repeater, 0xf9); | 2892 | 0xf2 + i); |
2301 | state->i2c_edid = adv7604_dummy_client(sd, pdata->i2c_edid, 0xfa); | 2893 | if (state->i2c_clients[i] == NULL) { |
2302 | state->i2c_hdmi = adv7604_dummy_client(sd, pdata->i2c_hdmi, 0xfb); | 2894 | err = -ENOMEM; |
2303 | state->i2c_test = adv7604_dummy_client(sd, pdata->i2c_test, 0xfc); | 2895 | v4l2_err(sd, "failed to create i2c client %u\n", i); |
2304 | state->i2c_cp = adv7604_dummy_client(sd, pdata->i2c_cp, 0xfd); | 2896 | goto err_i2c; |
2305 | state->i2c_vdp = adv7604_dummy_client(sd, pdata->i2c_vdp, 0xfe); | 2897 | } |
2306 | if (!state->i2c_avlink || !state->i2c_cec || !state->i2c_infoframe || | ||
2307 | !state->i2c_esdp || !state->i2c_dpp || !state->i2c_afe || | ||
2308 | !state->i2c_repeater || !state->i2c_edid || !state->i2c_hdmi || | ||
2309 | !state->i2c_test || !state->i2c_cp || !state->i2c_vdp) { | ||
2310 | err = -ENOMEM; | ||
2311 | v4l2_err(sd, "failed to create all i2c clients\n"); | ||
2312 | goto err_i2c; | ||
2313 | } | 2898 | } |
2314 | 2899 | ||
2315 | /* work queues */ | 2900 | /* work queues */ |
@@ -2323,8 +2908,14 @@ static int adv7604_probe(struct i2c_client *client, | |||
2323 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, | 2908 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, |
2324 | adv7604_delayed_work_enable_hotplug); | 2909 | adv7604_delayed_work_enable_hotplug); |
2325 | 2910 | ||
2326 | state->pad.flags = MEDIA_PAD_FL_SOURCE; | 2911 | state->source_pad = state->info->num_dv_ports |
2327 | err = media_entity_init(&sd->entity, 1, &state->pad, 0); | 2912 | + (state->info->has_afe ? 2 : 0); |
2913 | for (i = 0; i < state->source_pad; ++i) | ||
2914 | state->pads[i].flags = MEDIA_PAD_FL_SINK; | ||
2915 | state->pads[state->source_pad].flags = MEDIA_PAD_FL_SOURCE; | ||
2916 | |||
2917 | err = media_entity_init(&sd->entity, state->source_pad + 1, | ||
2918 | state->pads, 0); | ||
2328 | if (err) | 2919 | if (err) |
2329 | goto err_work_queues; | 2920 | goto err_work_queues; |
2330 | 2921 | ||
@@ -2333,6 +2924,11 @@ static int adv7604_probe(struct i2c_client *client, | |||
2333 | goto err_entity; | 2924 | goto err_entity; |
2334 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, | 2925 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
2335 | client->addr << 1, client->adapter->name); | 2926 | client->addr << 1, client->adapter->name); |
2927 | |||
2928 | err = v4l2_async_register_subdev(sd); | ||
2929 | if (err) | ||
2930 | goto err_entity; | ||
2931 | |||
2336 | return 0; | 2932 | return 0; |
2337 | 2933 | ||
2338 | err_entity: | 2934 | err_entity: |
@@ -2356,6 +2952,7 @@ static int adv7604_remove(struct i2c_client *client) | |||
2356 | 2952 | ||
2357 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 2953 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
2358 | destroy_workqueue(state->work_queues); | 2954 | destroy_workqueue(state->work_queues); |
2955 | v4l2_async_unregister_subdev(sd); | ||
2359 | v4l2_device_unregister_subdev(sd); | 2956 | v4l2_device_unregister_subdev(sd); |
2360 | media_entity_cleanup(&sd->entity); | 2957 | media_entity_cleanup(&sd->entity); |
2361 | adv7604_unregister_clients(to_state(sd)); | 2958 | adv7604_unregister_clients(to_state(sd)); |
@@ -2365,20 +2962,15 @@ static int adv7604_remove(struct i2c_client *client) | |||
2365 | 2962 | ||
2366 | /* ----------------------------------------------------------------------- */ | 2963 | /* ----------------------------------------------------------------------- */ |
2367 | 2964 | ||
2368 | static struct i2c_device_id adv7604_id[] = { | ||
2369 | { "adv7604", 0 }, | ||
2370 | { } | ||
2371 | }; | ||
2372 | MODULE_DEVICE_TABLE(i2c, adv7604_id); | ||
2373 | |||
2374 | static struct i2c_driver adv7604_driver = { | 2965 | static struct i2c_driver adv7604_driver = { |
2375 | .driver = { | 2966 | .driver = { |
2376 | .owner = THIS_MODULE, | 2967 | .owner = THIS_MODULE, |
2377 | .name = "adv7604", | 2968 | .name = "adv7604", |
2969 | .of_match_table = of_match_ptr(adv7604_of_id), | ||
2378 | }, | 2970 | }, |
2379 | .probe = adv7604_probe, | 2971 | .probe = adv7604_probe, |
2380 | .remove = adv7604_remove, | 2972 | .remove = adv7604_remove, |
2381 | .id_table = adv7604_id, | 2973 | .id_table = adv7604_i2c_id, |
2382 | }; | 2974 | }; |
2383 | 2975 | ||
2384 | module_i2c_driver(adv7604_driver); | 2976 | module_i2c_driver(adv7604_driver); |
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 151cecd0ea25..6a93f928dfde 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o | 1 | vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o |
2 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o | 2 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o |
3 | vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o | 3 | vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o |
4 | vsp1-y += vsp1_sru.o vsp1_uds.o | 4 | vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o |
5 | 5 | ||
6 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o | 6 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o |
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 0313210c6e9e..6ca2cf20d545 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h | |||
@@ -28,6 +28,7 @@ struct clk; | |||
28 | struct device; | 28 | struct device; |
29 | 29 | ||
30 | struct vsp1_platform_data; | 30 | struct vsp1_platform_data; |
31 | struct vsp1_bru; | ||
31 | struct vsp1_hsit; | 32 | struct vsp1_hsit; |
32 | struct vsp1_lif; | 33 | struct vsp1_lif; |
33 | struct vsp1_lut; | 34 | struct vsp1_lut; |
@@ -45,11 +46,11 @@ struct vsp1_device { | |||
45 | 46 | ||
46 | void __iomem *mmio; | 47 | void __iomem *mmio; |
47 | struct clk *clock; | 48 | struct clk *clock; |
48 | struct clk *rt_clock; | ||
49 | 49 | ||
50 | struct mutex lock; | 50 | struct mutex lock; |
51 | int ref_count; | 51 | int ref_count; |
52 | 52 | ||
53 | struct vsp1_bru *bru; | ||
53 | struct vsp1_hsit *hsi; | 54 | struct vsp1_hsit *hsi; |
54 | struct vsp1_hsit *hst; | 55 | struct vsp1_hsit *hst; |
55 | struct vsp1_lif *lif; | 56 | struct vsp1_lif *lif; |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c new file mode 100644 index 000000000000..f80695480060 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_bru.c | |||
@@ -0,0 +1,395 @@ | |||
1 | /* | ||
2 | * vsp1_bru.c -- R-Car VSP1 Blend ROP Unit | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/gfp.h> | ||
16 | |||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1.h" | ||
20 | #include "vsp1_bru.h" | ||
21 | |||
22 | #define BRU_MIN_SIZE 4U | ||
23 | #define BRU_MAX_SIZE 8190U | ||
24 | |||
25 | /* ----------------------------------------------------------------------------- | ||
26 | * Device Access | ||
27 | */ | ||
28 | |||
29 | static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg) | ||
30 | { | ||
31 | return vsp1_read(bru->entity.vsp1, reg); | ||
32 | } | ||
33 | |||
34 | static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data) | ||
35 | { | ||
36 | vsp1_write(bru->entity.vsp1, reg, data); | ||
37 | } | ||
38 | |||
39 | /* ----------------------------------------------------------------------------- | ||
40 | * V4L2 Subdevice Core Operations | ||
41 | */ | ||
42 | |||
43 | static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input) | ||
44 | { | ||
45 | return media_entity_remote_pad(&bru->entity.pads[input]) != NULL; | ||
46 | } | ||
47 | |||
48 | static int bru_s_stream(struct v4l2_subdev *subdev, int enable) | ||
49 | { | ||
50 | struct vsp1_bru *bru = to_bru(subdev); | ||
51 | struct v4l2_mbus_framefmt *format; | ||
52 | unsigned int i; | ||
53 | |||
54 | if (!enable) | ||
55 | return 0; | ||
56 | |||
57 | format = &bru->entity.formats[BRU_PAD_SOURCE]; | ||
58 | |||
59 | /* The hardware is extremely flexible but we have no userspace API to | ||
60 | * expose all the parameters, nor is it clear whether we would have use | ||
61 | * cases for all the supported modes. Let's just harcode the parameters | ||
62 | * to sane default values for now. | ||
63 | */ | ||
64 | |||
65 | /* Disable both color data normalization and dithering. */ | ||
66 | vsp1_bru_write(bru, VI6_BRU_INCTRL, 0); | ||
67 | |||
68 | /* Set the background position to cover the whole output image and | ||
69 | * set its color to opaque black. | ||
70 | */ | ||
71 | vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE, | ||
72 | (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | | ||
73 | (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); | ||
74 | vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0); | ||
75 | vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, | ||
76 | 0xff << VI6_BRU_VIRRPF_COL_A_SHIFT); | ||
77 | |||
78 | /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP | ||
79 | * unit with a NOP operation to make BRU input 1 available as the | ||
80 | * Blend/ROP unit B SRC input. | ||
81 | */ | ||
82 | vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | | ||
83 | VI6_BRU_ROP_CROP(VI6_ROP_NOP) | | ||
84 | VI6_BRU_ROP_AROP(VI6_ROP_NOP)); | ||
85 | |||
86 | for (i = 0; i < 4; ++i) { | ||
87 | u32 ctrl = 0; | ||
88 | |||
89 | /* Configure all Blend/ROP units corresponding to an enabled BRU | ||
90 | * input for alpha blending. Blend/ROP units corresponding to | ||
91 | * disabled BRU inputs are used in ROP NOP mode to ignore the | ||
92 | * SRC input. | ||
93 | */ | ||
94 | if (bru_is_input_enabled(bru, i)) | ||
95 | ctrl |= VI6_BRU_CTRL_RBC; | ||
96 | else | ||
97 | ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP) | ||
98 | | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); | ||
99 | |||
100 | /* Select the virtual RPF as the Blend/ROP unit A DST input to | ||
101 | * serve as a background color. | ||
102 | */ | ||
103 | if (i == 0) | ||
104 | ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; | ||
105 | |||
106 | /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to | ||
107 | * D in that order. The Blend/ROP unit B SRC is hardwired to the | ||
108 | * ROP unit output, the corresponding register bits must be set | ||
109 | * to 0. | ||
110 | */ | ||
111 | if (i != 1) | ||
112 | ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); | ||
113 | |||
114 | vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl); | ||
115 | |||
116 | /* Harcode the blending formula to | ||
117 | * | ||
118 | * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa | ||
119 | * DSTa = DSTa * (1 - SRCa) + SRCa | ||
120 | */ | ||
121 | vsp1_bru_write(bru, VI6_BRU_BLD(i), | ||
122 | VI6_BRU_BLD_CCMDX_255_SRC_A | | ||
123 | VI6_BRU_BLD_CCMDY_SRC_A | | ||
124 | VI6_BRU_BLD_ACMDX_255_SRC_A | | ||
125 | VI6_BRU_BLD_ACMDY_COEFY | | ||
126 | (0xff << VI6_BRU_BLD_COEFY_SHIFT)); | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | /* ----------------------------------------------------------------------------- | ||
133 | * V4L2 Subdevice Pad Operations | ||
134 | */ | ||
135 | |||
136 | /* | ||
137 | * The BRU can't perform format conversion, all sink and source formats must be | ||
138 | * identical. We pick the format on the first sink pad (pad 0) and propagate it | ||
139 | * to all other pads. | ||
140 | */ | ||
141 | |||
142 | static int bru_enum_mbus_code(struct v4l2_subdev *subdev, | ||
143 | struct v4l2_subdev_fh *fh, | ||
144 | struct v4l2_subdev_mbus_code_enum *code) | ||
145 | { | ||
146 | static const unsigned int codes[] = { | ||
147 | V4L2_MBUS_FMT_ARGB8888_1X32, | ||
148 | V4L2_MBUS_FMT_AYUV8_1X32, | ||
149 | }; | ||
150 | struct v4l2_mbus_framefmt *format; | ||
151 | |||
152 | if (code->pad == BRU_PAD_SINK(0)) { | ||
153 | if (code->index >= ARRAY_SIZE(codes)) | ||
154 | return -EINVAL; | ||
155 | |||
156 | code->code = codes[code->index]; | ||
157 | } else { | ||
158 | if (code->index) | ||
159 | return -EINVAL; | ||
160 | |||
161 | format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); | ||
162 | code->code = format->code; | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int bru_enum_frame_size(struct v4l2_subdev *subdev, | ||
169 | struct v4l2_subdev_fh *fh, | ||
170 | struct v4l2_subdev_frame_size_enum *fse) | ||
171 | { | ||
172 | if (fse->index) | ||
173 | return -EINVAL; | ||
174 | |||
175 | if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 && | ||
176 | fse->code != V4L2_MBUS_FMT_AYUV8_1X32) | ||
177 | return -EINVAL; | ||
178 | |||
179 | fse->min_width = BRU_MIN_SIZE; | ||
180 | fse->max_width = BRU_MAX_SIZE; | ||
181 | fse->min_height = BRU_MIN_SIZE; | ||
182 | fse->max_height = BRU_MAX_SIZE; | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, | ||
188 | struct v4l2_subdev_fh *fh, | ||
189 | unsigned int pad, u32 which) | ||
190 | { | ||
191 | switch (which) { | ||
192 | case V4L2_SUBDEV_FORMAT_TRY: | ||
193 | return v4l2_subdev_get_try_crop(fh, pad); | ||
194 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
195 | return &bru->compose[pad]; | ||
196 | default: | ||
197 | return NULL; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | ||
202 | struct v4l2_subdev_format *fmt) | ||
203 | { | ||
204 | struct vsp1_bru *bru = to_bru(subdev); | ||
205 | |||
206 | fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, | ||
207 | fmt->which); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, | ||
213 | unsigned int pad, struct v4l2_mbus_framefmt *fmt, | ||
214 | enum v4l2_subdev_format_whence which) | ||
215 | { | ||
216 | struct v4l2_mbus_framefmt *format; | ||
217 | |||
218 | switch (pad) { | ||
219 | case BRU_PAD_SINK(0): | ||
220 | /* Default to YUV if the requested format is not supported. */ | ||
221 | if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && | ||
222 | fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) | ||
223 | fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; | ||
224 | break; | ||
225 | |||
226 | default: | ||
227 | /* The BRU can't perform format conversion. */ | ||
228 | format = vsp1_entity_get_pad_format(&bru->entity, fh, | ||
229 | BRU_PAD_SINK(0), which); | ||
230 | fmt->code = format->code; | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE); | ||
235 | fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE); | ||
236 | fmt->field = V4L2_FIELD_NONE; | ||
237 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | ||
238 | } | ||
239 | |||
240 | static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, | ||
241 | struct v4l2_subdev_format *fmt) | ||
242 | { | ||
243 | struct vsp1_bru *bru = to_bru(subdev); | ||
244 | struct v4l2_mbus_framefmt *format; | ||
245 | |||
246 | bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); | ||
247 | |||
248 | format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, | ||
249 | fmt->which); | ||
250 | *format = fmt->format; | ||
251 | |||
252 | /* Reset the compose rectangle */ | ||
253 | if (fmt->pad != BRU_PAD_SOURCE) { | ||
254 | struct v4l2_rect *compose; | ||
255 | |||
256 | compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); | ||
257 | compose->left = 0; | ||
258 | compose->top = 0; | ||
259 | compose->width = format->width; | ||
260 | compose->height = format->height; | ||
261 | } | ||
262 | |||
263 | /* Propagate the format code to all pads */ | ||
264 | if (fmt->pad == BRU_PAD_SINK(0)) { | ||
265 | unsigned int i; | ||
266 | |||
267 | for (i = 0; i <= BRU_PAD_SOURCE; ++i) { | ||
268 | format = vsp1_entity_get_pad_format(&bru->entity, fh, | ||
269 | i, fmt->which); | ||
270 | format->code = fmt->format.code; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int bru_get_selection(struct v4l2_subdev *subdev, | ||
278 | struct v4l2_subdev_fh *fh, | ||
279 | struct v4l2_subdev_selection *sel) | ||
280 | { | ||
281 | struct vsp1_bru *bru = to_bru(subdev); | ||
282 | |||
283 | if (sel->pad == BRU_PAD_SOURCE) | ||
284 | return -EINVAL; | ||
285 | |||
286 | switch (sel->target) { | ||
287 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
288 | sel->r.left = 0; | ||
289 | sel->r.top = 0; | ||
290 | sel->r.width = BRU_MAX_SIZE; | ||
291 | sel->r.height = BRU_MAX_SIZE; | ||
292 | return 0; | ||
293 | |||
294 | case V4L2_SEL_TGT_COMPOSE: | ||
295 | sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); | ||
296 | return 0; | ||
297 | |||
298 | default: | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static int bru_set_selection(struct v4l2_subdev *subdev, | ||
304 | struct v4l2_subdev_fh *fh, | ||
305 | struct v4l2_subdev_selection *sel) | ||
306 | { | ||
307 | struct vsp1_bru *bru = to_bru(subdev); | ||
308 | struct v4l2_mbus_framefmt *format; | ||
309 | struct v4l2_rect *compose; | ||
310 | |||
311 | if (sel->pad == BRU_PAD_SOURCE) | ||
312 | return -EINVAL; | ||
313 | |||
314 | if (sel->target != V4L2_SEL_TGT_COMPOSE) | ||
315 | return -EINVAL; | ||
316 | |||
317 | /* The compose rectangle top left corner must be inside the output | ||
318 | * frame. | ||
319 | */ | ||
320 | format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, | ||
321 | sel->which); | ||
322 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); | ||
323 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); | ||
324 | |||
325 | /* Scaling isn't supported, the compose rectangle size must be identical | ||
326 | * to the sink format size. | ||
327 | */ | ||
328 | format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, | ||
329 | sel->which); | ||
330 | sel->r.width = format->width; | ||
331 | sel->r.height = format->height; | ||
332 | |||
333 | compose = bru_get_compose(bru, fh, sel->pad, sel->which); | ||
334 | *compose = sel->r; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | /* ----------------------------------------------------------------------------- | ||
340 | * V4L2 Subdevice Operations | ||
341 | */ | ||
342 | |||
343 | static struct v4l2_subdev_video_ops bru_video_ops = { | ||
344 | .s_stream = bru_s_stream, | ||
345 | }; | ||
346 | |||
347 | static struct v4l2_subdev_pad_ops bru_pad_ops = { | ||
348 | .enum_mbus_code = bru_enum_mbus_code, | ||
349 | .enum_frame_size = bru_enum_frame_size, | ||
350 | .get_fmt = bru_get_format, | ||
351 | .set_fmt = bru_set_format, | ||
352 | .get_selection = bru_get_selection, | ||
353 | .set_selection = bru_set_selection, | ||
354 | }; | ||
355 | |||
356 | static struct v4l2_subdev_ops bru_ops = { | ||
357 | .video = &bru_video_ops, | ||
358 | .pad = &bru_pad_ops, | ||
359 | }; | ||
360 | |||
361 | /* ----------------------------------------------------------------------------- | ||
362 | * Initialization and Cleanup | ||
363 | */ | ||
364 | |||
365 | struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) | ||
366 | { | ||
367 | struct v4l2_subdev *subdev; | ||
368 | struct vsp1_bru *bru; | ||
369 | int ret; | ||
370 | |||
371 | bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL); | ||
372 | if (bru == NULL) | ||
373 | return ERR_PTR(-ENOMEM); | ||
374 | |||
375 | bru->entity.type = VSP1_ENTITY_BRU; | ||
376 | |||
377 | ret = vsp1_entity_init(vsp1, &bru->entity, 5); | ||
378 | if (ret < 0) | ||
379 | return ERR_PTR(ret); | ||
380 | |||
381 | /* Initialize the V4L2 subdev. */ | ||
382 | subdev = &bru->entity.subdev; | ||
383 | v4l2_subdev_init(subdev, &bru_ops); | ||
384 | |||
385 | subdev->entity.ops = &vsp1_media_ops; | ||
386 | subdev->internal_ops = &vsp1_subdev_internal_ops; | ||
387 | snprintf(subdev->name, sizeof(subdev->name), "%s bru", | ||
388 | dev_name(vsp1->dev)); | ||
389 | v4l2_set_subdevdata(subdev, bru); | ||
390 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
391 | |||
392 | vsp1_entity_init_formats(subdev, NULL); | ||
393 | |||
394 | return bru; | ||
395 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h new file mode 100644 index 000000000000..37062704dbf6 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_bru.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * vsp1_bru.h -- R-Car VSP1 Blend ROP Unit | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | #ifndef __VSP1_BRU_H__ | ||
14 | #define __VSP1_BRU_H__ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1_entity.h" | ||
20 | |||
21 | struct vsp1_device; | ||
22 | |||
23 | #define BRU_PAD_SINK(n) (n) | ||
24 | #define BRU_PAD_SOURCE 4 | ||
25 | |||
26 | struct vsp1_bru { | ||
27 | struct vsp1_entity entity; | ||
28 | |||
29 | struct v4l2_rect compose[4]; | ||
30 | }; | ||
31 | |||
32 | static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) | ||
33 | { | ||
34 | return container_of(subdev, struct vsp1_bru, entity.subdev); | ||
35 | } | ||
36 | |||
37 | struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1); | ||
38 | |||
39 | #endif /* __VSP1_BRU_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 2f74f0e0ddf5..c69ee0657f75 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c | |||
@@ -16,10 +16,12 @@ | |||
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/of.h> | ||
19 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
20 | #include <linux/videodev2.h> | 21 | #include <linux/videodev2.h> |
21 | 22 | ||
22 | #include "vsp1.h" | 23 | #include "vsp1.h" |
24 | #include "vsp1_bru.h" | ||
23 | #include "vsp1_hsit.h" | 25 | #include "vsp1_hsit.h" |
24 | #include "vsp1_lif.h" | 26 | #include "vsp1_lif.h" |
25 | #include "vsp1_lut.h" | 27 | #include "vsp1_lut.h" |
@@ -155,6 +157,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
155 | } | 157 | } |
156 | 158 | ||
157 | /* Instantiate all the entities. */ | 159 | /* Instantiate all the entities. */ |
160 | vsp1->bru = vsp1_bru_create(vsp1); | ||
161 | if (IS_ERR(vsp1->bru)) { | ||
162 | ret = PTR_ERR(vsp1->bru); | ||
163 | goto done; | ||
164 | } | ||
165 | |||
166 | list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); | ||
167 | |||
158 | vsp1->hsi = vsp1_hsit_create(vsp1, true); | 168 | vsp1->hsi = vsp1_hsit_create(vsp1, true); |
159 | if (IS_ERR(vsp1->hsi)) { | 169 | if (IS_ERR(vsp1->hsi)) { |
160 | ret = PTR_ERR(vsp1->hsi); | 170 | ret = PTR_ERR(vsp1->hsi); |
@@ -329,33 +339,6 @@ static int vsp1_device_init(struct vsp1_device *vsp1) | |||
329 | return 0; | 339 | return 0; |
330 | } | 340 | } |
331 | 341 | ||
332 | static int vsp1_clocks_enable(struct vsp1_device *vsp1) | ||
333 | { | ||
334 | int ret; | ||
335 | |||
336 | ret = clk_prepare_enable(vsp1->clock); | ||
337 | if (ret < 0) | ||
338 | return ret; | ||
339 | |||
340 | if (IS_ERR(vsp1->rt_clock)) | ||
341 | return 0; | ||
342 | |||
343 | ret = clk_prepare_enable(vsp1->rt_clock); | ||
344 | if (ret < 0) { | ||
345 | clk_disable_unprepare(vsp1->clock); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void vsp1_clocks_disable(struct vsp1_device *vsp1) | ||
353 | { | ||
354 | if (!IS_ERR(vsp1->rt_clock)) | ||
355 | clk_disable_unprepare(vsp1->rt_clock); | ||
356 | clk_disable_unprepare(vsp1->clock); | ||
357 | } | ||
358 | |||
359 | /* | 342 | /* |
360 | * vsp1_device_get - Acquire the VSP1 device | 343 | * vsp1_device_get - Acquire the VSP1 device |
361 | * | 344 | * |
@@ -373,7 +356,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) | |||
373 | if (vsp1->ref_count > 0) | 356 | if (vsp1->ref_count > 0) |
374 | goto done; | 357 | goto done; |
375 | 358 | ||
376 | ret = vsp1_clocks_enable(vsp1); | 359 | ret = clk_prepare_enable(vsp1->clock); |
377 | if (ret < 0) { | 360 | if (ret < 0) { |
378 | __vsp1 = NULL; | 361 | __vsp1 = NULL; |
379 | goto done; | 362 | goto done; |
@@ -381,7 +364,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) | |||
381 | 364 | ||
382 | ret = vsp1_device_init(vsp1); | 365 | ret = vsp1_device_init(vsp1); |
383 | if (ret < 0) { | 366 | if (ret < 0) { |
384 | vsp1_clocks_disable(vsp1); | 367 | clk_disable_unprepare(vsp1->clock); |
385 | __vsp1 = NULL; | 368 | __vsp1 = NULL; |
386 | goto done; | 369 | goto done; |
387 | } | 370 | } |
@@ -405,7 +388,7 @@ void vsp1_device_put(struct vsp1_device *vsp1) | |||
405 | mutex_lock(&vsp1->lock); | 388 | mutex_lock(&vsp1->lock); |
406 | 389 | ||
407 | if (--vsp1->ref_count == 0) | 390 | if (--vsp1->ref_count == 0) |
408 | vsp1_clocks_disable(vsp1); | 391 | clk_disable_unprepare(vsp1->clock); |
409 | 392 | ||
410 | mutex_unlock(&vsp1->lock); | 393 | mutex_unlock(&vsp1->lock); |
411 | } | 394 | } |
@@ -424,7 +407,7 @@ static int vsp1_pm_suspend(struct device *dev) | |||
424 | if (vsp1->ref_count == 0) | 407 | if (vsp1->ref_count == 0) |
425 | return 0; | 408 | return 0; |
426 | 409 | ||
427 | vsp1_clocks_disable(vsp1); | 410 | clk_disable_unprepare(vsp1->clock); |
428 | return 0; | 411 | return 0; |
429 | } | 412 | } |
430 | 413 | ||
@@ -437,7 +420,7 @@ static int vsp1_pm_resume(struct device *dev) | |||
437 | if (vsp1->ref_count) | 420 | if (vsp1->ref_count) |
438 | return 0; | 421 | return 0; |
439 | 422 | ||
440 | return vsp1_clocks_enable(vsp1); | 423 | return clk_prepare_enable(vsp1->clock); |
441 | } | 424 | } |
442 | #endif | 425 | #endif |
443 | 426 | ||
@@ -449,34 +432,59 @@ static const struct dev_pm_ops vsp1_pm_ops = { | |||
449 | * Platform Driver | 432 | * Platform Driver |
450 | */ | 433 | */ |
451 | 434 | ||
452 | static struct vsp1_platform_data * | 435 | static int vsp1_validate_platform_data(struct platform_device *pdev, |
453 | vsp1_get_platform_data(struct platform_device *pdev) | 436 | struct vsp1_platform_data *pdata) |
454 | { | 437 | { |
455 | struct vsp1_platform_data *pdata = pdev->dev.platform_data; | ||
456 | |||
457 | if (pdata == NULL) { | 438 | if (pdata == NULL) { |
458 | dev_err(&pdev->dev, "missing platform data\n"); | 439 | dev_err(&pdev->dev, "missing platform data\n"); |
459 | return NULL; | 440 | return -EINVAL; |
460 | } | 441 | } |
461 | 442 | ||
462 | if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) { | 443 | if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) { |
463 | dev_err(&pdev->dev, "invalid number of RPF (%u)\n", | 444 | dev_err(&pdev->dev, "invalid number of RPF (%u)\n", |
464 | pdata->rpf_count); | 445 | pdata->rpf_count); |
465 | return NULL; | 446 | return -EINVAL; |
466 | } | 447 | } |
467 | 448 | ||
468 | if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) { | 449 | if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) { |
469 | dev_err(&pdev->dev, "invalid number of UDS (%u)\n", | 450 | dev_err(&pdev->dev, "invalid number of UDS (%u)\n", |
470 | pdata->uds_count); | 451 | pdata->uds_count); |
471 | return NULL; | 452 | return -EINVAL; |
472 | } | 453 | } |
473 | 454 | ||
474 | if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) { | 455 | if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) { |
475 | dev_err(&pdev->dev, "invalid number of WPF (%u)\n", | 456 | dev_err(&pdev->dev, "invalid number of WPF (%u)\n", |
476 | pdata->wpf_count); | 457 | pdata->wpf_count); |
477 | return NULL; | 458 | return -EINVAL; |
478 | } | 459 | } |
479 | 460 | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct vsp1_platform_data * | ||
465 | vsp1_get_platform_data(struct platform_device *pdev) | ||
466 | { | ||
467 | struct device_node *np = pdev->dev.of_node; | ||
468 | struct vsp1_platform_data *pdata; | ||
469 | |||
470 | if (!IS_ENABLED(CONFIG_OF) || np == NULL) | ||
471 | return pdev->dev.platform_data; | ||
472 | |||
473 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
474 | if (pdata == NULL) | ||
475 | return NULL; | ||
476 | |||
477 | if (of_property_read_bool(np, "renesas,has-lif")) | ||
478 | pdata->features |= VSP1_HAS_LIF; | ||
479 | if (of_property_read_bool(np, "renesas,has-lut")) | ||
480 | pdata->features |= VSP1_HAS_LUT; | ||
481 | if (of_property_read_bool(np, "renesas,has-sru")) | ||
482 | pdata->features |= VSP1_HAS_SRU; | ||
483 | |||
484 | of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count); | ||
485 | of_property_read_u32(np, "renesas,#uds", &pdata->uds_count); | ||
486 | of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count); | ||
487 | |||
480 | return pdata; | 488 | return pdata; |
481 | } | 489 | } |
482 | 490 | ||
@@ -499,6 +507,10 @@ static int vsp1_probe(struct platform_device *pdev) | |||
499 | if (vsp1->pdata == NULL) | 507 | if (vsp1->pdata == NULL) |
500 | return -ENODEV; | 508 | return -ENODEV; |
501 | 509 | ||
510 | ret = vsp1_validate_platform_data(pdev, vsp1->pdata); | ||
511 | if (ret < 0) | ||
512 | return ret; | ||
513 | |||
502 | /* I/O, IRQ and clock resources */ | 514 | /* I/O, IRQ and clock resources */ |
503 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 515 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
504 | vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); | 516 | vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); |
@@ -511,9 +523,6 @@ static int vsp1_probe(struct platform_device *pdev) | |||
511 | return PTR_ERR(vsp1->clock); | 523 | return PTR_ERR(vsp1->clock); |
512 | } | 524 | } |
513 | 525 | ||
514 | /* The RT clock is optional */ | ||
515 | vsp1->rt_clock = devm_clk_get(&pdev->dev, "rt"); | ||
516 | |||
517 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 526 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
518 | if (!irq) { | 527 | if (!irq) { |
519 | dev_err(&pdev->dev, "missing IRQ\n"); | 528 | dev_err(&pdev->dev, "missing IRQ\n"); |
@@ -548,6 +557,11 @@ static int vsp1_remove(struct platform_device *pdev) | |||
548 | return 0; | 557 | return 0; |
549 | } | 558 | } |
550 | 559 | ||
560 | static const struct of_device_id vsp1_of_match[] = { | ||
561 | { .compatible = "renesas,vsp1" }, | ||
562 | { }, | ||
563 | }; | ||
564 | |||
551 | static struct platform_driver vsp1_platform_driver = { | 565 | static struct platform_driver vsp1_platform_driver = { |
552 | .probe = vsp1_probe, | 566 | .probe = vsp1_probe, |
553 | .remove = vsp1_remove, | 567 | .remove = vsp1_remove, |
@@ -555,6 +569,7 @@ static struct platform_driver vsp1_platform_driver = { | |||
555 | .owner = THIS_MODULE, | 569 | .owner = THIS_MODULE, |
556 | .name = "vsp1", | 570 | .name = "vsp1", |
557 | .pm = &vsp1_pm_ops, | 571 | .pm = &vsp1_pm_ops, |
572 | .of_match_table = vsp1_of_match, | ||
558 | }, | 573 | }, |
559 | }; | 574 | }; |
560 | 575 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 3fc9e4266caf..44167834285d 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
@@ -100,8 +100,10 @@ static int vsp1_entity_link_setup(struct media_entity *entity, | |||
100 | if (source->sink) | 100 | if (source->sink) |
101 | return -EBUSY; | 101 | return -EBUSY; |
102 | source->sink = remote->entity; | 102 | source->sink = remote->entity; |
103 | source->sink_pad = remote->index; | ||
103 | } else { | 104 | } else { |
104 | source->sink = NULL; | 105 | source->sink = NULL; |
106 | source->sink_pad = 0; | ||
105 | } | 107 | } |
106 | 108 | ||
107 | return 0; | 109 | return 0; |
@@ -116,42 +118,43 @@ const struct media_entity_operations vsp1_media_ops = { | |||
116 | * Initialization | 118 | * Initialization |
117 | */ | 119 | */ |
118 | 120 | ||
121 | static const struct vsp1_route vsp1_routes[] = { | ||
122 | { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, | ||
123 | { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), | ||
124 | VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), } }, | ||
125 | { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } }, | ||
126 | { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, | ||
127 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, | ||
128 | { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, | ||
129 | { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } }, | ||
130 | { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } }, | ||
131 | { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } }, | ||
132 | { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } }, | ||
133 | { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } }, | ||
134 | { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, | ||
135 | { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, | ||
136 | { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, | ||
137 | { VSP1_ENTITY_UDS, 2, VI6_DPR_UDS_ROUTE(2), { VI6_DPR_NODE_UDS(2), } }, | ||
138 | { VSP1_ENTITY_WPF, 0, 0, { VI6_DPR_NODE_WPF(0), } }, | ||
139 | { VSP1_ENTITY_WPF, 1, 0, { VI6_DPR_NODE_WPF(1), } }, | ||
140 | { VSP1_ENTITY_WPF, 2, 0, { VI6_DPR_NODE_WPF(2), } }, | ||
141 | { VSP1_ENTITY_WPF, 3, 0, { VI6_DPR_NODE_WPF(3), } }, | ||
142 | }; | ||
143 | |||
119 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | 144 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, |
120 | unsigned int num_pads) | 145 | unsigned int num_pads) |
121 | { | 146 | { |
122 | static const struct { | ||
123 | unsigned int id; | ||
124 | unsigned int reg; | ||
125 | } routes[] = { | ||
126 | { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE }, | ||
127 | { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE }, | ||
128 | { VI6_DPR_NODE_LIF, 0 }, | ||
129 | { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE }, | ||
130 | { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, | ||
131 | { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, | ||
132 | { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, | ||
133 | { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) }, | ||
134 | { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) }, | ||
135 | { VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE }, | ||
136 | { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) }, | ||
137 | { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) }, | ||
138 | { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) }, | ||
139 | { VI6_DPR_NODE_WPF(0), 0 }, | ||
140 | { VI6_DPR_NODE_WPF(1), 0 }, | ||
141 | { VI6_DPR_NODE_WPF(2), 0 }, | ||
142 | { VI6_DPR_NODE_WPF(3), 0 }, | ||
143 | }; | ||
144 | |||
145 | unsigned int i; | 147 | unsigned int i; |
146 | 148 | ||
147 | for (i = 0; i < ARRAY_SIZE(routes); ++i) { | 149 | for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) { |
148 | if (routes[i].id == entity->id) { | 150 | if (vsp1_routes[i].type == entity->type && |
149 | entity->route = routes[i].reg; | 151 | vsp1_routes[i].index == entity->index) { |
152 | entity->route = &vsp1_routes[i]; | ||
150 | break; | 153 | break; |
151 | } | 154 | } |
152 | } | 155 | } |
153 | 156 | ||
154 | if (i == ARRAY_SIZE(routes)) | 157 | if (i == ARRAY_SIZE(vsp1_routes)) |
155 | return -EINVAL; | 158 | return -EINVAL; |
156 | 159 | ||
157 | entity->vsp1 = vsp1; | 160 | entity->vsp1 = vsp1; |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index f6fd6988aeb0..7afbd8a7ba66 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
@@ -20,6 +20,7 @@ | |||
20 | struct vsp1_device; | 20 | struct vsp1_device; |
21 | 21 | ||
22 | enum vsp1_entity_type { | 22 | enum vsp1_entity_type { |
23 | VSP1_ENTITY_BRU, | ||
23 | VSP1_ENTITY_HSI, | 24 | VSP1_ENTITY_HSI, |
24 | VSP1_ENTITY_HST, | 25 | VSP1_ENTITY_HST, |
25 | VSP1_ENTITY_LIF, | 26 | VSP1_ENTITY_LIF, |
@@ -30,13 +31,31 @@ enum vsp1_entity_type { | |||
30 | VSP1_ENTITY_WPF, | 31 | VSP1_ENTITY_WPF, |
31 | }; | 32 | }; |
32 | 33 | ||
34 | /* | ||
35 | * struct vsp1_route - Entity routing configuration | ||
36 | * @type: Entity type this routing entry is associated with | ||
37 | * @index: Entity index this routing entry is associated with | ||
38 | * @reg: Output routing configuration register | ||
39 | * @inputs: Target node value for each input | ||
40 | * | ||
41 | * Each $vsp1_route entry describes routing configuration for the entity | ||
42 | * specified by the entry's @type and @index. @reg indicates the register that | ||
43 | * holds output routing configuration for the entity, and the @inputs array | ||
44 | * store the target node value for each input of the entity. | ||
45 | */ | ||
46 | struct vsp1_route { | ||
47 | enum vsp1_entity_type type; | ||
48 | unsigned int index; | ||
49 | unsigned int reg; | ||
50 | unsigned int inputs[4]; | ||
51 | }; | ||
52 | |||
33 | struct vsp1_entity { | 53 | struct vsp1_entity { |
34 | struct vsp1_device *vsp1; | 54 | struct vsp1_device *vsp1; |
35 | 55 | ||
36 | enum vsp1_entity_type type; | 56 | enum vsp1_entity_type type; |
37 | unsigned int index; | 57 | unsigned int index; |
38 | unsigned int id; | 58 | const struct vsp1_route *route; |
39 | unsigned int route; | ||
40 | 59 | ||
41 | struct list_head list_dev; | 60 | struct list_head list_dev; |
42 | struct list_head list_pipe; | 61 | struct list_head list_pipe; |
@@ -45,6 +64,7 @@ struct vsp1_entity { | |||
45 | unsigned int source_pad; | 64 | unsigned int source_pad; |
46 | 65 | ||
47 | struct media_entity *sink; | 66 | struct media_entity *sink; |
67 | unsigned int sink_pad; | ||
48 | 68 | ||
49 | struct v4l2_subdev subdev; | 69 | struct v4l2_subdev subdev; |
50 | struct v4l2_mbus_framefmt *formats; | 70 | struct v4l2_mbus_framefmt *formats; |
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 285485350d82..db2950a73c60 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
@@ -193,13 +193,10 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) | |||
193 | 193 | ||
194 | hsit->inverse = inverse; | 194 | hsit->inverse = inverse; |
195 | 195 | ||
196 | if (inverse) { | 196 | if (inverse) |
197 | hsit->entity.type = VSP1_ENTITY_HSI; | 197 | hsit->entity.type = VSP1_ENTITY_HSI; |
198 | hsit->entity.id = VI6_DPR_NODE_HSI; | 198 | else |
199 | } else { | ||
200 | hsit->entity.type = VSP1_ENTITY_HST; | 199 | hsit->entity.type = VSP1_ENTITY_HST; |
201 | hsit->entity.id = VI6_DPR_NODE_HST; | ||
202 | } | ||
203 | 200 | ||
204 | ret = vsp1_entity_init(vsp1, &hsit->entity, 2); | 201 | ret = vsp1_entity_init(vsp1, &hsit->entity, 2); |
205 | if (ret < 0) | 202 | if (ret < 0) |
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 135a78957014..d4fb23e9c4a8 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c | |||
@@ -215,7 +215,6 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) | |||
215 | return ERR_PTR(-ENOMEM); | 215 | return ERR_PTR(-ENOMEM); |
216 | 216 | ||
217 | lif->entity.type = VSP1_ENTITY_LIF; | 217 | lif->entity.type = VSP1_ENTITY_LIF; |
218 | lif->entity.id = VI6_DPR_NODE_LIF; | ||
219 | 218 | ||
220 | ret = vsp1_entity_init(vsp1, &lif->entity, 2); | 219 | ret = vsp1_entity_init(vsp1, &lif->entity, 2); |
221 | if (ret < 0) | 220 | if (ret < 0) |
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4e9dc7c86ef8..fea36ebe2565 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c | |||
@@ -229,7 +229,6 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) | |||
229 | return ERR_PTR(-ENOMEM); | 229 | return ERR_PTR(-ENOMEM); |
230 | 230 | ||
231 | lut->entity.type = VSP1_ENTITY_LUT; | 231 | lut->entity.type = VSP1_ENTITY_LUT; |
232 | lut->entity.id = VI6_DPR_NODE_LUT; | ||
233 | 232 | ||
234 | ret = vsp1_entity_init(vsp1, &lut->entity, 2); | 233 | ret = vsp1_entity_init(vsp1, &lut->entity, 2); |
235 | if (ret < 0) | 234 | if (ret < 0) |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 28650806c20f..3e74b44286f6 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h | |||
@@ -451,13 +451,111 @@ | |||
451 | * BRU Control Registers | 451 | * BRU Control Registers |
452 | */ | 452 | */ |
453 | 453 | ||
454 | #define VI6_ROP_NOP 0 | ||
455 | #define VI6_ROP_AND 1 | ||
456 | #define VI6_ROP_AND_REV 2 | ||
457 | #define VI6_ROP_COPY 3 | ||
458 | #define VI6_ROP_AND_INV 4 | ||
459 | #define VI6_ROP_CLEAR 5 | ||
460 | #define VI6_ROP_XOR 6 | ||
461 | #define VI6_ROP_OR 7 | ||
462 | #define VI6_ROP_NOR 8 | ||
463 | #define VI6_ROP_EQUIV 9 | ||
464 | #define VI6_ROP_INVERT 10 | ||
465 | #define VI6_ROP_OR_REV 11 | ||
466 | #define VI6_ROP_COPY_INV 12 | ||
467 | #define VI6_ROP_OR_INV 13 | ||
468 | #define VI6_ROP_NAND 14 | ||
469 | #define VI6_ROP_SET 15 | ||
470 | |||
454 | #define VI6_BRU_INCTRL 0x2c00 | 471 | #define VI6_BRU_INCTRL 0x2c00 |
472 | #define VI6_BRU_INCTRL_NRM (1 << 28) | ||
473 | #define VI6_BRU_INCTRL_DnON (1 << (16 + (n))) | ||
474 | #define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4)) | ||
475 | #define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4)) | ||
476 | #define VI6_BRU_INCTRL_DITHn_16BPP (2 << ((n) * 4)) | ||
477 | #define VI6_BRU_INCTRL_DITHn_15BPP (3 << ((n) * 4)) | ||
478 | #define VI6_BRU_INCTRL_DITHn_12BPP (4 << ((n) * 4)) | ||
479 | #define VI6_BRU_INCTRL_DITHn_8BPP (5 << ((n) * 4)) | ||
480 | #define VI6_BRU_INCTRL_DITHn_MASK (7 << ((n) * 4)) | ||
481 | #define VI6_BRU_INCTRL_DITHn_SHIFT ((n) * 4) | ||
482 | |||
455 | #define VI6_BRU_VIRRPF_SIZE 0x2c04 | 483 | #define VI6_BRU_VIRRPF_SIZE 0x2c04 |
484 | #define VI6_BRU_VIRRPF_SIZE_HSIZE_MASK (0x1fff << 16) | ||
485 | #define VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT 16 | ||
486 | #define VI6_BRU_VIRRPF_SIZE_VSIZE_MASK (0x1fff << 0) | ||
487 | #define VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT 0 | ||
488 | |||
456 | #define VI6_BRU_VIRRPF_LOC 0x2c08 | 489 | #define VI6_BRU_VIRRPF_LOC 0x2c08 |
490 | #define VI6_BRU_VIRRPF_LOC_HCOORD_MASK (0x1fff << 16) | ||
491 | #define VI6_BRU_VIRRPF_LOC_HCOORD_SHIFT 16 | ||
492 | #define VI6_BRU_VIRRPF_LOC_VCOORD_MASK (0x1fff << 0) | ||
493 | #define VI6_BRU_VIRRPF_LOC_VCOORD_SHIFT 0 | ||
494 | |||
457 | #define VI6_BRU_VIRRPF_COL 0x2c0c | 495 | #define VI6_BRU_VIRRPF_COL 0x2c0c |
496 | #define VI6_BRU_VIRRPF_COL_A_MASK (0xff << 24) | ||
497 | #define VI6_BRU_VIRRPF_COL_A_SHIFT 24 | ||
498 | #define VI6_BRU_VIRRPF_COL_RCR_MASK (0xff << 16) | ||
499 | #define VI6_BRU_VIRRPF_COL_RCR_SHIFT 16 | ||
500 | #define VI6_BRU_VIRRPF_COL_GY_MASK (0xff << 8) | ||
501 | #define VI6_BRU_VIRRPF_COL_GY_SHIFT 8 | ||
502 | #define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0) | ||
503 | #define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0 | ||
504 | |||
458 | #define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8) | 505 | #define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8) |
506 | #define VI6_BRU_CTRL_RBC (1 << 31) | ||
507 | #define VI6_BRU_CTRL_DSTSEL_BRUIN(n) ((n) << 20) | ||
508 | #define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20) | ||
509 | #define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20) | ||
510 | #define VI6_BRU_CTRL_SRCSEL_BRUIN(n) ((n) << 16) | ||
511 | #define VI6_BRU_CTRL_SRCSEL_VRPF (4 << 16) | ||
512 | #define VI6_BRU_CTRL_SRCSEL_MASK (7 << 16) | ||
513 | #define VI6_BRU_CTRL_CROP(rop) ((rop) << 4) | ||
514 | #define VI6_BRU_CTRL_CROP_MASK (0xf << 4) | ||
515 | #define VI6_BRU_CTRL_AROP(rop) ((rop) << 0) | ||
516 | #define VI6_BRU_CTRL_AROP_MASK (0xf << 0) | ||
517 | |||
459 | #define VI6_BRU_BLD(n) (0x2c14 + (n) * 8) | 518 | #define VI6_BRU_BLD(n) (0x2c14 + (n) * 8) |
519 | #define VI6_BRU_BLD_CBES (1 << 31) | ||
520 | #define VI6_BRU_BLD_CCMDX_DST_A (0 << 28) | ||
521 | #define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28) | ||
522 | #define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28) | ||
523 | #define VI6_BRU_BLD_CCMDX_255_SRC_A (3 << 28) | ||
524 | #define VI6_BRU_BLD_CCMDX_COEFX (4 << 28) | ||
525 | #define VI6_BRU_BLD_CCMDX_MASK (7 << 28) | ||
526 | #define VI6_BRU_BLD_CCMDY_DST_A (0 << 24) | ||
527 | #define VI6_BRU_BLD_CCMDY_255_DST_A (1 << 24) | ||
528 | #define VI6_BRU_BLD_CCMDY_SRC_A (2 << 24) | ||
529 | #define VI6_BRU_BLD_CCMDY_255_SRC_A (3 << 24) | ||
530 | #define VI6_BRU_BLD_CCMDY_COEFY (4 << 24) | ||
531 | #define VI6_BRU_BLD_CCMDY_MASK (7 << 24) | ||
532 | #define VI6_BRU_BLD_CCMDY_SHIFT 24 | ||
533 | #define VI6_BRU_BLD_ABES (1 << 23) | ||
534 | #define VI6_BRU_BLD_ACMDX_DST_A (0 << 20) | ||
535 | #define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20) | ||
536 | #define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20) | ||
537 | #define VI6_BRU_BLD_ACMDX_255_SRC_A (3 << 20) | ||
538 | #define VI6_BRU_BLD_ACMDX_COEFX (4 << 20) | ||
539 | #define VI6_BRU_BLD_ACMDX_MASK (7 << 20) | ||
540 | #define VI6_BRU_BLD_ACMDY_DST_A (0 << 16) | ||
541 | #define VI6_BRU_BLD_ACMDY_255_DST_A (1 << 16) | ||
542 | #define VI6_BRU_BLD_ACMDY_SRC_A (2 << 16) | ||
543 | #define VI6_BRU_BLD_ACMDY_255_SRC_A (3 << 16) | ||
544 | #define VI6_BRU_BLD_ACMDY_COEFY (4 << 16) | ||
545 | #define VI6_BRU_BLD_ACMDY_MASK (7 << 16) | ||
546 | #define VI6_BRU_BLD_COEFX_MASK (0xff << 8) | ||
547 | #define VI6_BRU_BLD_COEFX_SHIFT 8 | ||
548 | #define VI6_BRU_BLD_COEFY_MASK (0xff << 0) | ||
549 | #define VI6_BRU_BLD_COEFY_SHIFT 0 | ||
550 | |||
460 | #define VI6_BRU_ROP 0x2c30 | 551 | #define VI6_BRU_ROP 0x2c30 |
552 | #define VI6_BRU_ROP_DSTSEL_BRUIN(n) ((n) << 20) | ||
553 | #define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20) | ||
554 | #define VI6_BRU_ROP_DSTSEL_MASK (7 << 20) | ||
555 | #define VI6_BRU_ROP_CROP(rop) ((rop) << 4) | ||
556 | #define VI6_BRU_ROP_CROP_MASK (0xf << 4) | ||
557 | #define VI6_BRU_ROP_AROP(rop) ((rop) << 0) | ||
558 | #define VI6_BRU_ROP_AROP_MASK (0xf << 0) | ||
461 | 559 | ||
462 | /* ----------------------------------------------------------------------------- | 560 | /* ----------------------------------------------------------------------------- |
463 | * HGO Control Registers | 561 | * HGO Control Registers |
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 2b04d0f95c62..c3d98642a4aa 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c | |||
@@ -96,8 +96,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
96 | vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); | 96 | vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); |
97 | vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); | 97 | vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); |
98 | 98 | ||
99 | /* Output location. Composing isn't supported yet. */ | 99 | /* Output location */ |
100 | vsp1_rpf_write(rpf, VI6_RPF_LOC, 0); | 100 | vsp1_rpf_write(rpf, VI6_RPF_LOC, |
101 | (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) | | ||
102 | (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT)); | ||
101 | 103 | ||
102 | /* Disable alpha, mask and color key. Set the alpha channel to a fixed | 104 | /* Disable alpha, mask and color key. Set the alpha channel to a fixed |
103 | * value of 255. | 105 | * value of 255. |
@@ -176,7 +178,6 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) | |||
176 | 178 | ||
177 | rpf->entity.type = VSP1_ENTITY_RPF; | 179 | rpf->entity.type = VSP1_ENTITY_RPF; |
178 | rpf->entity.index = index; | 180 | rpf->entity.index = index; |
179 | rpf->entity.id = VI6_DPR_NODE_RPF(index); | ||
180 | 181 | ||
181 | ret = vsp1_entity_init(vsp1, &rpf->entity, 2); | 182 | ret = vsp1_entity_init(vsp1, &rpf->entity, 2); |
182 | if (ret < 0) | 183 | if (ret < 0) |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 5c5ee81bbeae..b4fb65e58770 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
@@ -30,6 +30,10 @@ struct vsp1_rwpf { | |||
30 | unsigned int max_width; | 30 | unsigned int max_width; |
31 | unsigned int max_height; | 31 | unsigned int max_height; |
32 | 32 | ||
33 | struct { | ||
34 | unsigned int left; | ||
35 | unsigned int top; | ||
36 | } location; | ||
33 | struct v4l2_rect crop; | 37 | struct v4l2_rect crop; |
34 | 38 | ||
35 | unsigned int offsets[2]; | 39 | unsigned int offsets[2]; |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 7ab1a0b2d656..aa0e04c56f3f 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
@@ -327,7 +327,6 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) | |||
327 | return ERR_PTR(-ENOMEM); | 327 | return ERR_PTR(-ENOMEM); |
328 | 328 | ||
329 | sru->entity.type = VSP1_ENTITY_SRU; | 329 | sru->entity.type = VSP1_ENTITY_SRU; |
330 | sru->entity.id = VI6_DPR_NODE_SRU; | ||
331 | 330 | ||
332 | ret = vsp1_entity_init(vsp1, &sru->entity, 2); | 331 | ret = vsp1_entity_init(vsp1, &sru->entity, 2); |
333 | if (ret < 0) | 332 | if (ret < 0) |
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 622342ac7770..0293bdbb4401 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c | |||
@@ -131,7 +131,7 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) | |||
131 | return 0; | 131 | return 0; |
132 | 132 | ||
133 | /* Enable multi-tap scaling. */ | 133 | /* Enable multi-tap scaling. */ |
134 | vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_BC); | 134 | vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_AON | VI6_UDS_CTRL_BC); |
135 | 135 | ||
136 | vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, | 136 | vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, |
137 | (uds_passband_width(uds->hscale) | 137 | (uds_passband_width(uds->hscale) |
@@ -139,7 +139,6 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) | |||
139 | (uds_passband_width(uds->vscale) | 139 | (uds_passband_width(uds->vscale) |
140 | << VI6_UDS_PASS_BWIDTH_V_SHIFT)); | 140 | << VI6_UDS_PASS_BWIDTH_V_SHIFT)); |
141 | 141 | ||
142 | |||
143 | /* Set the scaling ratios and the output size. */ | 142 | /* Set the scaling ratios and the output size. */ |
144 | format = &uds->entity.formats[UDS_PAD_SOURCE]; | 143 | format = &uds->entity.formats[UDS_PAD_SOURCE]; |
145 | 144 | ||
@@ -323,7 +322,6 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) | |||
323 | 322 | ||
324 | uds->entity.type = VSP1_ENTITY_UDS; | 323 | uds->entity.type = VSP1_ENTITY_UDS; |
325 | uds->entity.index = index; | 324 | uds->entity.index = index; |
326 | uds->entity.id = VI6_DPR_NODE_UDS(index); | ||
327 | 325 | ||
328 | ret = vsp1_entity_init(vsp1, &uds->entity, 2); | 326 | ret = vsp1_entity_init(vsp1, &uds->entity, 2); |
329 | if (ret < 0) | 327 | if (ret < 0) |
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index a0595c17700f..8a1253e51f04 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <media/videobuf2-dma-contig.h> | 28 | #include <media/videobuf2-dma-contig.h> |
29 | 29 | ||
30 | #include "vsp1.h" | 30 | #include "vsp1.h" |
31 | #include "vsp1_bru.h" | ||
31 | #include "vsp1_entity.h" | 32 | #include "vsp1_entity.h" |
32 | #include "vsp1_rwpf.h" | 33 | #include "vsp1_rwpf.h" |
33 | #include "vsp1_video.h" | 34 | #include "vsp1_video.h" |
@@ -280,6 +281,9 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, | |||
280 | struct media_pad *pad; | 281 | struct media_pad *pad; |
281 | bool uds_found = false; | 282 | bool uds_found = false; |
282 | 283 | ||
284 | input->location.left = 0; | ||
285 | input->location.top = 0; | ||
286 | |||
283 | pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); | 287 | pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); |
284 | 288 | ||
285 | while (1) { | 289 | while (1) { |
@@ -292,6 +296,17 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, | |||
292 | 296 | ||
293 | entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); | 297 | entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); |
294 | 298 | ||
299 | /* A BRU is present in the pipeline, store the compose rectangle | ||
300 | * location in the input RPF for use when configuring the RPF. | ||
301 | */ | ||
302 | if (entity->type == VSP1_ENTITY_BRU) { | ||
303 | struct vsp1_bru *bru = to_bru(&entity->subdev); | ||
304 | struct v4l2_rect *rect = &bru->compose[pad->index]; | ||
305 | |||
306 | input->location.left = rect->left; | ||
307 | input->location.top = rect->top; | ||
308 | } | ||
309 | |||
295 | /* We've reached the WPF, we're done. */ | 310 | /* We've reached the WPF, we're done. */ |
296 | if (entity->type == VSP1_ENTITY_WPF) | 311 | if (entity->type == VSP1_ENTITY_WPF) |
297 | break; | 312 | break; |
@@ -363,6 +378,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, | |||
363 | rwpf->video.pipe_index = 0; | 378 | rwpf->video.pipe_index = 0; |
364 | } else if (e->type == VSP1_ENTITY_LIF) { | 379 | } else if (e->type == VSP1_ENTITY_LIF) { |
365 | pipe->lif = e; | 380 | pipe->lif = e; |
381 | } else if (e->type == VSP1_ENTITY_BRU) { | ||
382 | pipe->bru = e; | ||
366 | } | 383 | } |
367 | } | 384 | } |
368 | 385 | ||
@@ -392,6 +409,7 @@ error: | |||
392 | pipe->num_video = 0; | 409 | pipe->num_video = 0; |
393 | pipe->num_inputs = 0; | 410 | pipe->num_inputs = 0; |
394 | pipe->output = NULL; | 411 | pipe->output = NULL; |
412 | pipe->bru = NULL; | ||
395 | pipe->lif = NULL; | 413 | pipe->lif = NULL; |
396 | return ret; | 414 | return ret; |
397 | } | 415 | } |
@@ -430,6 +448,7 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe) | |||
430 | pipe->num_video = 0; | 448 | pipe->num_video = 0; |
431 | pipe->num_inputs = 0; | 449 | pipe->num_inputs = 0; |
432 | pipe->output = NULL; | 450 | pipe->output = NULL; |
451 | pipe->bru = NULL; | ||
433 | pipe->lif = NULL; | 452 | pipe->lif = NULL; |
434 | } | 453 | } |
435 | 454 | ||
@@ -461,7 +480,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) | |||
461 | 480 | ||
462 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | 481 | list_for_each_entry(entity, &pipe->entities, list_pipe) { |
463 | if (entity->route) | 482 | if (entity->route) |
464 | vsp1_write(entity->vsp1, entity->route, | 483 | vsp1_write(entity->vsp1, entity->route->reg, |
465 | VI6_DPR_NODE_UNUSED); | 484 | VI6_DPR_NODE_UNUSED); |
466 | 485 | ||
467 | v4l2_subdev_call(&entity->subdev, video, s_stream, 0); | 486 | v4l2_subdev_call(&entity->subdev, video, s_stream, 0); |
@@ -680,11 +699,12 @@ static void vsp1_entity_route_setup(struct vsp1_entity *source) | |||
680 | { | 699 | { |
681 | struct vsp1_entity *sink; | 700 | struct vsp1_entity *sink; |
682 | 701 | ||
683 | if (source->route == 0) | 702 | if (source->route->reg == 0) |
684 | return; | 703 | return; |
685 | 704 | ||
686 | sink = container_of(source->sink, struct vsp1_entity, subdev.entity); | 705 | sink = container_of(source->sink, struct vsp1_entity, subdev.entity); |
687 | vsp1_write(source->vsp1, source->route, sink->id); | 706 | vsp1_write(source->vsp1, source->route->reg, |
707 | sink->route->inputs[source->sink_pad]); | ||
688 | } | 708 | } |
689 | 709 | ||
690 | static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) | 710 | static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) |
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 53e4b3745940..c04d48fa2999 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h | |||
@@ -75,6 +75,7 @@ struct vsp1_pipeline { | |||
75 | unsigned int num_inputs; | 75 | unsigned int num_inputs; |
76 | struct vsp1_rwpf *inputs[VPS1_MAX_RPF]; | 76 | struct vsp1_rwpf *inputs[VPS1_MAX_RPF]; |
77 | struct vsp1_rwpf *output; | 77 | struct vsp1_rwpf *output; |
78 | struct vsp1_entity *bru; | ||
78 | struct vsp1_entity *lif; | 79 | struct vsp1_entity *lif; |
79 | 80 | ||
80 | struct list_head entities; | 81 | struct list_head entities; |
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 11a61c601da0..1294340dcb36 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -58,13 +58,21 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* Sources */ | 61 | /* Sources. If the pipeline has a single input configure it as the |
62 | * master layer. Otherwise configure all inputs as sub-layers and | ||
63 | * select the virtual RPF as the master layer. | ||
64 | */ | ||
62 | for (i = 0; i < pipe->num_inputs; ++i) { | 65 | for (i = 0; i < pipe->num_inputs; ++i) { |
63 | struct vsp1_rwpf *input = pipe->inputs[i]; | 66 | struct vsp1_rwpf *input = pipe->inputs[i]; |
64 | 67 | ||
65 | srcrpf |= VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index); | 68 | srcrpf |= pipe->num_inputs == 1 |
69 | ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) | ||
70 | : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); | ||
66 | } | 71 | } |
67 | 72 | ||
73 | if (pipe->num_inputs > 1) | ||
74 | srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; | ||
75 | |||
68 | vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); | 76 | vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); |
69 | 77 | ||
70 | /* Destination stride. */ | 78 | /* Destination stride. */ |
@@ -181,7 +189,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) | |||
181 | 189 | ||
182 | wpf->entity.type = VSP1_ENTITY_WPF; | 190 | wpf->entity.type = VSP1_ENTITY_WPF; |
183 | wpf->entity.index = index; | 191 | wpf->entity.index = index; |
184 | wpf->entity.id = VI6_DPR_NODE_WPF(index); | ||
185 | 192 | ||
186 | ret = vsp1_entity_init(vsp1, &wpf->entity, 2); | 193 | ret = vsp1_entity_init(vsp1, &wpf->entity, 2); |
187 | if (ret < 0) | 194 | if (ret < 0) |
diff --git a/include/media/adv7604.h b/include/media/adv7604.h index c6b39372eed7..aa1c4477722d 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h | |||
@@ -32,14 +32,18 @@ enum adv7604_ain_sel { | |||
32 | ADV7604_AIN9_4_5_6_SYNC_2_1 = 4, | 32 | ADV7604_AIN9_4_5_6_SYNC_2_1 = 4, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* Bus rotation and reordering (IO register 0x04, [7:5]) */ | 35 | /* |
36 | enum adv7604_op_ch_sel { | 36 | * Bus rotation and reordering. This is used to specify component reordering on |
37 | ADV7604_OP_CH_SEL_GBR = 0, | 37 | * the board and describes the components order on the bus when the ADV7604 |
38 | ADV7604_OP_CH_SEL_GRB = 1, | 38 | * outputs RGB. |
39 | ADV7604_OP_CH_SEL_BGR = 2, | 39 | */ |
40 | ADV7604_OP_CH_SEL_RGB = 3, | 40 | enum adv7604_bus_order { |
41 | ADV7604_OP_CH_SEL_BRG = 4, | 41 | ADV7604_BUS_ORDER_RGB, /* No operation */ |
42 | ADV7604_OP_CH_SEL_RBG = 5, | 42 | ADV7604_BUS_ORDER_GRB, /* Swap 1-2 */ |
43 | ADV7604_BUS_ORDER_RBG, /* Swap 2-3 */ | ||
44 | ADV7604_BUS_ORDER_BGR, /* Swap 1-3 */ | ||
45 | ADV7604_BUS_ORDER_BRG, /* Rotate right */ | ||
46 | ADV7604_BUS_ORDER_GBR, /* Rotate left */ | ||
43 | }; | 47 | }; |
44 | 48 | ||
45 | /* Input Color Space (IO register 0x02, [7:4]) */ | 49 | /* Input Color Space (IO register 0x02, [7:4]) */ |
@@ -55,29 +59,11 @@ enum adv7604_inp_color_space { | |||
55 | ADV7604_INP_COLOR_SPACE_AUTO = 0xf, | 59 | ADV7604_INP_COLOR_SPACE_AUTO = 0xf, |
56 | }; | 60 | }; |
57 | 61 | ||
58 | /* Select output format (IO register 0x03, [7:0]) */ | 62 | /* Select output format (IO register 0x03, [4:2]) */ |
59 | enum adv7604_op_format_sel { | 63 | enum adv7604_op_format_mode_sel { |
60 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_8 = 0x00, | 64 | ADV7604_OP_FORMAT_MODE0 = 0x00, |
61 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_10 = 0x01, | 65 | ADV7604_OP_FORMAT_MODE1 = 0x04, |
62 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE0 = 0x02, | 66 | ADV7604_OP_FORMAT_MODE2 = 0x08, |
63 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE1 = 0x06, | ||
64 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE2 = 0x0a, | ||
65 | ADV7604_OP_FORMAT_SEL_DDR_422_8 = 0x20, | ||
66 | ADV7604_OP_FORMAT_SEL_DDR_422_10 = 0x21, | ||
67 | ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE0 = 0x22, | ||
68 | ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE1 = 0x23, | ||
69 | ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE2 = 0x24, | ||
70 | ADV7604_OP_FORMAT_SEL_SDR_444_24 = 0x40, | ||
71 | ADV7604_OP_FORMAT_SEL_SDR_444_30 = 0x41, | ||
72 | ADV7604_OP_FORMAT_SEL_SDR_444_36_MODE0 = 0x42, | ||
73 | ADV7604_OP_FORMAT_SEL_DDR_444_24 = 0x60, | ||
74 | ADV7604_OP_FORMAT_SEL_DDR_444_30 = 0x61, | ||
75 | ADV7604_OP_FORMAT_SEL_DDR_444_36 = 0x62, | ||
76 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_16 = 0x80, | ||
77 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_20 = 0x81, | ||
78 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE0 = 0x82, | ||
79 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE1 = 0x86, | ||
80 | ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE2 = 0x8a, | ||
81 | }; | 67 | }; |
82 | 68 | ||
83 | enum adv7604_drive_strength { | 69 | enum adv7604_drive_strength { |
@@ -86,6 +72,30 @@ enum adv7604_drive_strength { | |||
86 | ADV7604_DR_STR_HIGH = 3, | 72 | ADV7604_DR_STR_HIGH = 3, |
87 | }; | 73 | }; |
88 | 74 | ||
75 | enum adv7604_int1_config { | ||
76 | ADV7604_INT1_CONFIG_OPEN_DRAIN, | ||
77 | ADV7604_INT1_CONFIG_ACTIVE_LOW, | ||
78 | ADV7604_INT1_CONFIG_ACTIVE_HIGH, | ||
79 | ADV7604_INT1_CONFIG_DISABLED, | ||
80 | }; | ||
81 | |||
82 | enum adv7604_page { | ||
83 | ADV7604_PAGE_IO, | ||
84 | ADV7604_PAGE_AVLINK, | ||
85 | ADV7604_PAGE_CEC, | ||
86 | ADV7604_PAGE_INFOFRAME, | ||
87 | ADV7604_PAGE_ESDP, | ||
88 | ADV7604_PAGE_DPP, | ||
89 | ADV7604_PAGE_AFE, | ||
90 | ADV7604_PAGE_REP, | ||
91 | ADV7604_PAGE_EDID, | ||
92 | ADV7604_PAGE_HDMI, | ||
93 | ADV7604_PAGE_TEST, | ||
94 | ADV7604_PAGE_CP, | ||
95 | ADV7604_PAGE_VDP, | ||
96 | ADV7604_PAGE_MAX, | ||
97 | }; | ||
98 | |||
89 | /* Platform dependent definition */ | 99 | /* Platform dependent definition */ |
90 | struct adv7604_platform_data { | 100 | struct adv7604_platform_data { |
91 | /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */ | 101 | /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */ |
@@ -94,30 +104,34 @@ struct adv7604_platform_data { | |||
94 | /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */ | 104 | /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */ |
95 | unsigned disable_cable_det_rst:1; | 105 | unsigned disable_cable_det_rst:1; |
96 | 106 | ||
107 | int default_input; | ||
108 | |||
97 | /* Analog input muxing mode */ | 109 | /* Analog input muxing mode */ |
98 | enum adv7604_ain_sel ain_sel; | 110 | enum adv7604_ain_sel ain_sel; |
99 | 111 | ||
100 | /* Bus rotation and reordering */ | 112 | /* Bus rotation and reordering */ |
101 | enum adv7604_op_ch_sel op_ch_sel; | 113 | enum adv7604_bus_order bus_order; |
102 | 114 | ||
103 | /* Select output format */ | 115 | /* Select output format mode */ |
104 | enum adv7604_op_format_sel op_format_sel; | 116 | enum adv7604_op_format_mode_sel op_format_mode_sel; |
117 | |||
118 | /* Configuration of the INT1 pin */ | ||
119 | enum adv7604_int1_config int1_config; | ||
105 | 120 | ||
106 | /* IO register 0x02 */ | 121 | /* IO register 0x02 */ |
107 | unsigned alt_gamma:1; | 122 | unsigned alt_gamma:1; |
108 | unsigned op_656_range:1; | 123 | unsigned op_656_range:1; |
109 | unsigned rgb_out:1; | ||
110 | unsigned alt_data_sat:1; | 124 | unsigned alt_data_sat:1; |
111 | 125 | ||
112 | /* IO register 0x05 */ | 126 | /* IO register 0x05 */ |
113 | unsigned blank_data:1; | 127 | unsigned blank_data:1; |
114 | unsigned insert_av_codes:1; | 128 | unsigned insert_av_codes:1; |
115 | unsigned replicate_av_codes:1; | 129 | unsigned replicate_av_codes:1; |
116 | unsigned invert_cbcr:1; | ||
117 | 130 | ||
118 | /* IO register 0x06 */ | 131 | /* IO register 0x06 */ |
119 | unsigned inv_vs_pol:1; | 132 | unsigned inv_vs_pol:1; |
120 | unsigned inv_hs_pol:1; | 133 | unsigned inv_hs_pol:1; |
134 | unsigned inv_llc_pol:1; | ||
121 | 135 | ||
122 | /* IO register 0x14 */ | 136 | /* IO register 0x14 */ |
123 | enum adv7604_drive_strength dr_str_data; | 137 | enum adv7604_drive_strength dr_str_data; |
@@ -131,34 +145,22 @@ struct adv7604_platform_data { | |||
131 | unsigned hdmi_free_run_mode; | 145 | unsigned hdmi_free_run_mode; |
132 | 146 | ||
133 | /* i2c addresses: 0 == use default */ | 147 | /* i2c addresses: 0 == use default */ |
134 | u8 i2c_avlink; | 148 | u8 i2c_addresses[ADV7604_PAGE_MAX]; |
135 | u8 i2c_cec; | ||
136 | u8 i2c_infoframe; | ||
137 | u8 i2c_esdp; | ||
138 | u8 i2c_dpp; | ||
139 | u8 i2c_afe; | ||
140 | u8 i2c_repeater; | ||
141 | u8 i2c_edid; | ||
142 | u8 i2c_hdmi; | ||
143 | u8 i2c_test; | ||
144 | u8 i2c_cp; | ||
145 | u8 i2c_vdp; | ||
146 | }; | 149 | }; |
147 | 150 | ||
148 | enum adv7604_input_port { | 151 | enum adv7604_pad { |
149 | ADV7604_INPUT_HDMI_PORT_A, | 152 | ADV7604_PAD_HDMI_PORT_A = 0, |
150 | ADV7604_INPUT_HDMI_PORT_B, | 153 | ADV7604_PAD_HDMI_PORT_B = 1, |
151 | ADV7604_INPUT_HDMI_PORT_C, | 154 | ADV7604_PAD_HDMI_PORT_C = 2, |
152 | ADV7604_INPUT_HDMI_PORT_D, | 155 | ADV7604_PAD_HDMI_PORT_D = 3, |
153 | ADV7604_INPUT_VGA_RGB, | 156 | ADV7604_PAD_VGA_RGB = 4, |
154 | ADV7604_INPUT_VGA_COMP, | 157 | ADV7604_PAD_VGA_COMP = 5, |
158 | /* The source pad is either 1 (ADV7611) or 6 (ADV7604) */ | ||
159 | ADV7604_PAD_SOURCE = 6, | ||
160 | ADV7611_PAD_SOURCE = 1, | ||
161 | ADV7604_PAD_MAX = 7, | ||
155 | }; | 162 | }; |
156 | 163 | ||
157 | #define ADV7604_EDID_PORT_A 0 | ||
158 | #define ADV7604_EDID_PORT_B 1 | ||
159 | #define ADV7604_EDID_PORT_C 2 | ||
160 | #define ADV7604_EDID_PORT_D 3 | ||
161 | |||
162 | #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) | 164 | #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) |
163 | #define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001) | 165 | #define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001) |
164 | #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) | 166 | #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) |
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 9fab013eea86..d7465725773d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
@@ -338,12 +338,8 @@ struct v4l2_subdev_video_ops { | |||
338 | struct v4l2_dv_timings *timings); | 338 | struct v4l2_dv_timings *timings); |
339 | int (*g_dv_timings)(struct v4l2_subdev *sd, | 339 | int (*g_dv_timings)(struct v4l2_subdev *sd, |
340 | struct v4l2_dv_timings *timings); | 340 | struct v4l2_dv_timings *timings); |
341 | int (*enum_dv_timings)(struct v4l2_subdev *sd, | ||
342 | struct v4l2_enum_dv_timings *timings); | ||
343 | int (*query_dv_timings)(struct v4l2_subdev *sd, | 341 | int (*query_dv_timings)(struct v4l2_subdev *sd, |
344 | struct v4l2_dv_timings *timings); | 342 | struct v4l2_dv_timings *timings); |
345 | int (*dv_timings_cap)(struct v4l2_subdev *sd, | ||
346 | struct v4l2_dv_timings_cap *cap); | ||
347 | int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, | 343 | int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, |
348 | enum v4l2_mbus_pixelcode *code); | 344 | enum v4l2_mbus_pixelcode *code); |
349 | int (*enum_mbus_fsizes)(struct v4l2_subdev *sd, | 345 | int (*enum_mbus_fsizes)(struct v4l2_subdev *sd, |