1b2ce5617SAnders Roxell // SPDX-License-Identifier: GPL-2.0-only
2b2ce5617SAnders Roxell /*
3b2ce5617SAnders Roxell * Analog Devices ADV7511 HDMI Transmitter Device Driver
4b2ce5617SAnders Roxell *
5b2ce5617SAnders Roxell * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6b2ce5617SAnders Roxell */
7b2ce5617SAnders Roxell
8b2ce5617SAnders Roxell /*
9b2ce5617SAnders Roxell * This file is named adv7511-v4l2.c so it doesn't conflict with the Analog
10b2ce5617SAnders Roxell * Device ADV7511 (config fragment CONFIG_DRM_I2C_ADV7511).
11b2ce5617SAnders Roxell */
12b2ce5617SAnders Roxell
13b2ce5617SAnders Roxell
14b2ce5617SAnders Roxell #include <linux/kernel.h>
15b2ce5617SAnders Roxell #include <linux/module.h>
16b2ce5617SAnders Roxell #include <linux/slab.h>
17b2ce5617SAnders Roxell #include <linux/i2c.h>
18b2ce5617SAnders Roxell #include <linux/delay.h>
19b2ce5617SAnders Roxell #include <linux/videodev2.h>
20b2ce5617SAnders Roxell #include <linux/workqueue.h>
21b2ce5617SAnders Roxell #include <linux/hdmi.h>
22b2ce5617SAnders Roxell #include <linux/v4l2-dv-timings.h>
23b2ce5617SAnders Roxell #include <media/v4l2-device.h>
24b2ce5617SAnders Roxell #include <media/v4l2-common.h>
25b2ce5617SAnders Roxell #include <media/v4l2-ctrls.h>
26b2ce5617SAnders Roxell #include <media/v4l2-dv-timings.h>
27b2ce5617SAnders Roxell #include <media/i2c/adv7511.h>
28b2ce5617SAnders Roxell #include <media/cec.h>
29b2ce5617SAnders Roxell
30b2ce5617SAnders Roxell static int debug;
31b2ce5617SAnders Roxell module_param(debug, int, 0644);
32b2ce5617SAnders Roxell MODULE_PARM_DESC(debug, "debug level (0-2)");
33b2ce5617SAnders Roxell
34b2ce5617SAnders Roxell MODULE_DESCRIPTION("Analog Devices ADV7511 HDMI Transmitter Device Driver");
35b2ce5617SAnders Roxell MODULE_AUTHOR("Hans Verkuil");
36b2ce5617SAnders Roxell MODULE_LICENSE("GPL v2");
37b2ce5617SAnders Roxell
38b2ce5617SAnders Roxell #define MASK_ADV7511_EDID_RDY_INT 0x04
39b2ce5617SAnders Roxell #define MASK_ADV7511_MSEN_INT 0x40
40b2ce5617SAnders Roxell #define MASK_ADV7511_HPD_INT 0x80
41b2ce5617SAnders Roxell
42b2ce5617SAnders Roxell #define MASK_ADV7511_HPD_DETECT 0x40
43b2ce5617SAnders Roxell #define MASK_ADV7511_MSEN_DETECT 0x20
44b2ce5617SAnders Roxell #define MASK_ADV7511_EDID_RDY 0x10
45b2ce5617SAnders Roxell
46b2ce5617SAnders Roxell #define EDID_MAX_RETRIES (8)
47b2ce5617SAnders Roxell #define EDID_DELAY 250
48b2ce5617SAnders Roxell #define EDID_MAX_SEGM 8
49b2ce5617SAnders Roxell
50b2ce5617SAnders Roxell #define ADV7511_MAX_WIDTH 1920
51b2ce5617SAnders Roxell #define ADV7511_MAX_HEIGHT 1200
52b2ce5617SAnders Roxell #define ADV7511_MIN_PIXELCLOCK 20000000
53b2ce5617SAnders Roxell #define ADV7511_MAX_PIXELCLOCK 225000000
54b2ce5617SAnders Roxell
55b2ce5617SAnders Roxell #define ADV7511_MAX_ADDRS (3)
56b2ce5617SAnders Roxell
57b2ce5617SAnders Roxell /*
58b2ce5617SAnders Roxell **********************************************************************
59b2ce5617SAnders Roxell *
60b2ce5617SAnders Roxell * Arrays with configuration parameters for the ADV7511
61b2ce5617SAnders Roxell *
62b2ce5617SAnders Roxell **********************************************************************
63b2ce5617SAnders Roxell */
64b2ce5617SAnders Roxell
65b2ce5617SAnders Roxell struct adv7511_state_edid {
66b2ce5617SAnders Roxell /* total number of blocks */
67b2ce5617SAnders Roxell u32 blocks;
68b2ce5617SAnders Roxell /* Number of segments read */
69b2ce5617SAnders Roxell u32 segments;
70b2ce5617SAnders Roxell u8 data[EDID_MAX_SEGM * 256];
71b2ce5617SAnders Roxell /* Number of EDID read retries left */
72b2ce5617SAnders Roxell unsigned read_retries;
73b2ce5617SAnders Roxell bool complete;
74b2ce5617SAnders Roxell };
75b2ce5617SAnders Roxell
76b2ce5617SAnders Roxell struct adv7511_state {
77b2ce5617SAnders Roxell struct adv7511_platform_data pdata;
78b2ce5617SAnders Roxell struct v4l2_subdev sd;
79b2ce5617SAnders Roxell struct media_pad pad;
80b2ce5617SAnders Roxell struct v4l2_ctrl_handler hdl;
81b2ce5617SAnders Roxell int chip_revision;
82b2ce5617SAnders Roxell u8 i2c_edid_addr;
83b2ce5617SAnders Roxell u8 i2c_pktmem_addr;
84b2ce5617SAnders Roxell u8 i2c_cec_addr;
85b2ce5617SAnders Roxell
86b2ce5617SAnders Roxell struct i2c_client *i2c_cec;
87b2ce5617SAnders Roxell struct cec_adapter *cec_adap;
88b2ce5617SAnders Roxell u8 cec_addr[ADV7511_MAX_ADDRS];
89b2ce5617SAnders Roxell u8 cec_valid_addrs;
90b2ce5617SAnders Roxell bool cec_enabled_adap;
91b2ce5617SAnders Roxell
92b2ce5617SAnders Roxell /* Is the adv7511 powered on? */
93b2ce5617SAnders Roxell bool power_on;
94b2ce5617SAnders Roxell /* Did we receive hotplug and rx-sense signals? */
95b2ce5617SAnders Roxell bool have_monitor;
96b2ce5617SAnders Roxell bool enabled_irq;
97b2ce5617SAnders Roxell /* timings from s_dv_timings */
98b2ce5617SAnders Roxell struct v4l2_dv_timings dv_timings;
99b2ce5617SAnders Roxell u32 fmt_code;
100b2ce5617SAnders Roxell u32 colorspace;
101b2ce5617SAnders Roxell u32 ycbcr_enc;
102b2ce5617SAnders Roxell u32 quantization;
103b2ce5617SAnders Roxell u32 xfer_func;
104b2ce5617SAnders Roxell u32 content_type;
105b2ce5617SAnders Roxell /* controls */
106b2ce5617SAnders Roxell struct v4l2_ctrl *hdmi_mode_ctrl;
107b2ce5617SAnders Roxell struct v4l2_ctrl *hotplug_ctrl;
108b2ce5617SAnders Roxell struct v4l2_ctrl *rx_sense_ctrl;
109b2ce5617SAnders Roxell struct v4l2_ctrl *have_edid0_ctrl;
110b2ce5617SAnders Roxell struct v4l2_ctrl *rgb_quantization_range_ctrl;
111b2ce5617SAnders Roxell struct v4l2_ctrl *content_type_ctrl;
112b2ce5617SAnders Roxell struct i2c_client *i2c_edid;
113b2ce5617SAnders Roxell struct i2c_client *i2c_pktmem;
114b2ce5617SAnders Roxell struct adv7511_state_edid edid;
115b2ce5617SAnders Roxell /* Running counter of the number of detected EDIDs (for debugging) */
116b2ce5617SAnders Roxell unsigned edid_detect_counter;
117b2ce5617SAnders Roxell struct workqueue_struct *work_queue;
118b2ce5617SAnders Roxell struct delayed_work edid_handler; /* work entry */
119b2ce5617SAnders Roxell };
120b2ce5617SAnders Roxell
121b2ce5617SAnders Roxell static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd);
122b2ce5617SAnders Roxell static bool adv7511_check_edid_status(struct v4l2_subdev *sd);
123b2ce5617SAnders Roxell static void adv7511_setup(struct v4l2_subdev *sd);
124b2ce5617SAnders Roxell static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq);
125b2ce5617SAnders Roxell static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
126b2ce5617SAnders Roxell
127b2ce5617SAnders Roxell
128b2ce5617SAnders Roxell static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
129b2ce5617SAnders Roxell .type = V4L2_DV_BT_656_1120,
130b2ce5617SAnders Roxell /* keep this initialization for compatibility with GCC < 4.4.6 */
131b2ce5617SAnders Roxell .reserved = { 0 },
132b2ce5617SAnders Roxell V4L2_INIT_BT_TIMINGS(640, ADV7511_MAX_WIDTH, 350, ADV7511_MAX_HEIGHT,
133b2ce5617SAnders Roxell ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
134b2ce5617SAnders Roxell V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
135b2ce5617SAnders Roxell V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
136b2ce5617SAnders Roxell V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
137b2ce5617SAnders Roxell V4L2_DV_BT_CAP_CUSTOM)
138b2ce5617SAnders Roxell };
139b2ce5617SAnders Roxell
get_adv7511_state(struct v4l2_subdev * sd)140b2ce5617SAnders Roxell static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd)
141b2ce5617SAnders Roxell {
142b2ce5617SAnders Roxell return container_of(sd, struct adv7511_state, sd);
143b2ce5617SAnders Roxell }
144b2ce5617SAnders Roxell
to_sd(struct v4l2_ctrl * ctrl)145b2ce5617SAnders Roxell static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
146b2ce5617SAnders Roxell {
147b2ce5617SAnders Roxell return &container_of(ctrl->handler, struct adv7511_state, hdl)->sd;
148b2ce5617SAnders Roxell }
149b2ce5617SAnders Roxell
150b2ce5617SAnders Roxell /* ------------------------ I2C ----------------------------------------------- */
151b2ce5617SAnders Roxell
adv_smbus_read_byte_data_check(struct i2c_client * client,u8 command,bool check)152b2ce5617SAnders Roxell static s32 adv_smbus_read_byte_data_check(struct i2c_client *client,
153b2ce5617SAnders Roxell u8 command, bool check)
154b2ce5617SAnders Roxell {
155b2ce5617SAnders Roxell union i2c_smbus_data data;
156b2ce5617SAnders Roxell
157b2ce5617SAnders Roxell if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags,
158b2ce5617SAnders Roxell I2C_SMBUS_READ, command,
159b2ce5617SAnders Roxell I2C_SMBUS_BYTE_DATA, &data))
160b2ce5617SAnders Roxell return data.byte;
161b2ce5617SAnders Roxell if (check)
162b2ce5617SAnders Roxell v4l_err(client, "error reading %02x, %02x\n",
163b2ce5617SAnders Roxell client->addr, command);
164b2ce5617SAnders Roxell return -1;
165b2ce5617SAnders Roxell }
166b2ce5617SAnders Roxell
adv_smbus_read_byte_data(struct i2c_client * client,u8 command)167b2ce5617SAnders Roxell static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command)
168b2ce5617SAnders Roxell {
169b2ce5617SAnders Roxell int i;
170b2ce5617SAnders Roxell for (i = 0; i < 3; i++) {
171b2ce5617SAnders Roxell int ret = adv_smbus_read_byte_data_check(client, command, true);
172b2ce5617SAnders Roxell if (ret >= 0) {
173b2ce5617SAnders Roxell if (i)
174b2ce5617SAnders Roxell v4l_err(client, "read ok after %d retries\n", i);
175b2ce5617SAnders Roxell return ret;
176b2ce5617SAnders Roxell }
177b2ce5617SAnders Roxell }
178b2ce5617SAnders Roxell v4l_err(client, "read failed\n");
179b2ce5617SAnders Roxell return -1;
180b2ce5617SAnders Roxell }
181b2ce5617SAnders Roxell
adv7511_rd(struct v4l2_subdev * sd,u8 reg)182b2ce5617SAnders Roxell static int adv7511_rd(struct v4l2_subdev *sd, u8 reg)
183b2ce5617SAnders Roxell {
184b2ce5617SAnders Roxell struct i2c_client *client = v4l2_get_subdevdata(sd);
185b2ce5617SAnders Roxell
186b2ce5617SAnders Roxell return adv_smbus_read_byte_data(client, reg);
187b2ce5617SAnders Roxell }
188b2ce5617SAnders Roxell
adv7511_wr(struct v4l2_subdev * sd,u8 reg,u8 val)189b2ce5617SAnders Roxell static int adv7511_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
190b2ce5617SAnders Roxell {
191b2ce5617SAnders Roxell struct i2c_client *client = v4l2_get_subdevdata(sd);
192b2ce5617SAnders Roxell int ret;
193b2ce5617SAnders Roxell int i;
194b2ce5617SAnders Roxell
195b2ce5617SAnders Roxell for (i = 0; i < 3; i++) {
196b2ce5617SAnders Roxell ret = i2c_smbus_write_byte_data(client, reg, val);
197b2ce5617SAnders Roxell if (ret == 0)
198b2ce5617SAnders Roxell return 0;
199b2ce5617SAnders Roxell }
200b2ce5617SAnders Roxell v4l2_err(sd, "%s: i2c write error\n", __func__);
201b2ce5617SAnders Roxell return ret;
202b2ce5617SAnders Roxell }
203b2ce5617SAnders Roxell
204b2ce5617SAnders Roxell /* To set specific bits in the register, a clear-mask is given (to be AND-ed),
205b2ce5617SAnders Roxell and then the value-mask (to be OR-ed). */
adv7511_wr_and_or(struct v4l2_subdev * sd,u8 reg,u8 clr_mask,u8 val_mask)206b2ce5617SAnders Roxell static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask)
207b2ce5617SAnders Roxell {
208b2ce5617SAnders Roxell adv7511_wr(sd, reg, (adv7511_rd(sd, reg) & clr_mask) | val_mask);
209b2ce5617SAnders Roxell }
210b2ce5617SAnders Roxell
adv7511_edid_rd(struct v4l2_subdev * sd,uint16_t len,uint8_t * buf)211eea62d6dSWolfram Sang static int adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf)
212b2ce5617SAnders Roxell {
213b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
214b2ce5617SAnders Roxell int i;
215b2ce5617SAnders Roxell
216b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s:\n", __func__);
217b2ce5617SAnders Roxell
218eea62d6dSWolfram Sang for (i = 0; i < len; i += I2C_SMBUS_BLOCK_MAX) {
219eea62d6dSWolfram Sang s32 ret;
220eea62d6dSWolfram Sang
221eea62d6dSWolfram Sang ret = i2c_smbus_read_i2c_block_data(state->i2c_edid, i,
222b2ce5617SAnders Roxell I2C_SMBUS_BLOCK_MAX, buf + i);
223eea62d6dSWolfram Sang if (ret < 0) {
224b2ce5617SAnders Roxell v4l2_err(sd, "%s: i2c read error\n", __func__);
225eea62d6dSWolfram Sang return ret;
226eea62d6dSWolfram Sang }
227eea62d6dSWolfram Sang }
228eea62d6dSWolfram Sang
229eea62d6dSWolfram Sang return 0;
230b2ce5617SAnders Roxell }
231b2ce5617SAnders Roxell
adv7511_cec_read(struct v4l2_subdev * sd,u8 reg)232b2ce5617SAnders Roxell static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg)
233b2ce5617SAnders Roxell {
234b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
235b2ce5617SAnders Roxell
236b2ce5617SAnders Roxell return i2c_smbus_read_byte_data(state->i2c_cec, reg);
237b2ce5617SAnders Roxell }
238b2ce5617SAnders Roxell
adv7511_cec_write(struct v4l2_subdev * sd,u8 reg,u8 val)239b2ce5617SAnders Roxell static int adv7511_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
240b2ce5617SAnders Roxell {
241b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
242b2ce5617SAnders Roxell int ret;
243b2ce5617SAnders Roxell int i;
244b2ce5617SAnders Roxell
245b2ce5617SAnders Roxell for (i = 0; i < 3; i++) {
246b2ce5617SAnders Roxell ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val);
247b2ce5617SAnders Roxell if (ret == 0)
248b2ce5617SAnders Roxell return 0;
249b2ce5617SAnders Roxell }
250b2ce5617SAnders Roxell v4l2_err(sd, "%s: I2C Write Problem\n", __func__);
251b2ce5617SAnders Roxell return ret;
252b2ce5617SAnders Roxell }
253b2ce5617SAnders Roxell
adv7511_cec_write_and_or(struct v4l2_subdev * sd,u8 reg,u8 mask,u8 val)254b2ce5617SAnders Roxell static inline int adv7511_cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask,
255b2ce5617SAnders Roxell u8 val)
256b2ce5617SAnders Roxell {
257b2ce5617SAnders Roxell return adv7511_cec_write(sd, reg, (adv7511_cec_read(sd, reg) & mask) | val);
258b2ce5617SAnders Roxell }
259b2ce5617SAnders Roxell
adv7511_pktmem_rd(struct v4l2_subdev * sd,u8 reg)260b2ce5617SAnders Roxell static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg)
261b2ce5617SAnders Roxell {
262b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
263b2ce5617SAnders Roxell
264b2ce5617SAnders Roxell return adv_smbus_read_byte_data(state->i2c_pktmem, reg);
265b2ce5617SAnders Roxell }
266b2ce5617SAnders Roxell
adv7511_have_hotplug(struct v4l2_subdev * sd)267b2ce5617SAnders Roxell static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd)
268b2ce5617SAnders Roxell {
269b2ce5617SAnders Roxell return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT;
270b2ce5617SAnders Roxell }
271b2ce5617SAnders Roxell
adv7511_have_rx_sense(struct v4l2_subdev * sd)272b2ce5617SAnders Roxell static inline bool adv7511_have_rx_sense(struct v4l2_subdev *sd)
273b2ce5617SAnders Roxell {
274b2ce5617SAnders Roxell return adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT;
275b2ce5617SAnders Roxell }
276b2ce5617SAnders Roxell
adv7511_csc_conversion_mode(struct v4l2_subdev * sd,u8 mode)277b2ce5617SAnders Roxell static void adv7511_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode)
278b2ce5617SAnders Roxell {
279b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5);
280b2ce5617SAnders Roxell }
281b2ce5617SAnders Roxell
adv7511_csc_coeff(struct v4l2_subdev * sd,u16 A1,u16 A2,u16 A3,u16 A4,u16 B1,u16 B2,u16 B3,u16 B4,u16 C1,u16 C2,u16 C3,u16 C4)282b2ce5617SAnders Roxell static void adv7511_csc_coeff(struct v4l2_subdev *sd,
283b2ce5617SAnders Roxell u16 A1, u16 A2, u16 A3, u16 A4,
284b2ce5617SAnders Roxell u16 B1, u16 B2, u16 B3, u16 B4,
285b2ce5617SAnders Roxell u16 C1, u16 C2, u16 C3, u16 C4)
286b2ce5617SAnders Roxell {
287b2ce5617SAnders Roxell /* A */
288b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x18, 0xe0, A1>>8);
289b2ce5617SAnders Roxell adv7511_wr(sd, 0x19, A1);
290b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x1A, 0xe0, A2>>8);
291b2ce5617SAnders Roxell adv7511_wr(sd, 0x1B, A2);
292b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x1c, 0xe0, A3>>8);
293b2ce5617SAnders Roxell adv7511_wr(sd, 0x1d, A3);
294b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x1e, 0xe0, A4>>8);
295b2ce5617SAnders Roxell adv7511_wr(sd, 0x1f, A4);
296b2ce5617SAnders Roxell
297b2ce5617SAnders Roxell /* B */
298b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x20, 0xe0, B1>>8);
299b2ce5617SAnders Roxell adv7511_wr(sd, 0x21, B1);
300b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x22, 0xe0, B2>>8);
301b2ce5617SAnders Roxell adv7511_wr(sd, 0x23, B2);
302b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x24, 0xe0, B3>>8);
303b2ce5617SAnders Roxell adv7511_wr(sd, 0x25, B3);
304b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x26, 0xe0, B4>>8);
305b2ce5617SAnders Roxell adv7511_wr(sd, 0x27, B4);
306b2ce5617SAnders Roxell
307b2ce5617SAnders Roxell /* C */
308b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x28, 0xe0, C1>>8);
309b2ce5617SAnders Roxell adv7511_wr(sd, 0x29, C1);
310b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x2A, 0xe0, C2>>8);
311b2ce5617SAnders Roxell adv7511_wr(sd, 0x2B, C2);
312b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x2C, 0xe0, C3>>8);
313b2ce5617SAnders Roxell adv7511_wr(sd, 0x2D, C3);
314b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x2E, 0xe0, C4>>8);
315b2ce5617SAnders Roxell adv7511_wr(sd, 0x2F, C4);
316b2ce5617SAnders Roxell }
317b2ce5617SAnders Roxell
adv7511_csc_rgb_full2limit(struct v4l2_subdev * sd,bool enable)318b2ce5617SAnders Roxell static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable)
319b2ce5617SAnders Roxell {
320b2ce5617SAnders Roxell if (enable) {
321b2ce5617SAnders Roxell u8 csc_mode = 0;
322b2ce5617SAnders Roxell adv7511_csc_conversion_mode(sd, csc_mode);
323b2ce5617SAnders Roxell adv7511_csc_coeff(sd,
324b2ce5617SAnders Roxell 4096-564, 0, 0, 256,
325b2ce5617SAnders Roxell 0, 4096-564, 0, 256,
326b2ce5617SAnders Roxell 0, 0, 4096-564, 256);
327b2ce5617SAnders Roxell /* enable CSC */
328b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x18, 0x7f, 0x80);
329b2ce5617SAnders Roxell /* AVI infoframe: Limited range RGB (16-235) */
330b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x57, 0xf3, 0x04);
331b2ce5617SAnders Roxell } else {
332b2ce5617SAnders Roxell /* disable CSC */
333b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0);
334b2ce5617SAnders Roxell /* AVI infoframe: Full range RGB (0-255) */
335b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x57, 0xf3, 0x08);
336b2ce5617SAnders Roxell }
337b2ce5617SAnders Roxell }
338b2ce5617SAnders Roxell
adv7511_set_rgb_quantization_mode(struct v4l2_subdev * sd,struct v4l2_ctrl * ctrl)339b2ce5617SAnders Roxell static void adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl)
340b2ce5617SAnders Roxell {
341b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
342b2ce5617SAnders Roxell
343b2ce5617SAnders Roxell /* Only makes sense for RGB formats */
344b2ce5617SAnders Roxell if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) {
345b2ce5617SAnders Roxell /* so just keep quantization */
346b2ce5617SAnders Roxell adv7511_csc_rgb_full2limit(sd, false);
347b2ce5617SAnders Roxell return;
348b2ce5617SAnders Roxell }
349b2ce5617SAnders Roxell
350b2ce5617SAnders Roxell switch (ctrl->val) {
351b2ce5617SAnders Roxell case V4L2_DV_RGB_RANGE_AUTO:
352b2ce5617SAnders Roxell /* automatic */
353b2ce5617SAnders Roxell if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {
354b2ce5617SAnders Roxell /* CE format, RGB limited range (16-235) */
355b2ce5617SAnders Roxell adv7511_csc_rgb_full2limit(sd, true);
356b2ce5617SAnders Roxell } else {
357b2ce5617SAnders Roxell /* not CE format, RGB full range (0-255) */
358b2ce5617SAnders Roxell adv7511_csc_rgb_full2limit(sd, false);
359b2ce5617SAnders Roxell }
360b2ce5617SAnders Roxell break;
361b2ce5617SAnders Roxell case V4L2_DV_RGB_RANGE_LIMITED:
362b2ce5617SAnders Roxell /* RGB limited range (16-235) */
363b2ce5617SAnders Roxell adv7511_csc_rgb_full2limit(sd, true);
364b2ce5617SAnders Roxell break;
365b2ce5617SAnders Roxell case V4L2_DV_RGB_RANGE_FULL:
366b2ce5617SAnders Roxell /* RGB full range (0-255) */
367b2ce5617SAnders Roxell adv7511_csc_rgb_full2limit(sd, false);
368b2ce5617SAnders Roxell break;
369b2ce5617SAnders Roxell }
370b2ce5617SAnders Roxell }
371b2ce5617SAnders Roxell
372b2ce5617SAnders Roxell /* ------------------------------ CTRL OPS ------------------------------ */
373b2ce5617SAnders Roxell
adv7511_s_ctrl(struct v4l2_ctrl * ctrl)374b2ce5617SAnders Roxell static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl)
375b2ce5617SAnders Roxell {
376b2ce5617SAnders Roxell struct v4l2_subdev *sd = to_sd(ctrl);
377b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
378b2ce5617SAnders Roxell
379b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
380b2ce5617SAnders Roxell
381b2ce5617SAnders Roxell if (state->hdmi_mode_ctrl == ctrl) {
382b2ce5617SAnders Roxell /* Set HDMI or DVI-D */
383b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
384b2ce5617SAnders Roxell return 0;
385b2ce5617SAnders Roxell }
386b2ce5617SAnders Roxell if (state->rgb_quantization_range_ctrl == ctrl) {
387b2ce5617SAnders Roxell adv7511_set_rgb_quantization_mode(sd, ctrl);
388b2ce5617SAnders Roxell return 0;
389b2ce5617SAnders Roxell }
390b2ce5617SAnders Roxell if (state->content_type_ctrl == ctrl) {
391b2ce5617SAnders Roxell u8 itc, cn;
392b2ce5617SAnders Roxell
393b2ce5617SAnders Roxell state->content_type = ctrl->val;
394b2ce5617SAnders Roxell itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC;
395b2ce5617SAnders Roxell cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS;
396b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x57, 0x7f, itc << 7);
397b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x59, 0xcf, cn << 4);
398b2ce5617SAnders Roxell return 0;
399b2ce5617SAnders Roxell }
400b2ce5617SAnders Roxell
401b2ce5617SAnders Roxell return -EINVAL;
402b2ce5617SAnders Roxell }
403b2ce5617SAnders Roxell
404b2ce5617SAnders Roxell static const struct v4l2_ctrl_ops adv7511_ctrl_ops = {
405b2ce5617SAnders Roxell .s_ctrl = adv7511_s_ctrl,
406b2ce5617SAnders Roxell };
407b2ce5617SAnders Roxell
408b2ce5617SAnders Roxell /* ---------------------------- CORE OPS ------------------------------------------- */
409b2ce5617SAnders Roxell
410b2ce5617SAnders Roxell #ifdef CONFIG_VIDEO_ADV_DEBUG
adv7511_inv_register(struct v4l2_subdev * sd)411b2ce5617SAnders Roxell static void adv7511_inv_register(struct v4l2_subdev *sd)
412b2ce5617SAnders Roxell {
413b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
414b2ce5617SAnders Roxell
415b2ce5617SAnders Roxell v4l2_info(sd, "0x000-0x0ff: Main Map\n");
416b2ce5617SAnders Roxell if (state->i2c_cec)
417b2ce5617SAnders Roxell v4l2_info(sd, "0x100-0x1ff: CEC Map\n");
418b2ce5617SAnders Roxell }
419b2ce5617SAnders Roxell
adv7511_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)420b2ce5617SAnders Roxell static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
421b2ce5617SAnders Roxell {
422b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
423b2ce5617SAnders Roxell
424b2ce5617SAnders Roxell reg->size = 1;
425b2ce5617SAnders Roxell switch (reg->reg >> 8) {
426b2ce5617SAnders Roxell case 0:
427b2ce5617SAnders Roxell reg->val = adv7511_rd(sd, reg->reg & 0xff);
428b2ce5617SAnders Roxell break;
429b2ce5617SAnders Roxell case 1:
430b2ce5617SAnders Roxell if (state->i2c_cec) {
431b2ce5617SAnders Roxell reg->val = adv7511_cec_read(sd, reg->reg & 0xff);
432b2ce5617SAnders Roxell break;
433b2ce5617SAnders Roxell }
4341771e9fbSGustavo A. R. Silva fallthrough;
435b2ce5617SAnders Roxell default:
436b2ce5617SAnders Roxell v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
437b2ce5617SAnders Roxell adv7511_inv_register(sd);
438b2ce5617SAnders Roxell break;
439b2ce5617SAnders Roxell }
440b2ce5617SAnders Roxell return 0;
441b2ce5617SAnders Roxell }
442b2ce5617SAnders Roxell
adv7511_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)443b2ce5617SAnders Roxell static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
444b2ce5617SAnders Roxell {
445b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
446b2ce5617SAnders Roxell
447b2ce5617SAnders Roxell switch (reg->reg >> 8) {
448b2ce5617SAnders Roxell case 0:
449b2ce5617SAnders Roxell adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff);
450b2ce5617SAnders Roxell break;
451b2ce5617SAnders Roxell case 1:
452b2ce5617SAnders Roxell if (state->i2c_cec) {
453b2ce5617SAnders Roxell adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff);
454b2ce5617SAnders Roxell break;
455b2ce5617SAnders Roxell }
4561771e9fbSGustavo A. R. Silva fallthrough;
457b2ce5617SAnders Roxell default:
458b2ce5617SAnders Roxell v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
459b2ce5617SAnders Roxell adv7511_inv_register(sd);
460b2ce5617SAnders Roxell break;
461b2ce5617SAnders Roxell }
462b2ce5617SAnders Roxell return 0;
463b2ce5617SAnders Roxell }
464b2ce5617SAnders Roxell #endif
465b2ce5617SAnders Roxell
466b2ce5617SAnders Roxell struct adv7511_cfg_read_infoframe {
467b2ce5617SAnders Roxell const char *desc;
468b2ce5617SAnders Roxell u8 present_reg;
469b2ce5617SAnders Roxell u8 present_mask;
470b2ce5617SAnders Roxell u8 header[3];
471b2ce5617SAnders Roxell u16 payload_addr;
472b2ce5617SAnders Roxell };
473b2ce5617SAnders Roxell
hdmi_infoframe_checksum(u8 * ptr,size_t size)474b2ce5617SAnders Roxell static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
475b2ce5617SAnders Roxell {
476b2ce5617SAnders Roxell u8 csum = 0;
477b2ce5617SAnders Roxell size_t i;
478b2ce5617SAnders Roxell
479b2ce5617SAnders Roxell /* compute checksum */
480b2ce5617SAnders Roxell for (i = 0; i < size; i++)
481b2ce5617SAnders Roxell csum += ptr[i];
482b2ce5617SAnders Roxell
483b2ce5617SAnders Roxell return 256 - csum;
484b2ce5617SAnders Roxell }
485b2ce5617SAnders Roxell
log_infoframe(struct v4l2_subdev * sd,const struct adv7511_cfg_read_infoframe * cri)486b2ce5617SAnders Roxell static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri)
487b2ce5617SAnders Roxell {
488b2ce5617SAnders Roxell struct i2c_client *client = v4l2_get_subdevdata(sd);
489b2ce5617SAnders Roxell struct device *dev = &client->dev;
490b2ce5617SAnders Roxell union hdmi_infoframe frame;
491b2ce5617SAnders Roxell u8 buffer[32];
492b2ce5617SAnders Roxell u8 len;
493b2ce5617SAnders Roxell int i;
494b2ce5617SAnders Roxell
495b2ce5617SAnders Roxell if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) {
496b2ce5617SAnders Roxell v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc);
497b2ce5617SAnders Roxell return;
498b2ce5617SAnders Roxell }
499b2ce5617SAnders Roxell
500b2ce5617SAnders Roxell memcpy(buffer, cri->header, sizeof(cri->header));
501b2ce5617SAnders Roxell
502b2ce5617SAnders Roxell len = buffer[2];
503b2ce5617SAnders Roxell
504b2ce5617SAnders Roxell if (len + 4 > sizeof(buffer)) {
505b2ce5617SAnders Roxell v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
506b2ce5617SAnders Roxell return;
507b2ce5617SAnders Roxell }
508b2ce5617SAnders Roxell
509b2ce5617SAnders Roxell if (cri->payload_addr >= 0x100) {
510b2ce5617SAnders Roxell for (i = 0; i < len; i++)
511b2ce5617SAnders Roxell buffer[i + 4] = adv7511_pktmem_rd(sd, cri->payload_addr + i - 0x100);
512b2ce5617SAnders Roxell } else {
513b2ce5617SAnders Roxell for (i = 0; i < len; i++)
514b2ce5617SAnders Roxell buffer[i + 4] = adv7511_rd(sd, cri->payload_addr + i);
515b2ce5617SAnders Roxell }
516b2ce5617SAnders Roxell buffer[3] = 0;
517b2ce5617SAnders Roxell buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
518b2ce5617SAnders Roxell
5194a92fc6eSTom Rix if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) {
520b2ce5617SAnders Roxell v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
521b2ce5617SAnders Roxell return;
522b2ce5617SAnders Roxell }
523b2ce5617SAnders Roxell
524b2ce5617SAnders Roxell hdmi_infoframe_log(KERN_INFO, dev, &frame);
525b2ce5617SAnders Roxell }
526b2ce5617SAnders Roxell
adv7511_log_infoframes(struct v4l2_subdev * sd)527b2ce5617SAnders Roxell static void adv7511_log_infoframes(struct v4l2_subdev *sd)
528b2ce5617SAnders Roxell {
529b2ce5617SAnders Roxell static const struct adv7511_cfg_read_infoframe cri[] = {
530b2ce5617SAnders Roxell { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 },
531b2ce5617SAnders Roxell { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 },
532b2ce5617SAnders Roxell { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 },
533b2ce5617SAnders Roxell };
534b2ce5617SAnders Roxell int i;
535b2ce5617SAnders Roxell
536b2ce5617SAnders Roxell for (i = 0; i < ARRAY_SIZE(cri); i++)
537b2ce5617SAnders Roxell log_infoframe(sd, &cri[i]);
538b2ce5617SAnders Roxell }
539b2ce5617SAnders Roxell
adv7511_log_status(struct v4l2_subdev * sd)540b2ce5617SAnders Roxell static int adv7511_log_status(struct v4l2_subdev *sd)
541b2ce5617SAnders Roxell {
542b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
543b2ce5617SAnders Roxell struct adv7511_state_edid *edid = &state->edid;
544b2ce5617SAnders Roxell int i;
545b2ce5617SAnders Roxell
546b2ce5617SAnders Roxell static const char * const states[] = {
547b2ce5617SAnders Roxell "in reset",
548b2ce5617SAnders Roxell "reading EDID",
549b2ce5617SAnders Roxell "idle",
550b2ce5617SAnders Roxell "initializing HDCP",
551b2ce5617SAnders Roxell "HDCP enabled",
552b2ce5617SAnders Roxell "initializing HDCP repeater",
553b2ce5617SAnders Roxell "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"
554b2ce5617SAnders Roxell };
555b2ce5617SAnders Roxell static const char * const errors[] = {
556b2ce5617SAnders Roxell "no error",
557b2ce5617SAnders Roxell "bad receiver BKSV",
558b2ce5617SAnders Roxell "Ri mismatch",
559b2ce5617SAnders Roxell "Pj mismatch",
560b2ce5617SAnders Roxell "i2c error",
561b2ce5617SAnders Roxell "timed out",
562b2ce5617SAnders Roxell "max repeater cascade exceeded",
563b2ce5617SAnders Roxell "hash check failed",
564b2ce5617SAnders Roxell "too many devices",
565b2ce5617SAnders Roxell "9", "A", "B", "C", "D", "E", "F"
566b2ce5617SAnders Roxell };
567b2ce5617SAnders Roxell
568b2ce5617SAnders Roxell v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off");
569b2ce5617SAnders Roxell v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n",
570b2ce5617SAnders Roxell (adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT) ? "detected" : "no",
571b2ce5617SAnders Roxell (adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT) ? "detected" : "no",
572b2ce5617SAnders Roxell edid->segments ? "found" : "no",
573b2ce5617SAnders Roxell edid->blocks);
574b2ce5617SAnders Roxell v4l2_info(sd, "%s output %s\n",
575b2ce5617SAnders Roxell (adv7511_rd(sd, 0xaf) & 0x02) ?
576b2ce5617SAnders Roxell "HDMI" : "DVI-D",
577b2ce5617SAnders Roxell (adv7511_rd(sd, 0xa1) & 0x3c) ?
578b2ce5617SAnders Roxell "disabled" : "enabled");
579b2ce5617SAnders Roxell v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n",
580b2ce5617SAnders Roxell states[adv7511_rd(sd, 0xc8) & 0xf],
581b2ce5617SAnders Roxell errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter,
582b2ce5617SAnders Roxell adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96));
583b2ce5617SAnders Roxell v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full");
584b2ce5617SAnders Roxell if (adv7511_rd(sd, 0xaf) & 0x02) {
585b2ce5617SAnders Roxell /* HDMI only */
586b2ce5617SAnders Roxell u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80;
587b2ce5617SAnders Roxell u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 |
588b2ce5617SAnders Roxell adv7511_rd(sd, 0x02) << 8 |
589b2ce5617SAnders Roxell adv7511_rd(sd, 0x03);
590b2ce5617SAnders Roxell u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2;
591b2ce5617SAnders Roxell u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f;
592b2ce5617SAnders Roxell u32 CTS;
593b2ce5617SAnders Roxell
594b2ce5617SAnders Roxell if (manual_cts)
595b2ce5617SAnders Roxell CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 |
596b2ce5617SAnders Roxell adv7511_rd(sd, 0x08) << 8 |
597b2ce5617SAnders Roxell adv7511_rd(sd, 0x09);
598b2ce5617SAnders Roxell else
599b2ce5617SAnders Roxell CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 |
600b2ce5617SAnders Roxell adv7511_rd(sd, 0x05) << 8 |
601b2ce5617SAnders Roxell adv7511_rd(sd, 0x06);
602b2ce5617SAnders Roxell v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n",
603b2ce5617SAnders Roxell manual_cts ? "manual" : "automatic", N, CTS);
604b2ce5617SAnders Roxell v4l2_info(sd, "VIC: detected %d, sent %d\n",
605b2ce5617SAnders Roxell vic_detect, vic_sent);
606b2ce5617SAnders Roxell adv7511_log_infoframes(sd);
607b2ce5617SAnders Roxell }
608b2ce5617SAnders Roxell if (state->dv_timings.type == V4L2_DV_BT_656_1120)
609b2ce5617SAnders Roxell v4l2_print_dv_timings(sd->name, "timings: ",
610b2ce5617SAnders Roxell &state->dv_timings, false);
611b2ce5617SAnders Roxell else
612b2ce5617SAnders Roxell v4l2_info(sd, "no timings set\n");
613b2ce5617SAnders Roxell v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr);
614b2ce5617SAnders Roxell
615b2ce5617SAnders Roxell if (state->i2c_cec == NULL)
616b2ce5617SAnders Roxell return 0;
617b2ce5617SAnders Roxell
618b2ce5617SAnders Roxell v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr);
619b2ce5617SAnders Roxell
620b2ce5617SAnders Roxell v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ?
621b2ce5617SAnders Roxell "enabled" : "disabled");
622b2ce5617SAnders Roxell if (state->cec_enabled_adap) {
623b2ce5617SAnders Roxell for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
624b2ce5617SAnders Roxell bool is_valid = state->cec_valid_addrs & (1 << i);
625b2ce5617SAnders Roxell
626b2ce5617SAnders Roxell if (is_valid)
627b2ce5617SAnders Roxell v4l2_info(sd, "CEC Logical Address: 0x%x\n",
628b2ce5617SAnders Roxell state->cec_addr[i]);
629b2ce5617SAnders Roxell }
630b2ce5617SAnders Roxell }
631b2ce5617SAnders Roxell v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr);
632b2ce5617SAnders Roxell return 0;
633b2ce5617SAnders Roxell }
634b2ce5617SAnders Roxell
635b2ce5617SAnders Roxell /* Power up/down adv7511 */
adv7511_s_power(struct v4l2_subdev * sd,int on)636b2ce5617SAnders Roxell static int adv7511_s_power(struct v4l2_subdev *sd, int on)
637b2ce5617SAnders Roxell {
638b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
639b2ce5617SAnders Roxell const int retries = 20;
640b2ce5617SAnders Roxell int i;
641b2ce5617SAnders Roxell
642b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off");
643b2ce5617SAnders Roxell
644b2ce5617SAnders Roxell state->power_on = on;
645b2ce5617SAnders Roxell
646b2ce5617SAnders Roxell if (!on) {
647b2ce5617SAnders Roxell /* Power down */
648b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40);
649b2ce5617SAnders Roxell return true;
650b2ce5617SAnders Roxell }
651b2ce5617SAnders Roxell
652b2ce5617SAnders Roxell /* Power up */
653b2ce5617SAnders Roxell /* The adv7511 does not always come up immediately.
654b2ce5617SAnders Roxell Retry multiple times. */
655b2ce5617SAnders Roxell for (i = 0; i < retries; i++) {
656b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x41, 0xbf, 0x0);
657b2ce5617SAnders Roxell if ((adv7511_rd(sd, 0x41) & 0x40) == 0)
658b2ce5617SAnders Roxell break;
659b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40);
660b2ce5617SAnders Roxell msleep(10);
661b2ce5617SAnders Roxell }
662b2ce5617SAnders Roxell if (i == retries) {
663b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: failed to powerup the adv7511!\n", __func__);
664b2ce5617SAnders Roxell adv7511_s_power(sd, 0);
665b2ce5617SAnders Roxell return false;
666b2ce5617SAnders Roxell }
667b2ce5617SAnders Roxell if (i > 1)
668b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: needed %d retries to powerup the adv7511\n", __func__, i);
669b2ce5617SAnders Roxell
670b2ce5617SAnders Roxell /* Reserved registers that must be set */
671b2ce5617SAnders Roxell adv7511_wr(sd, 0x98, 0x03);
672b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x9a, 0xfe, 0x70);
673b2ce5617SAnders Roxell adv7511_wr(sd, 0x9c, 0x30);
674b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x9d, 0xfc, 0x01);
675b2ce5617SAnders Roxell adv7511_wr(sd, 0xa2, 0xa4);
676b2ce5617SAnders Roxell adv7511_wr(sd, 0xa3, 0xa4);
677b2ce5617SAnders Roxell adv7511_wr(sd, 0xe0, 0xd0);
678b2ce5617SAnders Roxell adv7511_wr(sd, 0xf9, 0x00);
679b2ce5617SAnders Roxell
680b2ce5617SAnders Roxell adv7511_wr(sd, 0x43, state->i2c_edid_addr);
681b2ce5617SAnders Roxell adv7511_wr(sd, 0x45, state->i2c_pktmem_addr);
682b2ce5617SAnders Roxell
683b2ce5617SAnders Roxell /* Set number of attempts to read the EDID */
684b2ce5617SAnders Roxell adv7511_wr(sd, 0xc9, 0xf);
685b2ce5617SAnders Roxell return true;
686b2ce5617SAnders Roxell }
687b2ce5617SAnders Roxell
688b2ce5617SAnders Roxell #if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC)
adv7511_cec_adap_enable(struct cec_adapter * adap,bool enable)689b2ce5617SAnders Roxell static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
690b2ce5617SAnders Roxell {
691b2ce5617SAnders Roxell struct adv7511_state *state = cec_get_drvdata(adap);
692b2ce5617SAnders Roxell struct v4l2_subdev *sd = &state->sd;
693b2ce5617SAnders Roxell
694b2ce5617SAnders Roxell if (state->i2c_cec == NULL)
695b2ce5617SAnders Roxell return -EIO;
696b2ce5617SAnders Roxell
697b2ce5617SAnders Roxell if (!state->cec_enabled_adap && enable) {
698b2ce5617SAnders Roxell /* power up cec section */
699b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01);
700b2ce5617SAnders Roxell /* legacy mode and clear all rx buffers */
701b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4a, 0x00);
702b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4a, 0x07);
703b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */
704b2ce5617SAnders Roxell /* enabled irqs: */
705b2ce5617SAnders Roxell /* tx: ready */
706b2ce5617SAnders Roxell /* tx: arbitration lost */
707b2ce5617SAnders Roxell /* tx: retry timeout */
708b2ce5617SAnders Roxell /* rx: ready 1 */
709b2ce5617SAnders Roxell if (state->enabled_irq)
710b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39);
711b2ce5617SAnders Roxell } else if (state->cec_enabled_adap && !enable) {
712b2ce5617SAnders Roxell if (state->enabled_irq)
713b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00);
714b2ce5617SAnders Roxell /* disable address mask 1-3 */
715b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0x00);
716b2ce5617SAnders Roxell /* power down cec section */
717b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x00);
718b2ce5617SAnders Roxell state->cec_valid_addrs = 0;
719b2ce5617SAnders Roxell }
720b2ce5617SAnders Roxell state->cec_enabled_adap = enable;
721b2ce5617SAnders Roxell return 0;
722b2ce5617SAnders Roxell }
723b2ce5617SAnders Roxell
adv7511_cec_adap_log_addr(struct cec_adapter * adap,u8 addr)724b2ce5617SAnders Roxell static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
725b2ce5617SAnders Roxell {
726b2ce5617SAnders Roxell struct adv7511_state *state = cec_get_drvdata(adap);
727b2ce5617SAnders Roxell struct v4l2_subdev *sd = &state->sd;
728b2ce5617SAnders Roxell unsigned int i, free_idx = ADV7511_MAX_ADDRS;
729b2ce5617SAnders Roxell
730b2ce5617SAnders Roxell if (!state->cec_enabled_adap)
731b2ce5617SAnders Roxell return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
732b2ce5617SAnders Roxell
733b2ce5617SAnders Roxell if (addr == CEC_LOG_ADDR_INVALID) {
734b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0);
735b2ce5617SAnders Roxell state->cec_valid_addrs = 0;
736b2ce5617SAnders Roxell return 0;
737b2ce5617SAnders Roxell }
738b2ce5617SAnders Roxell
739b2ce5617SAnders Roxell for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
740b2ce5617SAnders Roxell bool is_valid = state->cec_valid_addrs & (1 << i);
741b2ce5617SAnders Roxell
742b2ce5617SAnders Roxell if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
743b2ce5617SAnders Roxell free_idx = i;
744b2ce5617SAnders Roxell if (is_valid && state->cec_addr[i] == addr)
745b2ce5617SAnders Roxell return 0;
746b2ce5617SAnders Roxell }
747b2ce5617SAnders Roxell if (i == ADV7511_MAX_ADDRS) {
748b2ce5617SAnders Roxell i = free_idx;
749b2ce5617SAnders Roxell if (i == ADV7511_MAX_ADDRS)
750b2ce5617SAnders Roxell return -ENXIO;
751b2ce5617SAnders Roxell }
752b2ce5617SAnders Roxell state->cec_addr[i] = addr;
753b2ce5617SAnders Roxell state->cec_valid_addrs |= 1 << i;
754b2ce5617SAnders Roxell
755b2ce5617SAnders Roxell switch (i) {
756b2ce5617SAnders Roxell case 0:
757b2ce5617SAnders Roxell /* enable address mask 0 */
758b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4b, 0xef, 0x10);
759b2ce5617SAnders Roxell /* set address for mask 0 */
760b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4c, 0xf0, addr);
761b2ce5617SAnders Roxell break;
762b2ce5617SAnders Roxell case 1:
763b2ce5617SAnders Roxell /* enable address mask 1 */
764b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4b, 0xdf, 0x20);
765b2ce5617SAnders Roxell /* set address for mask 1 */
766b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4c, 0x0f, addr << 4);
767b2ce5617SAnders Roxell break;
768b2ce5617SAnders Roxell case 2:
769b2ce5617SAnders Roxell /* enable address mask 2 */
770b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4b, 0xbf, 0x40);
771b2ce5617SAnders Roxell /* set address for mask 1 */
772b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x4d, 0xf0, addr);
773b2ce5617SAnders Roxell break;
774b2ce5617SAnders Roxell }
775b2ce5617SAnders Roxell return 0;
776b2ce5617SAnders Roxell }
777b2ce5617SAnders Roxell
adv7511_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)778b2ce5617SAnders Roxell static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
779b2ce5617SAnders Roxell u32 signal_free_time, struct cec_msg *msg)
780b2ce5617SAnders Roxell {
781b2ce5617SAnders Roxell struct adv7511_state *state = cec_get_drvdata(adap);
782b2ce5617SAnders Roxell struct v4l2_subdev *sd = &state->sd;
783b2ce5617SAnders Roxell u8 len = msg->len;
784b2ce5617SAnders Roxell unsigned int i;
785b2ce5617SAnders Roxell
786b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len);
787b2ce5617SAnders Roxell
788b2ce5617SAnders Roxell if (len > 16) {
789b2ce5617SAnders Roxell v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len);
790b2ce5617SAnders Roxell return -EINVAL;
791b2ce5617SAnders Roxell }
792b2ce5617SAnders Roxell
793b2ce5617SAnders Roxell /*
794b2ce5617SAnders Roxell * The number of retries is the number of attempts - 1, but retry
795b2ce5617SAnders Roxell * at least once. It's not clear if a value of 0 is allowed, so
796b2ce5617SAnders Roxell * let's do at least one retry.
797b2ce5617SAnders Roxell */
798b2ce5617SAnders Roxell adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4);
799b2ce5617SAnders Roxell
800b2ce5617SAnders Roxell /* clear cec tx irq status */
801b2ce5617SAnders Roxell adv7511_wr(sd, 0x97, 0x38);
802b2ce5617SAnders Roxell
803b2ce5617SAnders Roxell /* write data */
804b2ce5617SAnders Roxell for (i = 0; i < len; i++)
805b2ce5617SAnders Roxell adv7511_cec_write(sd, i, msg->msg[i]);
806b2ce5617SAnders Roxell
807b2ce5617SAnders Roxell /* set length (data + header) */
808b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x10, len);
809b2ce5617SAnders Roxell /* start transmit, enable tx */
810b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x11, 0x01);
811b2ce5617SAnders Roxell return 0;
812b2ce5617SAnders Roxell }
813b2ce5617SAnders Roxell
adv_cec_tx_raw_status(struct v4l2_subdev * sd,u8 tx_raw_status)814b2ce5617SAnders Roxell static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status)
815b2ce5617SAnders Roxell {
816b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
817b2ce5617SAnders Roxell
818b2ce5617SAnders Roxell if ((adv7511_cec_read(sd, 0x11) & 0x01) == 0) {
819b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__);
820b2ce5617SAnders Roxell return;
821b2ce5617SAnders Roxell }
822b2ce5617SAnders Roxell
823b2ce5617SAnders Roxell if (tx_raw_status & 0x10) {
824b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd,
825b2ce5617SAnders Roxell "%s: tx raw: arbitration lost\n", __func__);
826b2ce5617SAnders Roxell cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST,
827b2ce5617SAnders Roxell 1, 0, 0, 0);
828b2ce5617SAnders Roxell return;
829b2ce5617SAnders Roxell }
830b2ce5617SAnders Roxell if (tx_raw_status & 0x08) {
831b2ce5617SAnders Roxell u8 status;
832b2ce5617SAnders Roxell u8 nack_cnt;
833b2ce5617SAnders Roxell u8 low_drive_cnt;
834b2ce5617SAnders Roxell
835b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__);
836b2ce5617SAnders Roxell /*
837b2ce5617SAnders Roxell * We set this status bit since this hardware performs
838b2ce5617SAnders Roxell * retransmissions.
839b2ce5617SAnders Roxell */
840b2ce5617SAnders Roxell status = CEC_TX_STATUS_MAX_RETRIES;
841b2ce5617SAnders Roxell nack_cnt = adv7511_cec_read(sd, 0x14) & 0xf;
842b2ce5617SAnders Roxell if (nack_cnt)
843b2ce5617SAnders Roxell status |= CEC_TX_STATUS_NACK;
844b2ce5617SAnders Roxell low_drive_cnt = adv7511_cec_read(sd, 0x14) >> 4;
845b2ce5617SAnders Roxell if (low_drive_cnt)
846b2ce5617SAnders Roxell status |= CEC_TX_STATUS_LOW_DRIVE;
847b2ce5617SAnders Roxell cec_transmit_done(state->cec_adap, status,
848b2ce5617SAnders Roxell 0, nack_cnt, low_drive_cnt, 0);
849b2ce5617SAnders Roxell return;
850b2ce5617SAnders Roxell }
851b2ce5617SAnders Roxell if (tx_raw_status & 0x20) {
852b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__);
853b2ce5617SAnders Roxell cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
854b2ce5617SAnders Roxell return;
855b2ce5617SAnders Roxell }
856b2ce5617SAnders Roxell }
857b2ce5617SAnders Roxell
858b2ce5617SAnders Roxell static const struct cec_adap_ops adv7511_cec_adap_ops = {
859b2ce5617SAnders Roxell .adap_enable = adv7511_cec_adap_enable,
860b2ce5617SAnders Roxell .adap_log_addr = adv7511_cec_adap_log_addr,
861b2ce5617SAnders Roxell .adap_transmit = adv7511_cec_adap_transmit,
862b2ce5617SAnders Roxell };
863b2ce5617SAnders Roxell #endif
864b2ce5617SAnders Roxell
865b2ce5617SAnders Roxell /* Enable interrupts */
adv7511_set_isr(struct v4l2_subdev * sd,bool enable)866b2ce5617SAnders Roxell static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)
867b2ce5617SAnders Roxell {
868b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
869b2ce5617SAnders Roxell u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT;
870b2ce5617SAnders Roxell u8 irqs_rd;
871b2ce5617SAnders Roxell int retries = 100;
872b2ce5617SAnders Roxell
873b2ce5617SAnders Roxell v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable");
874b2ce5617SAnders Roxell
875b2ce5617SAnders Roxell if (state->enabled_irq == enable)
876b2ce5617SAnders Roxell return;
877b2ce5617SAnders Roxell state->enabled_irq = enable;
878b2ce5617SAnders Roxell
879b2ce5617SAnders Roxell /* The datasheet says that the EDID ready interrupt should be
880b2ce5617SAnders Roxell disabled if there is no hotplug. */
881b2ce5617SAnders Roxell if (!enable)
882b2ce5617SAnders Roxell irqs = 0;
883b2ce5617SAnders Roxell else if (adv7511_have_hotplug(sd))
884b2ce5617SAnders Roxell irqs |= MASK_ADV7511_EDID_RDY_INT;
885b2ce5617SAnders Roxell
886b2ce5617SAnders Roxell /*
887b2ce5617SAnders Roxell * This i2c write can fail (approx. 1 in 1000 writes). But it
888b2ce5617SAnders Roxell * is essential that this register is correct, so retry it
889b2ce5617SAnders Roxell * multiple times.
890b2ce5617SAnders Roxell *
891b2ce5617SAnders Roxell * Note that the i2c write does not report an error, but the readback
892b2ce5617SAnders Roxell * clearly shows the wrong value.
893b2ce5617SAnders Roxell */
894b2ce5617SAnders Roxell do {
895b2ce5617SAnders Roxell adv7511_wr(sd, 0x94, irqs);
896b2ce5617SAnders Roxell irqs_rd = adv7511_rd(sd, 0x94);
897b2ce5617SAnders Roxell } while (retries-- && irqs_rd != irqs);
898b2ce5617SAnders Roxell
899b2ce5617SAnders Roxell if (irqs_rd != irqs)
900b2ce5617SAnders Roxell v4l2_err(sd, "Could not set interrupts: hw failure?\n");
901b2ce5617SAnders Roxell
902b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x95, 0xc0,
903b2ce5617SAnders Roxell (state->cec_enabled_adap && enable) ? 0x39 : 0x00);
904b2ce5617SAnders Roxell }
905b2ce5617SAnders Roxell
906b2ce5617SAnders Roxell /* Interrupt handler */
adv7511_isr(struct v4l2_subdev * sd,u32 status,bool * handled)907b2ce5617SAnders Roxell static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
908b2ce5617SAnders Roxell {
909b2ce5617SAnders Roxell u8 irq_status;
910b2ce5617SAnders Roxell u8 cec_irq;
911b2ce5617SAnders Roxell
912b2ce5617SAnders Roxell /* disable interrupts to prevent a race condition */
913b2ce5617SAnders Roxell adv7511_set_isr(sd, false);
914b2ce5617SAnders Roxell irq_status = adv7511_rd(sd, 0x96);
915b2ce5617SAnders Roxell cec_irq = adv7511_rd(sd, 0x97);
916b2ce5617SAnders Roxell /* clear detected interrupts */
917b2ce5617SAnders Roxell adv7511_wr(sd, 0x96, irq_status);
918b2ce5617SAnders Roxell adv7511_wr(sd, 0x97, cec_irq);
919b2ce5617SAnders Roxell
920b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__,
921b2ce5617SAnders Roxell irq_status, cec_irq);
922b2ce5617SAnders Roxell
923b2ce5617SAnders Roxell if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT))
924b2ce5617SAnders Roxell adv7511_check_monitor_present_status(sd);
925b2ce5617SAnders Roxell if (irq_status & MASK_ADV7511_EDID_RDY_INT)
926b2ce5617SAnders Roxell adv7511_check_edid_status(sd);
927b2ce5617SAnders Roxell
928b2ce5617SAnders Roxell #if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC)
929b2ce5617SAnders Roxell if (cec_irq & 0x38)
930b2ce5617SAnders Roxell adv_cec_tx_raw_status(sd, cec_irq);
931b2ce5617SAnders Roxell
932b2ce5617SAnders Roxell if (cec_irq & 1) {
933b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
934b2ce5617SAnders Roxell struct cec_msg msg;
935b2ce5617SAnders Roxell
936b2ce5617SAnders Roxell msg.len = adv7511_cec_read(sd, 0x25) & 0x1f;
937b2ce5617SAnders Roxell
938b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__,
939b2ce5617SAnders Roxell msg.len);
940b2ce5617SAnders Roxell
94105c480f4SHans Verkuil if (msg.len > CEC_MAX_MSG_SIZE)
94205c480f4SHans Verkuil msg.len = CEC_MAX_MSG_SIZE;
943b2ce5617SAnders Roxell
944b2ce5617SAnders Roxell if (msg.len) {
945b2ce5617SAnders Roxell u8 i;
946b2ce5617SAnders Roxell
947b2ce5617SAnders Roxell for (i = 0; i < msg.len; i++)
948b2ce5617SAnders Roxell msg.msg[i] = adv7511_cec_read(sd, i + 0x15);
949b2ce5617SAnders Roxell
950b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4a, 0); /* toggle to re-enable rx 1 */
951b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4a, 1);
952b2ce5617SAnders Roxell cec_received_msg(state->cec_adap, &msg);
953b2ce5617SAnders Roxell }
954b2ce5617SAnders Roxell }
955b2ce5617SAnders Roxell #endif
956b2ce5617SAnders Roxell
957b2ce5617SAnders Roxell /* enable interrupts */
958b2ce5617SAnders Roxell adv7511_set_isr(sd, true);
959b2ce5617SAnders Roxell
960b2ce5617SAnders Roxell if (handled)
961b2ce5617SAnders Roxell *handled = true;
962b2ce5617SAnders Roxell return 0;
963b2ce5617SAnders Roxell }
964b2ce5617SAnders Roxell
965b2ce5617SAnders Roxell static const struct v4l2_subdev_core_ops adv7511_core_ops = {
966b2ce5617SAnders Roxell .log_status = adv7511_log_status,
967b2ce5617SAnders Roxell #ifdef CONFIG_VIDEO_ADV_DEBUG
968b2ce5617SAnders Roxell .g_register = adv7511_g_register,
969b2ce5617SAnders Roxell .s_register = adv7511_s_register,
970b2ce5617SAnders Roxell #endif
971b2ce5617SAnders Roxell .s_power = adv7511_s_power,
972b2ce5617SAnders Roxell .interrupt_service_routine = adv7511_isr,
973b2ce5617SAnders Roxell };
974b2ce5617SAnders Roxell
975b2ce5617SAnders Roxell /* ------------------------------ VIDEO OPS ------------------------------ */
976b2ce5617SAnders Roxell
977b2ce5617SAnders Roxell /* Enable/disable adv7511 output */
adv7511_s_stream(struct v4l2_subdev * sd,int enable)978b2ce5617SAnders Roxell static int adv7511_s_stream(struct v4l2_subdev *sd, int enable)
979b2ce5617SAnders Roxell {
980b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
981b2ce5617SAnders Roxell
982b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
983b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c));
984b2ce5617SAnders Roxell if (enable) {
985b2ce5617SAnders Roxell adv7511_check_monitor_present_status(sd);
986b2ce5617SAnders Roxell } else {
987b2ce5617SAnders Roxell adv7511_s_power(sd, 0);
988b2ce5617SAnders Roxell state->have_monitor = false;
989b2ce5617SAnders Roxell }
990b2ce5617SAnders Roxell return 0;
991b2ce5617SAnders Roxell }
992b2ce5617SAnders Roxell
adv7511_s_dv_timings(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_dv_timings * timings)993259cadfaSPaweł Anikiel static int adv7511_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
994b2ce5617SAnders Roxell struct v4l2_dv_timings *timings)
995b2ce5617SAnders Roxell {
996b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
997b2ce5617SAnders Roxell struct v4l2_bt_timings *bt = &timings->bt;
998b2ce5617SAnders Roxell u32 fps;
999b2ce5617SAnders Roxell
1000b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1001b2ce5617SAnders Roxell
1002259cadfaSPaweł Anikiel if (pad != 0)
1003259cadfaSPaweł Anikiel return -EINVAL;
1004259cadfaSPaweł Anikiel
1005b2ce5617SAnders Roxell /* quick sanity check */
1006b2ce5617SAnders Roxell if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL))
1007b2ce5617SAnders Roxell return -EINVAL;
1008b2ce5617SAnders Roxell
1009b2ce5617SAnders Roxell /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
1010b2ce5617SAnders Roxell if the format is one of the CEA or DMT timings. */
1011b2ce5617SAnders Roxell v4l2_find_dv_timings_cap(timings, &adv7511_timings_cap, 0, NULL, NULL);
1012b2ce5617SAnders Roxell
1013b2ce5617SAnders Roxell /* save timings */
1014b2ce5617SAnders Roxell state->dv_timings = *timings;
1015b2ce5617SAnders Roxell
1016b2ce5617SAnders Roxell /* set h/vsync polarities */
1017b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x17, 0x9f,
1018b2ce5617SAnders Roxell ((bt->polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) |
1019b2ce5617SAnders Roxell ((bt->polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20));
1020b2ce5617SAnders Roxell
1021b2ce5617SAnders Roxell fps = (u32)bt->pixelclock / (V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt));
1022b2ce5617SAnders Roxell switch (fps) {
1023b2ce5617SAnders Roxell case 24:
1024b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xfb, 0xf9, 1 << 1);
1025b2ce5617SAnders Roxell break;
1026b2ce5617SAnders Roxell case 25:
1027b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xfb, 0xf9, 2 << 1);
1028b2ce5617SAnders Roxell break;
1029b2ce5617SAnders Roxell case 30:
1030b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xfb, 0xf9, 3 << 1);
1031b2ce5617SAnders Roxell break;
1032b2ce5617SAnders Roxell default:
1033b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xfb, 0xf9, 0);
1034b2ce5617SAnders Roxell break;
1035b2ce5617SAnders Roxell }
1036b2ce5617SAnders Roxell
1037b2ce5617SAnders Roxell /* update quantization range based on new dv_timings */
1038b2ce5617SAnders Roxell adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);
1039b2ce5617SAnders Roxell
1040b2ce5617SAnders Roxell return 0;
1041b2ce5617SAnders Roxell }
1042b2ce5617SAnders Roxell
adv7511_g_dv_timings(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_dv_timings * timings)1043259cadfaSPaweł Anikiel static int adv7511_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad,
1044b2ce5617SAnders Roxell struct v4l2_dv_timings *timings)
1045b2ce5617SAnders Roxell {
1046b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1047b2ce5617SAnders Roxell
1048b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1049b2ce5617SAnders Roxell
1050259cadfaSPaweł Anikiel if (pad != 0)
1051259cadfaSPaweł Anikiel return -EINVAL;
1052259cadfaSPaweł Anikiel
1053b2ce5617SAnders Roxell if (!timings)
1054b2ce5617SAnders Roxell return -EINVAL;
1055b2ce5617SAnders Roxell
1056b2ce5617SAnders Roxell *timings = state->dv_timings;
1057b2ce5617SAnders Roxell
1058b2ce5617SAnders Roxell return 0;
1059b2ce5617SAnders Roxell }
1060b2ce5617SAnders Roxell
adv7511_enum_dv_timings(struct v4l2_subdev * sd,struct v4l2_enum_dv_timings * timings)1061b2ce5617SAnders Roxell static int adv7511_enum_dv_timings(struct v4l2_subdev *sd,
1062b2ce5617SAnders Roxell struct v4l2_enum_dv_timings *timings)
1063b2ce5617SAnders Roxell {
1064b2ce5617SAnders Roxell if (timings->pad != 0)
1065b2ce5617SAnders Roxell return -EINVAL;
1066b2ce5617SAnders Roxell
1067b2ce5617SAnders Roxell return v4l2_enum_dv_timings_cap(timings, &adv7511_timings_cap, NULL, NULL);
1068b2ce5617SAnders Roxell }
1069b2ce5617SAnders Roxell
adv7511_dv_timings_cap(struct v4l2_subdev * sd,struct v4l2_dv_timings_cap * cap)1070b2ce5617SAnders Roxell static int adv7511_dv_timings_cap(struct v4l2_subdev *sd,
1071b2ce5617SAnders Roxell struct v4l2_dv_timings_cap *cap)
1072b2ce5617SAnders Roxell {
1073b2ce5617SAnders Roxell if (cap->pad != 0)
1074b2ce5617SAnders Roxell return -EINVAL;
1075b2ce5617SAnders Roxell
1076b2ce5617SAnders Roxell *cap = adv7511_timings_cap;
1077b2ce5617SAnders Roxell return 0;
1078b2ce5617SAnders Roxell }
1079b2ce5617SAnders Roxell
1080b2ce5617SAnders Roxell static const struct v4l2_subdev_video_ops adv7511_video_ops = {
1081b2ce5617SAnders Roxell .s_stream = adv7511_s_stream,
1082b2ce5617SAnders Roxell };
1083b2ce5617SAnders Roxell
1084b2ce5617SAnders Roxell /* ------------------------------ AUDIO OPS ------------------------------ */
adv7511_s_audio_stream(struct v4l2_subdev * sd,int enable)1085b2ce5617SAnders Roxell static int adv7511_s_audio_stream(struct v4l2_subdev *sd, int enable)
1086b2ce5617SAnders Roxell {
1087b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
1088b2ce5617SAnders Roxell
1089b2ce5617SAnders Roxell if (enable)
1090b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x80);
1091b2ce5617SAnders Roxell else
1092b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x40);
1093b2ce5617SAnders Roxell
1094b2ce5617SAnders Roxell return 0;
1095b2ce5617SAnders Roxell }
1096b2ce5617SAnders Roxell
adv7511_s_clock_freq(struct v4l2_subdev * sd,u32 freq)1097b2ce5617SAnders Roxell static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
1098b2ce5617SAnders Roxell {
1099b2ce5617SAnders Roxell u32 N;
1100b2ce5617SAnders Roxell
1101b2ce5617SAnders Roxell switch (freq) {
1102b2ce5617SAnders Roxell case 32000: N = 4096; break;
1103b2ce5617SAnders Roxell case 44100: N = 6272; break;
1104b2ce5617SAnders Roxell case 48000: N = 6144; break;
1105b2ce5617SAnders Roxell case 88200: N = 12544; break;
1106b2ce5617SAnders Roxell case 96000: N = 12288; break;
1107b2ce5617SAnders Roxell case 176400: N = 25088; break;
1108b2ce5617SAnders Roxell case 192000: N = 24576; break;
1109b2ce5617SAnders Roxell default:
1110b2ce5617SAnders Roxell return -EINVAL;
1111b2ce5617SAnders Roxell }
1112b2ce5617SAnders Roxell
1113b2ce5617SAnders Roxell /* Set N (used with CTS to regenerate the audio clock) */
1114b2ce5617SAnders Roxell adv7511_wr(sd, 0x01, (N >> 16) & 0xf);
1115b2ce5617SAnders Roxell adv7511_wr(sd, 0x02, (N >> 8) & 0xff);
1116b2ce5617SAnders Roxell adv7511_wr(sd, 0x03, N & 0xff);
1117b2ce5617SAnders Roxell
1118b2ce5617SAnders Roxell return 0;
1119b2ce5617SAnders Roxell }
1120b2ce5617SAnders Roxell
adv7511_s_i2s_clock_freq(struct v4l2_subdev * sd,u32 freq)1121b2ce5617SAnders Roxell static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
1122b2ce5617SAnders Roxell {
1123b2ce5617SAnders Roxell u32 i2s_sf;
1124b2ce5617SAnders Roxell
1125b2ce5617SAnders Roxell switch (freq) {
1126b2ce5617SAnders Roxell case 32000: i2s_sf = 0x30; break;
1127b2ce5617SAnders Roxell case 44100: i2s_sf = 0x00; break;
1128b2ce5617SAnders Roxell case 48000: i2s_sf = 0x20; break;
1129b2ce5617SAnders Roxell case 88200: i2s_sf = 0x80; break;
1130b2ce5617SAnders Roxell case 96000: i2s_sf = 0xa0; break;
1131b2ce5617SAnders Roxell case 176400: i2s_sf = 0xc0; break;
1132b2ce5617SAnders Roxell case 192000: i2s_sf = 0xe0; break;
1133b2ce5617SAnders Roxell default:
1134b2ce5617SAnders Roxell return -EINVAL;
1135b2ce5617SAnders Roxell }
1136b2ce5617SAnders Roxell
1137b2ce5617SAnders Roxell /* Set sampling frequency for I2S audio to 48 kHz */
1138b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x15, 0xf, i2s_sf);
1139b2ce5617SAnders Roxell
1140b2ce5617SAnders Roxell return 0;
1141b2ce5617SAnders Roxell }
1142b2ce5617SAnders Roxell
adv7511_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)1143b2ce5617SAnders Roxell static int adv7511_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config)
1144b2ce5617SAnders Roxell {
1145b2ce5617SAnders Roxell /* Only 2 channels in use for application */
1146b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x73, 0xf8, 0x1);
1147b2ce5617SAnders Roxell /* Speaker mapping */
1148b2ce5617SAnders Roxell adv7511_wr(sd, 0x76, 0x00);
1149b2ce5617SAnders Roxell
1150b2ce5617SAnders Roxell /* 16 bit audio word length */
1151b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x14, 0xf0, 0x02);
1152b2ce5617SAnders Roxell
1153b2ce5617SAnders Roxell return 0;
1154b2ce5617SAnders Roxell }
1155b2ce5617SAnders Roxell
1156b2ce5617SAnders Roxell static const struct v4l2_subdev_audio_ops adv7511_audio_ops = {
1157b2ce5617SAnders Roxell .s_stream = adv7511_s_audio_stream,
1158b2ce5617SAnders Roxell .s_clock_freq = adv7511_s_clock_freq,
1159b2ce5617SAnders Roxell .s_i2s_clock_freq = adv7511_s_i2s_clock_freq,
1160b2ce5617SAnders Roxell .s_routing = adv7511_s_routing,
1161b2ce5617SAnders Roxell };
1162b2ce5617SAnders Roxell
1163b2ce5617SAnders Roxell /* ---------------------------- PAD OPS ------------------------------------- */
1164b2ce5617SAnders Roxell
adv7511_get_edid(struct v4l2_subdev * sd,struct v4l2_edid * edid)1165b2ce5617SAnders Roxell static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
1166b2ce5617SAnders Roxell {
1167b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1168b2ce5617SAnders Roxell
1169b2ce5617SAnders Roxell memset(edid->reserved, 0, sizeof(edid->reserved));
1170b2ce5617SAnders Roxell
1171b2ce5617SAnders Roxell if (edid->pad != 0)
1172b2ce5617SAnders Roxell return -EINVAL;
1173b2ce5617SAnders Roxell
1174b2ce5617SAnders Roxell if (edid->start_block == 0 && edid->blocks == 0) {
1175b24bc3abSHans Verkuil edid->blocks = state->edid.blocks;
1176b2ce5617SAnders Roxell return 0;
1177b2ce5617SAnders Roxell }
1178b2ce5617SAnders Roxell
1179b24bc3abSHans Verkuil if (state->edid.blocks == 0)
1180b2ce5617SAnders Roxell return -ENODATA;
1181b2ce5617SAnders Roxell
1182b24bc3abSHans Verkuil if (edid->start_block >= state->edid.blocks)
1183b2ce5617SAnders Roxell return -EINVAL;
1184b2ce5617SAnders Roxell
1185b24bc3abSHans Verkuil if (edid->start_block + edid->blocks > state->edid.blocks)
1186b24bc3abSHans Verkuil edid->blocks = state->edid.blocks - edid->start_block;
1187b2ce5617SAnders Roxell
1188b2ce5617SAnders Roxell memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
1189b2ce5617SAnders Roxell 128 * edid->blocks);
1190b2ce5617SAnders Roxell
1191b2ce5617SAnders Roxell return 0;
1192b2ce5617SAnders Roxell }
1193b2ce5617SAnders Roxell
adv7511_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1194b2ce5617SAnders Roxell static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
11950d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1196b2ce5617SAnders Roxell struct v4l2_subdev_mbus_code_enum *code)
1197b2ce5617SAnders Roxell {
1198b2ce5617SAnders Roxell if (code->pad != 0)
1199b2ce5617SAnders Roxell return -EINVAL;
1200b2ce5617SAnders Roxell
1201b2ce5617SAnders Roxell switch (code->index) {
1202b2ce5617SAnders Roxell case 0:
1203b2ce5617SAnders Roxell code->code = MEDIA_BUS_FMT_RGB888_1X24;
1204b2ce5617SAnders Roxell break;
1205b2ce5617SAnders Roxell case 1:
1206b2ce5617SAnders Roxell code->code = MEDIA_BUS_FMT_YUYV8_1X16;
1207b2ce5617SAnders Roxell break;
1208b2ce5617SAnders Roxell case 2:
1209b2ce5617SAnders Roxell code->code = MEDIA_BUS_FMT_UYVY8_1X16;
1210b2ce5617SAnders Roxell break;
1211b2ce5617SAnders Roxell default:
1212b2ce5617SAnders Roxell return -EINVAL;
1213b2ce5617SAnders Roxell }
1214b2ce5617SAnders Roxell return 0;
1215b2ce5617SAnders Roxell }
1216b2ce5617SAnders Roxell
adv7511_fill_format(struct adv7511_state * state,struct v4l2_mbus_framefmt * format)1217b2ce5617SAnders Roxell static void adv7511_fill_format(struct adv7511_state *state,
1218b2ce5617SAnders Roxell struct v4l2_mbus_framefmt *format)
1219b2ce5617SAnders Roxell {
1220b2ce5617SAnders Roxell format->width = state->dv_timings.bt.width;
1221b2ce5617SAnders Roxell format->height = state->dv_timings.bt.height;
1222b2ce5617SAnders Roxell format->field = V4L2_FIELD_NONE;
1223b2ce5617SAnders Roxell }
1224b2ce5617SAnders Roxell
adv7511_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1225b2ce5617SAnders Roxell static int adv7511_get_fmt(struct v4l2_subdev *sd,
12260d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1227b2ce5617SAnders Roxell struct v4l2_subdev_format *format)
1228b2ce5617SAnders Roxell {
1229b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1230b2ce5617SAnders Roxell
1231b2ce5617SAnders Roxell if (format->pad != 0)
1232b2ce5617SAnders Roxell return -EINVAL;
1233b2ce5617SAnders Roxell
1234b2ce5617SAnders Roxell memset(&format->format, 0, sizeof(format->format));
1235b2ce5617SAnders Roxell adv7511_fill_format(state, &format->format);
1236b2ce5617SAnders Roxell
1237b2ce5617SAnders Roxell if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1238b2ce5617SAnders Roxell struct v4l2_mbus_framefmt *fmt;
1239b2ce5617SAnders Roxell
1240bc0e8d91SSakari Ailus fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
1241b2ce5617SAnders Roxell format->format.code = fmt->code;
1242b2ce5617SAnders Roxell format->format.colorspace = fmt->colorspace;
1243b2ce5617SAnders Roxell format->format.ycbcr_enc = fmt->ycbcr_enc;
1244b2ce5617SAnders Roxell format->format.quantization = fmt->quantization;
1245b2ce5617SAnders Roxell format->format.xfer_func = fmt->xfer_func;
1246b2ce5617SAnders Roxell } else {
1247b2ce5617SAnders Roxell format->format.code = state->fmt_code;
1248b2ce5617SAnders Roxell format->format.colorspace = state->colorspace;
1249b2ce5617SAnders Roxell format->format.ycbcr_enc = state->ycbcr_enc;
1250b2ce5617SAnders Roxell format->format.quantization = state->quantization;
1251b2ce5617SAnders Roxell format->format.xfer_func = state->xfer_func;
1252b2ce5617SAnders Roxell }
1253b2ce5617SAnders Roxell
1254b2ce5617SAnders Roxell return 0;
1255b2ce5617SAnders Roxell }
1256b2ce5617SAnders Roxell
adv7511_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1257b2ce5617SAnders Roxell static int adv7511_set_fmt(struct v4l2_subdev *sd,
12580d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
1259b2ce5617SAnders Roxell struct v4l2_subdev_format *format)
1260b2ce5617SAnders Roxell {
1261b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1262b2ce5617SAnders Roxell /*
1263b2ce5617SAnders Roxell * Bitfield namings come the CEA-861-F standard, table 8 "Auxiliary
1264b2ce5617SAnders Roxell * Video Information (AVI) InfoFrame Format"
1265b2ce5617SAnders Roxell *
1266b2ce5617SAnders Roxell * c = Colorimetry
1267b2ce5617SAnders Roxell * ec = Extended Colorimetry
1268b2ce5617SAnders Roxell * y = RGB or YCbCr
1269b2ce5617SAnders Roxell * q = RGB Quantization Range
1270b2ce5617SAnders Roxell * yq = YCC Quantization Range
1271b2ce5617SAnders Roxell */
1272b2ce5617SAnders Roxell u8 c = HDMI_COLORIMETRY_NONE;
1273b2ce5617SAnders Roxell u8 ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
1274b2ce5617SAnders Roxell u8 y = HDMI_COLORSPACE_RGB;
1275b2ce5617SAnders Roxell u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT;
1276b2ce5617SAnders Roxell u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
1277b2ce5617SAnders Roxell u8 itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC;
1278b2ce5617SAnders Roxell u8 cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS;
1279b2ce5617SAnders Roxell
1280b2ce5617SAnders Roxell if (format->pad != 0)
1281b2ce5617SAnders Roxell return -EINVAL;
1282b2ce5617SAnders Roxell switch (format->format.code) {
1283b2ce5617SAnders Roxell case MEDIA_BUS_FMT_UYVY8_1X16:
1284b2ce5617SAnders Roxell case MEDIA_BUS_FMT_YUYV8_1X16:
1285b2ce5617SAnders Roxell case MEDIA_BUS_FMT_RGB888_1X24:
1286b2ce5617SAnders Roxell break;
1287b2ce5617SAnders Roxell default:
1288b2ce5617SAnders Roxell return -EINVAL;
1289b2ce5617SAnders Roxell }
1290b2ce5617SAnders Roxell
1291b2ce5617SAnders Roxell adv7511_fill_format(state, &format->format);
1292b2ce5617SAnders Roxell if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1293b2ce5617SAnders Roxell struct v4l2_mbus_framefmt *fmt;
1294b2ce5617SAnders Roxell
1295bc0e8d91SSakari Ailus fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
1296b2ce5617SAnders Roxell fmt->code = format->format.code;
1297b2ce5617SAnders Roxell fmt->colorspace = format->format.colorspace;
1298b2ce5617SAnders Roxell fmt->ycbcr_enc = format->format.ycbcr_enc;
1299b2ce5617SAnders Roxell fmt->quantization = format->format.quantization;
1300b2ce5617SAnders Roxell fmt->xfer_func = format->format.xfer_func;
1301b2ce5617SAnders Roxell return 0;
1302b2ce5617SAnders Roxell }
1303b2ce5617SAnders Roxell
1304b2ce5617SAnders Roxell switch (format->format.code) {
1305b2ce5617SAnders Roxell case MEDIA_BUS_FMT_UYVY8_1X16:
1306b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01);
1307b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x16, 0x03, 0xb8);
1308b2ce5617SAnders Roxell y = HDMI_COLORSPACE_YUV422;
1309b2ce5617SAnders Roxell break;
1310b2ce5617SAnders Roxell case MEDIA_BUS_FMT_YUYV8_1X16:
1311b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01);
1312b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x16, 0x03, 0xbc);
1313b2ce5617SAnders Roxell y = HDMI_COLORSPACE_YUV422;
1314b2ce5617SAnders Roxell break;
1315b2ce5617SAnders Roxell case MEDIA_BUS_FMT_RGB888_1X24:
1316b2ce5617SAnders Roxell default:
1317b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x15, 0xf0, 0x00);
1318b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x16, 0x03, 0x00);
1319b2ce5617SAnders Roxell break;
1320b2ce5617SAnders Roxell }
1321b2ce5617SAnders Roxell state->fmt_code = format->format.code;
1322b2ce5617SAnders Roxell state->colorspace = format->format.colorspace;
1323b2ce5617SAnders Roxell state->ycbcr_enc = format->format.ycbcr_enc;
1324b2ce5617SAnders Roxell state->quantization = format->format.quantization;
1325b2ce5617SAnders Roxell state->xfer_func = format->format.xfer_func;
1326b2ce5617SAnders Roxell
1327b2ce5617SAnders Roxell switch (format->format.colorspace) {
1328b2ce5617SAnders Roxell case V4L2_COLORSPACE_OPRGB:
1329b2ce5617SAnders Roxell c = HDMI_COLORIMETRY_EXTENDED;
1330b2ce5617SAnders Roxell ec = y ? HDMI_EXTENDED_COLORIMETRY_OPYCC_601 :
1331b2ce5617SAnders Roxell HDMI_EXTENDED_COLORIMETRY_OPRGB;
1332b2ce5617SAnders Roxell break;
1333b2ce5617SAnders Roxell case V4L2_COLORSPACE_SMPTE170M:
1334b2ce5617SAnders Roxell c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE;
1335b2ce5617SAnders Roxell if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV601) {
1336b2ce5617SAnders Roxell c = HDMI_COLORIMETRY_EXTENDED;
1337b2ce5617SAnders Roxell ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
1338b2ce5617SAnders Roxell }
1339b2ce5617SAnders Roxell break;
1340b2ce5617SAnders Roxell case V4L2_COLORSPACE_REC709:
1341b2ce5617SAnders Roxell c = y ? HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_NONE;
1342b2ce5617SAnders Roxell if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
1343b2ce5617SAnders Roxell c = HDMI_COLORIMETRY_EXTENDED;
1344b2ce5617SAnders Roxell ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
1345b2ce5617SAnders Roxell }
1346b2ce5617SAnders Roxell break;
1347b2ce5617SAnders Roxell case V4L2_COLORSPACE_SRGB:
1348b2ce5617SAnders Roxell c = y ? HDMI_COLORIMETRY_EXTENDED : HDMI_COLORIMETRY_NONE;
1349b2ce5617SAnders Roxell ec = y ? HDMI_EXTENDED_COLORIMETRY_S_YCC_601 :
1350b2ce5617SAnders Roxell HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
1351b2ce5617SAnders Roxell break;
1352b2ce5617SAnders Roxell case V4L2_COLORSPACE_BT2020:
1353b2ce5617SAnders Roxell c = HDMI_COLORIMETRY_EXTENDED;
1354b2ce5617SAnders Roxell if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
1355b2ce5617SAnders Roxell ec = 5; /* Not yet available in hdmi.h */
1356b2ce5617SAnders Roxell else
1357b2ce5617SAnders Roxell ec = 6; /* Not yet available in hdmi.h */
1358b2ce5617SAnders Roxell break;
1359b2ce5617SAnders Roxell default:
1360b2ce5617SAnders Roxell break;
1361b2ce5617SAnders Roxell }
1362b2ce5617SAnders Roxell
1363b2ce5617SAnders Roxell /*
1364b2ce5617SAnders Roxell * CEA-861-F says that for RGB formats the YCC range must match the
1365b2ce5617SAnders Roxell * RGB range, although sources should ignore the YCC range.
1366b2ce5617SAnders Roxell *
1367b2ce5617SAnders Roxell * The RGB quantization range shouldn't be non-zero if the EDID doesn't
1368b2ce5617SAnders Roxell * have the Q bit set in the Video Capabilities Data Block, however this
1369b2ce5617SAnders Roxell * isn't checked at the moment. The assumption is that the application
1370b2ce5617SAnders Roxell * knows the EDID and can detect this.
1371b2ce5617SAnders Roxell *
1372b2ce5617SAnders Roxell * The same is true for the YCC quantization range: non-standard YCC
1373b2ce5617SAnders Roxell * quantization ranges should only be sent if the EDID has the YQ bit
1374b2ce5617SAnders Roxell * set in the Video Capabilities Data Block.
1375b2ce5617SAnders Roxell */
1376b2ce5617SAnders Roxell switch (format->format.quantization) {
1377b2ce5617SAnders Roxell case V4L2_QUANTIZATION_FULL_RANGE:
1378b2ce5617SAnders Roxell q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT :
1379b2ce5617SAnders Roxell HDMI_QUANTIZATION_RANGE_FULL;
1380b2ce5617SAnders Roxell yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_FULL;
1381b2ce5617SAnders Roxell break;
1382b2ce5617SAnders Roxell case V4L2_QUANTIZATION_LIM_RANGE:
1383b2ce5617SAnders Roxell q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT :
1384b2ce5617SAnders Roxell HDMI_QUANTIZATION_RANGE_LIMITED;
1385b2ce5617SAnders Roxell yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
1386b2ce5617SAnders Roxell break;
1387b2ce5617SAnders Roxell }
1388b2ce5617SAnders Roxell
1389b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x4a, 0xbf, 0);
1390b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5);
1391b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6);
1392b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7));
1393b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4));
1394b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
1395b2ce5617SAnders Roxell adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);
1396b2ce5617SAnders Roxell
1397b2ce5617SAnders Roxell return 0;
1398b2ce5617SAnders Roxell }
1399b2ce5617SAnders Roxell
1400b2ce5617SAnders Roxell static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
1401b2ce5617SAnders Roxell .get_edid = adv7511_get_edid,
1402b2ce5617SAnders Roxell .enum_mbus_code = adv7511_enum_mbus_code,
1403b2ce5617SAnders Roxell .get_fmt = adv7511_get_fmt,
1404b2ce5617SAnders Roxell .set_fmt = adv7511_set_fmt,
1405259cadfaSPaweł Anikiel .s_dv_timings = adv7511_s_dv_timings,
1406259cadfaSPaweł Anikiel .g_dv_timings = adv7511_g_dv_timings,
1407b2ce5617SAnders Roxell .enum_dv_timings = adv7511_enum_dv_timings,
1408b2ce5617SAnders Roxell .dv_timings_cap = adv7511_dv_timings_cap,
1409b2ce5617SAnders Roxell };
1410b2ce5617SAnders Roxell
1411b2ce5617SAnders Roxell /* --------------------- SUBDEV OPS --------------------------------------- */
1412b2ce5617SAnders Roxell
1413b2ce5617SAnders Roxell static const struct v4l2_subdev_ops adv7511_ops = {
1414b2ce5617SAnders Roxell .core = &adv7511_core_ops,
1415b2ce5617SAnders Roxell .pad = &adv7511_pad_ops,
1416b2ce5617SAnders Roxell .video = &adv7511_video_ops,
1417b2ce5617SAnders Roxell .audio = &adv7511_audio_ops,
1418b2ce5617SAnders Roxell };
1419b2ce5617SAnders Roxell
1420b2ce5617SAnders Roxell /* ----------------------------------------------------------------------- */
adv7511_dbg_dump_edid(int lvl,int debug,struct v4l2_subdev * sd,int segment,u8 * buf)1421b2ce5617SAnders Roxell static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, int segment, u8 *buf)
1422b2ce5617SAnders Roxell {
1423b2ce5617SAnders Roxell if (debug >= lvl) {
1424b2ce5617SAnders Roxell int i, j;
1425b2ce5617SAnders Roxell v4l2_dbg(lvl, debug, sd, "edid segment %d\n", segment);
1426b2ce5617SAnders Roxell for (i = 0; i < 256; i += 16) {
1427b2ce5617SAnders Roxell u8 b[128];
1428b2ce5617SAnders Roxell u8 *bp = b;
1429b2ce5617SAnders Roxell if (i == 128)
1430b2ce5617SAnders Roxell v4l2_dbg(lvl, debug, sd, "\n");
1431b2ce5617SAnders Roxell for (j = i; j < i + 16; j++) {
1432b2ce5617SAnders Roxell sprintf(bp, "0x%02x, ", buf[j]);
1433b2ce5617SAnders Roxell bp += 6;
1434b2ce5617SAnders Roxell }
1435b2ce5617SAnders Roxell bp[0] = '\0';
1436b2ce5617SAnders Roxell v4l2_dbg(lvl, debug, sd, "%s\n", b);
1437b2ce5617SAnders Roxell }
1438b2ce5617SAnders Roxell }
1439b2ce5617SAnders Roxell }
1440b2ce5617SAnders Roxell
adv7511_notify_no_edid(struct v4l2_subdev * sd)1441b2ce5617SAnders Roxell static void adv7511_notify_no_edid(struct v4l2_subdev *sd)
1442b2ce5617SAnders Roxell {
1443b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1444b2ce5617SAnders Roxell struct adv7511_edid_detect ed;
1445b2ce5617SAnders Roxell
1446b2ce5617SAnders Roxell /* We failed to read the EDID, so send an event for this. */
1447b2ce5617SAnders Roxell ed.present = false;
1448b2ce5617SAnders Roxell ed.segment = adv7511_rd(sd, 0xc4);
1449b2ce5617SAnders Roxell ed.phys_addr = CEC_PHYS_ADDR_INVALID;
1450b2ce5617SAnders Roxell cec_s_phys_addr(state->cec_adap, ed.phys_addr, false);
1451b2ce5617SAnders Roxell v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
1452b2ce5617SAnders Roxell v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0);
1453b2ce5617SAnders Roxell }
1454b2ce5617SAnders Roxell
adv7511_edid_handler(struct work_struct * work)1455b2ce5617SAnders Roxell static void adv7511_edid_handler(struct work_struct *work)
1456b2ce5617SAnders Roxell {
1457b2ce5617SAnders Roxell struct delayed_work *dwork = to_delayed_work(work);
1458b2ce5617SAnders Roxell struct adv7511_state *state = container_of(dwork, struct adv7511_state, edid_handler);
1459b2ce5617SAnders Roxell struct v4l2_subdev *sd = &state->sd;
1460b2ce5617SAnders Roxell
1461b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s:\n", __func__);
1462b2ce5617SAnders Roxell
1463b2ce5617SAnders Roxell if (adv7511_check_edid_status(sd)) {
1464b2ce5617SAnders Roxell /* Return if we received the EDID. */
1465b2ce5617SAnders Roxell return;
1466b2ce5617SAnders Roxell }
1467b2ce5617SAnders Roxell
1468b2ce5617SAnders Roxell if (adv7511_have_hotplug(sd)) {
1469b2ce5617SAnders Roxell /* We must retry reading the EDID several times, it is possible
1470b2ce5617SAnders Roxell * that initially the EDID couldn't be read due to i2c errors
1471b2ce5617SAnders Roxell * (DVI connectors are particularly prone to this problem). */
1472b2ce5617SAnders Roxell if (state->edid.read_retries) {
1473b2ce5617SAnders Roxell state->edid.read_retries--;
1474b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
1475b2ce5617SAnders Roxell state->have_monitor = false;
1476b2ce5617SAnders Roxell adv7511_s_power(sd, false);
1477b2ce5617SAnders Roxell adv7511_s_power(sd, true);
1478b2ce5617SAnders Roxell queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
1479b2ce5617SAnders Roxell return;
1480b2ce5617SAnders Roxell }
1481b2ce5617SAnders Roxell }
1482b2ce5617SAnders Roxell
1483b2ce5617SAnders Roxell /* We failed to read the EDID, so send an event for this. */
1484b2ce5617SAnders Roxell adv7511_notify_no_edid(sd);
1485b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__);
1486b2ce5617SAnders Roxell }
1487b2ce5617SAnders Roxell
adv7511_audio_setup(struct v4l2_subdev * sd)1488b2ce5617SAnders Roxell static void adv7511_audio_setup(struct v4l2_subdev *sd)
1489b2ce5617SAnders Roxell {
1490b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s\n", __func__);
1491b2ce5617SAnders Roxell
1492b2ce5617SAnders Roxell adv7511_s_i2s_clock_freq(sd, 48000);
1493b2ce5617SAnders Roxell adv7511_s_clock_freq(sd, 48000);
1494b2ce5617SAnders Roxell adv7511_s_routing(sd, 0, 0, 0);
1495b2ce5617SAnders Roxell }
1496b2ce5617SAnders Roxell
1497b2ce5617SAnders Roxell /* Configure hdmi transmitter. */
adv7511_setup(struct v4l2_subdev * sd)1498b2ce5617SAnders Roxell static void adv7511_setup(struct v4l2_subdev *sd)
1499b2ce5617SAnders Roxell {
1500b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1501b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s\n", __func__);
1502b2ce5617SAnders Roxell
1503b2ce5617SAnders Roxell /* Input format: RGB 4:4:4 */
1504b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x15, 0xf0, 0x0);
1505b2ce5617SAnders Roxell /* Output format: RGB 4:4:4 */
1506b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x16, 0x7f, 0x0);
1507b2ce5617SAnders Roxell /* 1st order interpolation 4:2:2 -> 4:4:4 up conversion, Aspect ratio: 16:9 */
1508b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x17, 0xf9, 0x06);
1509b2ce5617SAnders Roxell /* Disable pixel repetition */
1510b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x3b, 0x9f, 0x0);
1511b2ce5617SAnders Roxell /* Disable CSC */
1512b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0);
1513b2ce5617SAnders Roxell /* Output format: RGB 4:4:4, Active Format Information is valid,
1514b2ce5617SAnders Roxell * underscanned */
1515b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x55, 0x9c, 0x12);
1516b2ce5617SAnders Roxell /* AVI Info frame packet enable, Audio Info frame disable */
1517b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0x44, 0xe7, 0x10);
1518b2ce5617SAnders Roxell /* Colorimetry, Active format aspect ratio: same as picure. */
1519b2ce5617SAnders Roxell adv7511_wr(sd, 0x56, 0xa8);
1520b2ce5617SAnders Roxell /* No encryption */
1521b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xaf, 0xed, 0x0);
1522b2ce5617SAnders Roxell
1523b2ce5617SAnders Roxell /* Positive clk edge capture for input video clock */
1524b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xba, 0x1f, 0x60);
1525b2ce5617SAnders Roxell
1526b2ce5617SAnders Roxell adv7511_audio_setup(sd);
1527b2ce5617SAnders Roxell
1528b2ce5617SAnders Roxell v4l2_ctrl_handler_setup(&state->hdl);
1529b2ce5617SAnders Roxell }
1530b2ce5617SAnders Roxell
adv7511_notify_monitor_detect(struct v4l2_subdev * sd)1531b2ce5617SAnders Roxell static void adv7511_notify_monitor_detect(struct v4l2_subdev *sd)
1532b2ce5617SAnders Roxell {
1533b2ce5617SAnders Roxell struct adv7511_monitor_detect mdt;
1534b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1535b2ce5617SAnders Roxell
1536b2ce5617SAnders Roxell mdt.present = state->have_monitor;
1537b2ce5617SAnders Roxell v4l2_subdev_notify(sd, ADV7511_MONITOR_DETECT, (void *)&mdt);
1538b2ce5617SAnders Roxell }
1539b2ce5617SAnders Roxell
adv7511_check_monitor_present_status(struct v4l2_subdev * sd)1540b2ce5617SAnders Roxell static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
1541b2ce5617SAnders Roxell {
1542b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1543b2ce5617SAnders Roxell /* read hotplug and rx-sense state */
1544b2ce5617SAnders Roxell u8 status = adv7511_rd(sd, 0x42);
1545b2ce5617SAnders Roxell
1546b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n",
1547b2ce5617SAnders Roxell __func__,
1548b2ce5617SAnders Roxell status,
1549b2ce5617SAnders Roxell status & MASK_ADV7511_HPD_DETECT ? ", hotplug" : "",
1550b2ce5617SAnders Roxell status & MASK_ADV7511_MSEN_DETECT ? ", rx-sense" : "");
1551b2ce5617SAnders Roxell
1552b2ce5617SAnders Roxell /* update read only ctrls */
1553b2ce5617SAnders Roxell v4l2_ctrl_s_ctrl(state->hotplug_ctrl, adv7511_have_hotplug(sd) ? 0x1 : 0x0);
1554b2ce5617SAnders Roxell v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, adv7511_have_rx_sense(sd) ? 0x1 : 0x0);
1555b2ce5617SAnders Roxell
1556b2ce5617SAnders Roxell if ((status & MASK_ADV7511_HPD_DETECT) && ((status & MASK_ADV7511_MSEN_DETECT) || state->edid.segments)) {
1557b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: hotplug and (rx-sense or edid)\n", __func__);
1558b2ce5617SAnders Roxell if (!state->have_monitor) {
1559b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__);
1560b2ce5617SAnders Roxell state->have_monitor = true;
1561b2ce5617SAnders Roxell adv7511_set_isr(sd, true);
1562b2ce5617SAnders Roxell if (!adv7511_s_power(sd, true)) {
1563b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: monitor detected, powerup failed\n", __func__);
1564b2ce5617SAnders Roxell return;
1565b2ce5617SAnders Roxell }
1566b2ce5617SAnders Roxell adv7511_setup(sd);
1567b2ce5617SAnders Roxell adv7511_notify_monitor_detect(sd);
1568b2ce5617SAnders Roxell state->edid.read_retries = EDID_MAX_RETRIES;
1569b2ce5617SAnders Roxell queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
1570b2ce5617SAnders Roxell }
1571b2ce5617SAnders Roxell } else if (status & MASK_ADV7511_HPD_DETECT) {
1572b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__);
1573b2ce5617SAnders Roxell state->edid.read_retries = EDID_MAX_RETRIES;
1574b2ce5617SAnders Roxell queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
1575b2ce5617SAnders Roxell } else if (!(status & MASK_ADV7511_HPD_DETECT)) {
1576b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__);
1577b2ce5617SAnders Roxell if (state->have_monitor) {
1578b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__);
1579b2ce5617SAnders Roxell state->have_monitor = false;
1580b2ce5617SAnders Roxell adv7511_notify_monitor_detect(sd);
1581b2ce5617SAnders Roxell }
1582b2ce5617SAnders Roxell adv7511_s_power(sd, false);
1583b2ce5617SAnders Roxell memset(&state->edid, 0, sizeof(struct adv7511_state_edid));
1584b2ce5617SAnders Roxell adv7511_notify_no_edid(sd);
1585b2ce5617SAnders Roxell }
1586b2ce5617SAnders Roxell }
1587b2ce5617SAnders Roxell
edid_block_verify_crc(u8 * edid_block)1588b2ce5617SAnders Roxell static bool edid_block_verify_crc(u8 *edid_block)
1589b2ce5617SAnders Roxell {
1590b2ce5617SAnders Roxell u8 sum = 0;
1591b2ce5617SAnders Roxell int i;
1592b2ce5617SAnders Roxell
1593b2ce5617SAnders Roxell for (i = 0; i < 128; i++)
1594b2ce5617SAnders Roxell sum += edid_block[i];
1595b2ce5617SAnders Roxell return sum == 0;
1596b2ce5617SAnders Roxell }
1597b2ce5617SAnders Roxell
edid_verify_crc(struct v4l2_subdev * sd,u32 segment)1598b2ce5617SAnders Roxell static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
1599b2ce5617SAnders Roxell {
1600b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1601b2ce5617SAnders Roxell u32 blocks = state->edid.blocks;
1602b2ce5617SAnders Roxell u8 *data = state->edid.data;
1603b2ce5617SAnders Roxell
1604b2ce5617SAnders Roxell if (!edid_block_verify_crc(&data[segment * 256]))
1605b2ce5617SAnders Roxell return false;
1606b2ce5617SAnders Roxell if ((segment + 1) * 2 <= blocks)
1607b2ce5617SAnders Roxell return edid_block_verify_crc(&data[segment * 256 + 128]);
1608b2ce5617SAnders Roxell return true;
1609b2ce5617SAnders Roxell }
1610b2ce5617SAnders Roxell
edid_verify_header(struct v4l2_subdev * sd,u32 segment)1611b2ce5617SAnders Roxell static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
1612b2ce5617SAnders Roxell {
1613b2ce5617SAnders Roxell static const u8 hdmi_header[] = {
1614b2ce5617SAnders Roxell 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
1615b2ce5617SAnders Roxell };
1616b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1617b2ce5617SAnders Roxell u8 *data = state->edid.data;
1618b2ce5617SAnders Roxell
1619b2ce5617SAnders Roxell if (segment != 0)
1620b2ce5617SAnders Roxell return true;
1621b2ce5617SAnders Roxell return !memcmp(data, hdmi_header, sizeof(hdmi_header));
1622b2ce5617SAnders Roxell }
1623b2ce5617SAnders Roxell
adv7511_check_edid_status(struct v4l2_subdev * sd)1624b2ce5617SAnders Roxell static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
1625b2ce5617SAnders Roxell {
1626b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1627b2ce5617SAnders Roxell u8 edidRdy = adv7511_rd(sd, 0xc5);
1628b2ce5617SAnders Roxell
1629b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
1630b2ce5617SAnders Roxell __func__, EDID_MAX_RETRIES - state->edid.read_retries);
1631b2ce5617SAnders Roxell
1632b2ce5617SAnders Roxell if (state->edid.complete)
1633b2ce5617SAnders Roxell return true;
1634b2ce5617SAnders Roxell
1635b2ce5617SAnders Roxell if (edidRdy & MASK_ADV7511_EDID_RDY) {
1636b2ce5617SAnders Roxell int segment = adv7511_rd(sd, 0xc4);
1637b2ce5617SAnders Roxell struct adv7511_edid_detect ed;
1638eea62d6dSWolfram Sang int err;
1639b2ce5617SAnders Roxell
1640b2ce5617SAnders Roxell if (segment >= EDID_MAX_SEGM) {
1641b2ce5617SAnders Roxell v4l2_err(sd, "edid segment number too big\n");
1642b2ce5617SAnders Roxell return false;
1643b2ce5617SAnders Roxell }
1644b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment);
1645eea62d6dSWolfram Sang err = adv7511_edid_rd(sd, 256, &state->edid.data[segment * 256]);
1646eea62d6dSWolfram Sang if (!err) {
1647b2ce5617SAnders Roxell adv7511_dbg_dump_edid(2, debug, sd, segment, &state->edid.data[segment * 256]);
1648b2ce5617SAnders Roxell if (segment == 0) {
1649b2ce5617SAnders Roxell state->edid.blocks = state->edid.data[0x7e] + 1;
1650eea62d6dSWolfram Sang v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n",
1651eea62d6dSWolfram Sang __func__, state->edid.blocks);
1652b2ce5617SAnders Roxell }
1653eea62d6dSWolfram Sang }
1654eea62d6dSWolfram Sang
1655eea62d6dSWolfram Sang if (err || !edid_verify_crc(sd, segment) || !edid_verify_header(sd, segment)) {
1656eea62d6dSWolfram Sang /* Couldn't read EDID or EDID is invalid. Force retry! */
1657eea62d6dSWolfram Sang if (!err)
1658b2ce5617SAnders Roxell v4l2_err(sd, "%s: edid crc or header error\n", __func__);
1659b2ce5617SAnders Roxell state->have_monitor = false;
1660b2ce5617SAnders Roxell adv7511_s_power(sd, false);
1661b2ce5617SAnders Roxell adv7511_s_power(sd, true);
1662b2ce5617SAnders Roxell return false;
1663b2ce5617SAnders Roxell }
1664b2ce5617SAnders Roxell /* one more segment read ok */
1665b2ce5617SAnders Roxell state->edid.segments = segment + 1;
1666b2ce5617SAnders Roxell v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x1);
1667b2ce5617SAnders Roxell if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
1668b2ce5617SAnders Roxell /* Request next EDID segment */
1669b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: request segment %d\n", __func__, state->edid.segments);
1670b2ce5617SAnders Roxell adv7511_wr(sd, 0xc9, 0xf);
1671b2ce5617SAnders Roxell adv7511_wr(sd, 0xc4, state->edid.segments);
1672b2ce5617SAnders Roxell state->edid.read_retries = EDID_MAX_RETRIES;
1673b2ce5617SAnders Roxell queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY);
1674b2ce5617SAnders Roxell return false;
1675b2ce5617SAnders Roxell }
1676b2ce5617SAnders Roxell
1677b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments);
1678b2ce5617SAnders Roxell state->edid.complete = true;
1679b2ce5617SAnders Roxell ed.phys_addr = cec_get_edid_phys_addr(state->edid.data,
1680b2ce5617SAnders Roxell state->edid.segments * 256,
1681b2ce5617SAnders Roxell NULL);
1682b2ce5617SAnders Roxell /* report when we have all segments
1683b2ce5617SAnders Roxell but report only for segment 0
1684b2ce5617SAnders Roxell */
1685b2ce5617SAnders Roxell ed.present = true;
1686b2ce5617SAnders Roxell ed.segment = 0;
1687b2ce5617SAnders Roxell state->edid_detect_counter++;
1688b2ce5617SAnders Roxell cec_s_phys_addr(state->cec_adap, ed.phys_addr, false);
1689b2ce5617SAnders Roxell v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
1690b2ce5617SAnders Roxell return ed.present;
1691b2ce5617SAnders Roxell }
1692b2ce5617SAnders Roxell
1693b2ce5617SAnders Roxell return false;
1694b2ce5617SAnders Roxell }
1695b2ce5617SAnders Roxell
adv7511_registered(struct v4l2_subdev * sd)1696b2ce5617SAnders Roxell static int adv7511_registered(struct v4l2_subdev *sd)
1697b2ce5617SAnders Roxell {
1698b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1699b2ce5617SAnders Roxell struct i2c_client *client = v4l2_get_subdevdata(sd);
1700b2ce5617SAnders Roxell int err;
1701b2ce5617SAnders Roxell
1702b2ce5617SAnders Roxell err = cec_register_adapter(state->cec_adap, &client->dev);
1703b2ce5617SAnders Roxell if (err)
1704b2ce5617SAnders Roxell cec_delete_adapter(state->cec_adap);
1705b2ce5617SAnders Roxell return err;
1706b2ce5617SAnders Roxell }
1707b2ce5617SAnders Roxell
adv7511_unregistered(struct v4l2_subdev * sd)1708b2ce5617SAnders Roxell static void adv7511_unregistered(struct v4l2_subdev *sd)
1709b2ce5617SAnders Roxell {
1710b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1711b2ce5617SAnders Roxell
1712b2ce5617SAnders Roxell cec_unregister_adapter(state->cec_adap);
1713b2ce5617SAnders Roxell }
1714b2ce5617SAnders Roxell
1715b2ce5617SAnders Roxell static const struct v4l2_subdev_internal_ops adv7511_int_ops = {
1716b2ce5617SAnders Roxell .registered = adv7511_registered,
1717b2ce5617SAnders Roxell .unregistered = adv7511_unregistered,
1718b2ce5617SAnders Roxell };
1719b2ce5617SAnders Roxell
1720b2ce5617SAnders Roxell /* ----------------------------------------------------------------------- */
1721b2ce5617SAnders Roxell /* Setup ADV7511 */
adv7511_init_setup(struct v4l2_subdev * sd)1722b2ce5617SAnders Roxell static void adv7511_init_setup(struct v4l2_subdev *sd)
1723b2ce5617SAnders Roxell {
1724b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1725b2ce5617SAnders Roxell struct adv7511_state_edid *edid = &state->edid;
1726b2ce5617SAnders Roxell u32 cec_clk = state->pdata.cec_clk;
1727b2ce5617SAnders Roxell u8 ratio;
1728b2ce5617SAnders Roxell
1729b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s\n", __func__);
1730b2ce5617SAnders Roxell
1731b2ce5617SAnders Roxell /* clear all interrupts */
1732b2ce5617SAnders Roxell adv7511_wr(sd, 0x96, 0xff);
1733b2ce5617SAnders Roxell adv7511_wr(sd, 0x97, 0xff);
1734b2ce5617SAnders Roxell /*
1735b2ce5617SAnders Roxell * Stop HPD from resetting a lot of registers.
1736b2ce5617SAnders Roxell * It might leave the chip in a partly un-initialized state,
1737b2ce5617SAnders Roxell * in particular with regards to hotplug bounces.
1738b2ce5617SAnders Roxell */
1739b2ce5617SAnders Roxell adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0);
1740b2ce5617SAnders Roxell memset(edid, 0, sizeof(struct adv7511_state_edid));
1741b2ce5617SAnders Roxell state->have_monitor = false;
1742b2ce5617SAnders Roxell adv7511_set_isr(sd, false);
1743b2ce5617SAnders Roxell adv7511_s_stream(sd, false);
1744b2ce5617SAnders Roxell adv7511_s_audio_stream(sd, false);
1745b2ce5617SAnders Roxell
1746b2ce5617SAnders Roxell if (state->i2c_cec == NULL)
1747b2ce5617SAnders Roxell return;
1748b2ce5617SAnders Roxell
1749b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk);
1750b2ce5617SAnders Roxell
1751b2ce5617SAnders Roxell /* cec soft reset */
1752b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x50, 0x01);
1753b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x50, 0x00);
1754b2ce5617SAnders Roxell
1755b2ce5617SAnders Roxell /* legacy mode */
1756b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4a, 0x00);
1757b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4a, 0x07);
1758b2ce5617SAnders Roxell
1759b2ce5617SAnders Roxell if (cec_clk % 750000 != 0)
1760b2ce5617SAnders Roxell v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n",
1761b2ce5617SAnders Roxell __func__, cec_clk);
1762b2ce5617SAnders Roxell
1763b2ce5617SAnders Roxell ratio = (cec_clk / 750000) - 1;
1764b2ce5617SAnders Roxell adv7511_cec_write(sd, 0x4e, ratio << 2);
1765b2ce5617SAnders Roxell }
1766b2ce5617SAnders Roxell
adv7511_probe(struct i2c_client * client)176722d045d6SUwe Kleine-König static int adv7511_probe(struct i2c_client *client)
1768b2ce5617SAnders Roxell {
1769b2ce5617SAnders Roxell struct adv7511_state *state;
1770b2ce5617SAnders Roxell struct adv7511_platform_data *pdata = client->dev.platform_data;
1771b2ce5617SAnders Roxell struct v4l2_ctrl_handler *hdl;
1772b2ce5617SAnders Roxell struct v4l2_subdev *sd;
1773b2ce5617SAnders Roxell u8 chip_id[2];
1774b2ce5617SAnders Roxell int err = -EIO;
1775b2ce5617SAnders Roxell
1776b2ce5617SAnders Roxell /* Check if the adapter supports the needed features */
1777b2ce5617SAnders Roxell if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1778b2ce5617SAnders Roxell return -EIO;
1779b2ce5617SAnders Roxell
1780b2ce5617SAnders Roxell state = devm_kzalloc(&client->dev, sizeof(struct adv7511_state), GFP_KERNEL);
1781b2ce5617SAnders Roxell if (!state)
1782b2ce5617SAnders Roxell return -ENOMEM;
1783b2ce5617SAnders Roxell
1784b2ce5617SAnders Roxell /* Platform data */
1785b2ce5617SAnders Roxell if (!pdata) {
1786b2ce5617SAnders Roxell v4l_err(client, "No platform data!\n");
1787b2ce5617SAnders Roxell return -ENODEV;
1788b2ce5617SAnders Roxell }
1789b2ce5617SAnders Roxell memcpy(&state->pdata, pdata, sizeof(state->pdata));
1790b2ce5617SAnders Roxell state->fmt_code = MEDIA_BUS_FMT_RGB888_1X24;
1791b2ce5617SAnders Roxell state->colorspace = V4L2_COLORSPACE_SRGB;
1792b2ce5617SAnders Roxell
1793b2ce5617SAnders Roxell sd = &state->sd;
1794b2ce5617SAnders Roxell
1795b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "detecting adv7511 client on address 0x%x\n",
1796b2ce5617SAnders Roxell client->addr << 1);
1797b2ce5617SAnders Roxell
1798b2ce5617SAnders Roxell v4l2_i2c_subdev_init(sd, client, &adv7511_ops);
1799b2ce5617SAnders Roxell sd->internal_ops = &adv7511_int_ops;
1800b2ce5617SAnders Roxell
1801b2ce5617SAnders Roxell hdl = &state->hdl;
1802b2ce5617SAnders Roxell v4l2_ctrl_handler_init(hdl, 10);
1803b2ce5617SAnders Roxell /* add in ascending ID order */
1804b2ce5617SAnders Roxell state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
1805b2ce5617SAnders Roxell V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
1806b2ce5617SAnders Roxell 0, V4L2_DV_TX_MODE_DVI_D);
1807b2ce5617SAnders Roxell state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL,
1808b2ce5617SAnders Roxell V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0);
1809b2ce5617SAnders Roxell state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL,
1810b2ce5617SAnders Roxell V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0);
1811b2ce5617SAnders Roxell state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL,
1812b2ce5617SAnders Roxell V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0);
1813b2ce5617SAnders Roxell state->rgb_quantization_range_ctrl =
1814b2ce5617SAnders Roxell v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
1815b2ce5617SAnders Roxell V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
1816b2ce5617SAnders Roxell 0, V4L2_DV_RGB_RANGE_AUTO);
1817b2ce5617SAnders Roxell state->content_type_ctrl =
1818b2ce5617SAnders Roxell v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops,
1819b2ce5617SAnders Roxell V4L2_CID_DV_TX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC,
1820b2ce5617SAnders Roxell 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC);
1821b2ce5617SAnders Roxell sd->ctrl_handler = hdl;
1822b2ce5617SAnders Roxell if (hdl->error) {
1823b2ce5617SAnders Roxell err = hdl->error;
1824b2ce5617SAnders Roxell goto err_hdl;
1825b2ce5617SAnders Roxell }
1826b2ce5617SAnders Roxell state->pad.flags = MEDIA_PAD_FL_SINK;
1827b2ce5617SAnders Roxell sd->entity.function = MEDIA_ENT_F_DV_ENCODER;
1828b2ce5617SAnders Roxell err = media_entity_pads_init(&sd->entity, 1, &state->pad);
1829b2ce5617SAnders Roxell if (err)
1830b2ce5617SAnders Roxell goto err_hdl;
1831b2ce5617SAnders Roxell
1832b2ce5617SAnders Roxell /* EDID and CEC i2c addr */
1833b2ce5617SAnders Roxell state->i2c_edid_addr = state->pdata.i2c_edid << 1;
1834b2ce5617SAnders Roxell state->i2c_cec_addr = state->pdata.i2c_cec << 1;
1835b2ce5617SAnders Roxell state->i2c_pktmem_addr = state->pdata.i2c_pktmem << 1;
1836b2ce5617SAnders Roxell
1837b2ce5617SAnders Roxell state->chip_revision = adv7511_rd(sd, 0x0);
1838b2ce5617SAnders Roxell chip_id[0] = adv7511_rd(sd, 0xf5);
1839b2ce5617SAnders Roxell chip_id[1] = adv7511_rd(sd, 0xf6);
1840b2ce5617SAnders Roxell if (chip_id[0] != 0x75 || chip_id[1] != 0x11) {
1841b2ce5617SAnders Roxell v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0],
1842b2ce5617SAnders Roxell chip_id[1]);
1843b2ce5617SAnders Roxell err = -EIO;
1844b2ce5617SAnders Roxell goto err_entity;
1845b2ce5617SAnders Roxell }
1846b2ce5617SAnders Roxell
18479524da83SWolfram Sang state->i2c_edid = i2c_new_dummy_device(client->adapter,
1848b2ce5617SAnders Roxell state->i2c_edid_addr >> 1);
18499524da83SWolfram Sang if (IS_ERR(state->i2c_edid)) {
1850b2ce5617SAnders Roxell v4l2_err(sd, "failed to register edid i2c client\n");
18519524da83SWolfram Sang err = PTR_ERR(state->i2c_edid);
1852b2ce5617SAnders Roxell goto err_entity;
1853b2ce5617SAnders Roxell }
1854b2ce5617SAnders Roxell
1855b2ce5617SAnders Roxell adv7511_wr(sd, 0xe1, state->i2c_cec_addr);
1856b2ce5617SAnders Roxell if (state->pdata.cec_clk < 3000000 ||
1857b2ce5617SAnders Roxell state->pdata.cec_clk > 100000000) {
1858b2ce5617SAnders Roxell v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n",
1859b2ce5617SAnders Roxell __func__, state->pdata.cec_clk);
1860b2ce5617SAnders Roxell state->pdata.cec_clk = 0;
1861b2ce5617SAnders Roxell }
1862b2ce5617SAnders Roxell
1863b2ce5617SAnders Roxell if (state->pdata.cec_clk) {
18649524da83SWolfram Sang state->i2c_cec = i2c_new_dummy_device(client->adapter,
1865b2ce5617SAnders Roxell state->i2c_cec_addr >> 1);
18669524da83SWolfram Sang if (IS_ERR(state->i2c_cec)) {
1867b2ce5617SAnders Roxell v4l2_err(sd, "failed to register cec i2c client\n");
18689524da83SWolfram Sang err = PTR_ERR(state->i2c_cec);
1869b2ce5617SAnders Roxell goto err_unreg_edid;
1870b2ce5617SAnders Roxell }
1871b2ce5617SAnders Roxell adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */
1872b2ce5617SAnders Roxell } else {
1873b2ce5617SAnders Roxell adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */
1874b2ce5617SAnders Roxell }
1875b2ce5617SAnders Roxell
18769524da83SWolfram Sang state->i2c_pktmem = i2c_new_dummy_device(client->adapter, state->i2c_pktmem_addr >> 1);
18779524da83SWolfram Sang if (IS_ERR(state->i2c_pktmem)) {
1878b2ce5617SAnders Roxell v4l2_err(sd, "failed to register pktmem i2c client\n");
18799524da83SWolfram Sang err = PTR_ERR(state->i2c_pktmem);
1880b2ce5617SAnders Roxell goto err_unreg_cec;
1881b2ce5617SAnders Roxell }
1882b2ce5617SAnders Roxell
1883b2ce5617SAnders Roxell state->work_queue = create_singlethread_workqueue(sd->name);
1884b2ce5617SAnders Roxell if (state->work_queue == NULL) {
1885b2ce5617SAnders Roxell v4l2_err(sd, "could not create workqueue\n");
1886b2ce5617SAnders Roxell err = -ENOMEM;
1887b2ce5617SAnders Roxell goto err_unreg_pktmem;
1888b2ce5617SAnders Roxell }
1889b2ce5617SAnders Roxell
1890b2ce5617SAnders Roxell INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler);
1891b2ce5617SAnders Roxell
1892b2ce5617SAnders Roxell adv7511_init_setup(sd);
1893b2ce5617SAnders Roxell
1894b2ce5617SAnders Roxell #if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC)
1895b2ce5617SAnders Roxell state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
1896b2ce5617SAnders Roxell state, dev_name(&client->dev), CEC_CAP_DEFAULTS,
1897b2ce5617SAnders Roxell ADV7511_MAX_ADDRS);
1898b2ce5617SAnders Roxell err = PTR_ERR_OR_ZERO(state->cec_adap);
1899b2ce5617SAnders Roxell if (err) {
1900b2ce5617SAnders Roxell destroy_workqueue(state->work_queue);
1901b2ce5617SAnders Roxell goto err_unreg_pktmem;
1902b2ce5617SAnders Roxell }
1903b2ce5617SAnders Roxell #endif
1904b2ce5617SAnders Roxell
1905b2ce5617SAnders Roxell adv7511_set_isr(sd, true);
1906b2ce5617SAnders Roxell adv7511_check_monitor_present_status(sd);
1907b2ce5617SAnders Roxell
1908b2ce5617SAnders Roxell v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
1909b2ce5617SAnders Roxell client->addr << 1, client->adapter->name);
1910b2ce5617SAnders Roxell return 0;
1911b2ce5617SAnders Roxell
1912b2ce5617SAnders Roxell err_unreg_pktmem:
1913b2ce5617SAnders Roxell i2c_unregister_device(state->i2c_pktmem);
1914b2ce5617SAnders Roxell err_unreg_cec:
1915b2ce5617SAnders Roxell i2c_unregister_device(state->i2c_cec);
1916b2ce5617SAnders Roxell err_unreg_edid:
1917b2ce5617SAnders Roxell i2c_unregister_device(state->i2c_edid);
1918b2ce5617SAnders Roxell err_entity:
1919b2ce5617SAnders Roxell media_entity_cleanup(&sd->entity);
1920b2ce5617SAnders Roxell err_hdl:
1921b2ce5617SAnders Roxell v4l2_ctrl_handler_free(&state->hdl);
1922b2ce5617SAnders Roxell return err;
1923b2ce5617SAnders Roxell }
1924b2ce5617SAnders Roxell
1925b2ce5617SAnders Roxell /* ----------------------------------------------------------------------- */
1926b2ce5617SAnders Roxell
adv7511_remove(struct i2c_client * client)1927ed5c2f5fSUwe Kleine-König static void adv7511_remove(struct i2c_client *client)
1928b2ce5617SAnders Roxell {
1929b2ce5617SAnders Roxell struct v4l2_subdev *sd = i2c_get_clientdata(client);
1930b2ce5617SAnders Roxell struct adv7511_state *state = get_adv7511_state(sd);
1931b2ce5617SAnders Roxell
1932b2ce5617SAnders Roxell state->chip_revision = -1;
1933b2ce5617SAnders Roxell
1934b2ce5617SAnders Roxell v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,
1935b2ce5617SAnders Roxell client->addr << 1, client->adapter->name);
1936b2ce5617SAnders Roxell
1937b2ce5617SAnders Roxell adv7511_set_isr(sd, false);
1938b2ce5617SAnders Roxell adv7511_init_setup(sd);
19392c954172SYang Yingliang cancel_delayed_work_sync(&state->edid_handler);
1940b2ce5617SAnders Roxell i2c_unregister_device(state->i2c_edid);
1941b2ce5617SAnders Roxell i2c_unregister_device(state->i2c_cec);
1942b2ce5617SAnders Roxell i2c_unregister_device(state->i2c_pktmem);
1943b2ce5617SAnders Roxell destroy_workqueue(state->work_queue);
1944b2ce5617SAnders Roxell v4l2_device_unregister_subdev(sd);
1945b2ce5617SAnders Roxell media_entity_cleanup(&sd->entity);
1946b2ce5617SAnders Roxell v4l2_ctrl_handler_free(sd->ctrl_handler);
1947b2ce5617SAnders Roxell }
1948b2ce5617SAnders Roxell
1949b2ce5617SAnders Roxell /* ----------------------------------------------------------------------- */
1950b2ce5617SAnders Roxell
1951b2ce5617SAnders Roxell static const struct i2c_device_id adv7511_id[] = {
1952*cc4cbd4bSUwe Kleine-König { "adv7511-v4l2" },
1953b2ce5617SAnders Roxell { }
1954b2ce5617SAnders Roxell };
1955b2ce5617SAnders Roxell MODULE_DEVICE_TABLE(i2c, adv7511_id);
1956b2ce5617SAnders Roxell
1957b2ce5617SAnders Roxell static struct i2c_driver adv7511_driver = {
1958b2ce5617SAnders Roxell .driver = {
195925a3d6baSHans Verkuil .name = "adv7511-v4l2",
1960b2ce5617SAnders Roxell },
1961aaeb31c0SUwe Kleine-König .probe = adv7511_probe,
1962b2ce5617SAnders Roxell .remove = adv7511_remove,
1963b2ce5617SAnders Roxell .id_table = adv7511_id,
1964b2ce5617SAnders Roxell };
1965b2ce5617SAnders Roxell
1966b2ce5617SAnders Roxell module_i2c_driver(adv7511_driver);
1967