cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

chrontel-ch7033.c (15751B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Chrontel CH7033 Video Encoder Driver
      4 *
      5 * Copyright (C) 2019,2020 Lubomir Rintel
      6 */
      7
      8#include <linux/gpio/consumer.h>
      9#include <linux/module.h>
     10#include <linux/regmap.h>
     11
     12#include <drm/drm_atomic_helper.h>
     13#include <drm/drm_bridge.h>
     14#include <drm/drm_edid.h>
     15#include <drm/drm_of.h>
     16#include <drm/drm_print.h>
     17#include <drm/drm_probe_helper.h>
     18
     19/* Page 0, Register 0x07 */
     20enum {
     21	DRI_PD		= BIT(3),
     22	IO_PD		= BIT(5),
     23};
     24
     25/* Page 0, Register 0x08 */
     26enum {
     27	DRI_PDDRI	= GENMASK(7, 4),
     28	PDDAC		= GENMASK(3, 1),
     29	PANEN		= BIT(0),
     30};
     31
     32/* Page 0, Register 0x09 */
     33enum {
     34	DPD		= BIT(7),
     35	GCKOFF		= BIT(6),
     36	TV_BP		= BIT(5),
     37	SCLPD		= BIT(4),
     38	SDPD		= BIT(3),
     39	VGA_PD		= BIT(2),
     40	HDBKPD		= BIT(1),
     41	HDMI_PD		= BIT(0),
     42};
     43
     44/* Page 0, Register 0x0a */
     45enum {
     46	MEMINIT		= BIT(7),
     47	MEMIDLE		= BIT(6),
     48	MEMPD		= BIT(5),
     49	STOP		= BIT(4),
     50	LVDS_PD		= BIT(3),
     51	HD_DVIB		= BIT(2),
     52	HDCP_PD		= BIT(1),
     53	MCU_PD		= BIT(0),
     54};
     55
     56/* Page 0, Register 0x18 */
     57enum {
     58	IDF		= GENMASK(7, 4),
     59	INTEN		= BIT(3),
     60	SWAP		= GENMASK(2, 0),
     61};
     62
     63enum {
     64	BYTE_SWAP_RGB	= 0,
     65	BYTE_SWAP_RBG	= 1,
     66	BYTE_SWAP_GRB	= 2,
     67	BYTE_SWAP_GBR	= 3,
     68	BYTE_SWAP_BRG	= 4,
     69	BYTE_SWAP_BGR	= 5,
     70};
     71
     72/* Page 0, Register 0x19 */
     73enum {
     74	HPO_I		= BIT(5),
     75	VPO_I		= BIT(4),
     76	DEPO_I		= BIT(3),
     77	CRYS_EN		= BIT(2),
     78	GCLKFREQ	= GENMASK(2, 0),
     79};
     80
     81/* Page 0, Register 0x2e */
     82enum {
     83	HFLIP		= BIT(7),
     84	VFLIP		= BIT(6),
     85	DEPO_O		= BIT(5),
     86	HPO_O		= BIT(4),
     87	VPO_O		= BIT(3),
     88	TE		= GENMASK(2, 0),
     89};
     90
     91/* Page 0, Register 0x2b */
     92enum {
     93	SWAPS		= GENMASK(7, 4),
     94	VFMT		= GENMASK(3, 0),
     95};
     96
     97/* Page 0, Register 0x54 */
     98enum {
     99	COMP_BP		= BIT(7),
    100	DAC_EN_T	= BIT(6),
    101	HWO_HDMI_HI	= GENMASK(5, 3),
    102	HOO_HDMI_HI	= GENMASK(2, 0),
    103};
    104
    105/* Page 0, Register 0x57 */
    106enum {
    107	FLDSEN		= BIT(7),
    108	VWO_HDMI_HI	= GENMASK(5, 3),
    109	VOO_HDMI_HI	= GENMASK(2, 0),
    110};
    111
    112/* Page 0, Register 0x7e */
    113enum {
    114	HDMI_LVDS_SEL	= BIT(7),
    115	DE_GEN		= BIT(6),
    116	PWM_INDEX_HI	= BIT(5),
    117	USE_DE		= BIT(4),
    118	R_INT		= GENMASK(3, 0),
    119};
    120
    121/* Page 1, Register 0x07 */
    122enum {
    123	BPCKSEL		= BIT(7),
    124	DRI_CMFB_EN	= BIT(6),
    125	CEC_PUEN	= BIT(5),
    126	CEC_T		= BIT(3),
    127	CKINV		= BIT(2),
    128	CK_TVINV	= BIT(1),
    129	DRI_CKS2	= BIT(0),
    130};
    131
    132/* Page 1, Register 0x08 */
    133enum {
    134	DACG		= BIT(6),
    135	DACKTST		= BIT(5),
    136	DEDGEB		= BIT(4),
    137	SYO		= BIT(3),
    138	DRI_IT_LVDS	= GENMASK(2, 1),
    139	DISPON		= BIT(0),
    140};
    141
    142/* Page 1, Register 0x0c */
    143enum {
    144	DRI_PLL_CP	= GENMASK(7, 6),
    145	DRI_PLL_DIVSEL	= BIT(5),
    146	DRI_PLL_N1_1	= BIT(4),
    147	DRI_PLL_N1_0	= BIT(3),
    148	DRI_PLL_N3_1	= BIT(2),
    149	DRI_PLL_N3_0	= BIT(1),
    150	DRI_PLL_CKTSTEN = BIT(0),
    151};
    152
    153/* Page 1, Register 0x6b */
    154enum {
    155	VCO3CS		= GENMASK(7, 6),
    156	ICPGBK2_0	= GENMASK(5, 3),
    157	DRI_VCO357SC	= BIT(2),
    158	PDPLL2		= BIT(1),
    159	DRI_PD_SER	= BIT(0),
    160};
    161
    162/* Page 1, Register 0x6c */
    163enum {
    164	PLL2N11		= GENMASK(7, 4),
    165	PLL2N5_4	= BIT(3),
    166	PLL2N5_TOP	= BIT(2),
    167	DRI_PLL_PD	= BIT(1),
    168	PD_I2CM		= BIT(0),
    169};
    170
    171/* Page 3, Register 0x28 */
    172enum {
    173	DIFF_EN		= GENMASK(7, 6),
    174	CORREC_EN	= GENMASK(5, 4),
    175	VGACLK_BP	= BIT(3),
    176	HM_LV_SEL	= BIT(2),
    177	HD_VGA_SEL	= BIT(1),
    178};
    179
    180/* Page 3, Register 0x2a */
    181enum {
    182	LVDSCLK_BP	= BIT(7),
    183	HDTVCLK_BP	= BIT(6),
    184	HDMICLK_BP	= BIT(5),
    185	HDTV_BP		= BIT(4),
    186	HDMI_BP		= BIT(3),
    187	THRWL		= GENMASK(2, 0),
    188};
    189
    190/* Page 4, Register 0x52 */
    191enum {
    192	PGM_ARSTB	= BIT(7),
    193	MCU_ARSTB	= BIT(6),
    194	MCU_RETB	= BIT(2),
    195	RESETIB		= BIT(1),
    196	RESETDB		= BIT(0),
    197};
    198
    199struct ch7033_priv {
    200	struct regmap *regmap;
    201	struct drm_bridge *next_bridge;
    202	struct drm_bridge bridge;
    203	struct drm_connector connector;
    204};
    205
    206#define conn_to_ch7033_priv(x) \
    207	container_of(x, struct ch7033_priv, connector)
    208#define bridge_to_ch7033_priv(x) \
    209	container_of(x, struct ch7033_priv, bridge)
    210
    211
    212static enum drm_connector_status ch7033_connector_detect(
    213	struct drm_connector *connector, bool force)
    214{
    215	struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
    216
    217	return drm_bridge_detect(priv->next_bridge);
    218}
    219
    220static const struct drm_connector_funcs ch7033_connector_funcs = {
    221	.reset = drm_atomic_helper_connector_reset,
    222	.fill_modes = drm_helper_probe_single_connector_modes,
    223	.detect = ch7033_connector_detect,
    224	.destroy = drm_connector_cleanup,
    225	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
    226	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
    227};
    228
    229static int ch7033_connector_get_modes(struct drm_connector *connector)
    230{
    231	struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
    232	struct edid *edid;
    233	int ret;
    234
    235	edid = drm_bridge_get_edid(priv->next_bridge, connector);
    236	drm_connector_update_edid_property(connector, edid);
    237	if (edid) {
    238		ret = drm_add_edid_modes(connector, edid);
    239		kfree(edid);
    240	} else {
    241		ret = drm_add_modes_noedid(connector, 1920, 1080);
    242		drm_set_preferred_mode(connector, 1024, 768);
    243	}
    244
    245	return ret;
    246}
    247
    248static struct drm_encoder *ch7033_connector_best_encoder(
    249			struct drm_connector *connector)
    250{
    251	struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
    252
    253	return priv->bridge.encoder;
    254}
    255
    256static const struct drm_connector_helper_funcs ch7033_connector_helper_funcs = {
    257	.get_modes = ch7033_connector_get_modes,
    258	.best_encoder = ch7033_connector_best_encoder,
    259};
    260
    261static void ch7033_hpd_event(void *arg, enum drm_connector_status status)
    262{
    263	struct ch7033_priv *priv = arg;
    264
    265	if (priv->bridge.dev)
    266		drm_helper_hpd_irq_event(priv->connector.dev);
    267}
    268
    269static int ch7033_bridge_attach(struct drm_bridge *bridge,
    270				enum drm_bridge_attach_flags flags)
    271{
    272	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
    273	struct drm_connector *connector = &priv->connector;
    274	int ret;
    275
    276	ret = drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge,
    277				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
    278	if (ret)
    279		return ret;
    280
    281	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
    282		return 0;
    283
    284	if (priv->next_bridge->ops & DRM_BRIDGE_OP_DETECT) {
    285		connector->polled = DRM_CONNECTOR_POLL_HPD;
    286	} else {
    287		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
    288				    DRM_CONNECTOR_POLL_DISCONNECT;
    289	}
    290
    291	if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) {
    292		drm_bridge_hpd_enable(priv->next_bridge, ch7033_hpd_event,
    293				      priv);
    294	}
    295
    296	drm_connector_helper_add(connector,
    297				 &ch7033_connector_helper_funcs);
    298	ret = drm_connector_init_with_ddc(bridge->dev, &priv->connector,
    299					  &ch7033_connector_funcs,
    300					  priv->next_bridge->type,
    301					  priv->next_bridge->ddc);
    302	if (ret) {
    303		DRM_ERROR("Failed to initialize connector\n");
    304		return ret;
    305	}
    306
    307	return drm_connector_attach_encoder(&priv->connector, bridge->encoder);
    308}
    309
    310static void ch7033_bridge_detach(struct drm_bridge *bridge)
    311{
    312	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
    313
    314	if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD)
    315		drm_bridge_hpd_disable(priv->next_bridge);
    316	drm_connector_cleanup(&priv->connector);
    317}
    318
    319static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge,
    320				     const struct drm_display_info *info,
    321				     const struct drm_display_mode *mode)
    322{
    323	if (mode->clock > 165000)
    324		return MODE_CLOCK_HIGH;
    325	if (mode->hdisplay >= 1920)
    326		return MODE_BAD_HVALUE;
    327	if (mode->vdisplay >= 1080)
    328		return MODE_BAD_VVALUE;
    329	return MODE_OK;
    330}
    331
    332static void ch7033_bridge_disable(struct drm_bridge *bridge)
    333{
    334	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
    335
    336	regmap_write(priv->regmap, 0x03, 0x04);
    337	regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00);
    338}
    339
    340static void ch7033_bridge_enable(struct drm_bridge *bridge)
    341{
    342	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
    343
    344	regmap_write(priv->regmap, 0x03, 0x04);
    345	regmap_update_bits(priv->regmap, 0x52, RESETDB, RESETDB);
    346}
    347
    348static void ch7033_bridge_mode_set(struct drm_bridge *bridge,
    349				   const struct drm_display_mode *mode,
    350				   const struct drm_display_mode *adjusted_mode)
    351{
    352	struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
    353	int hbporch = mode->hsync_start - mode->hdisplay;
    354	int hsynclen = mode->hsync_end - mode->hsync_start;
    355	int vbporch = mode->vsync_start - mode->vdisplay;
    356	int vsynclen = mode->vsync_end - mode->vsync_start;
    357
    358	/*
    359	 * Page 4
    360	 */
    361	regmap_write(priv->regmap, 0x03, 0x04);
    362
    363	/* Turn everything off to set all the registers to their defaults. */
    364	regmap_write(priv->regmap, 0x52, 0x00);
    365	/* Bring I/O block up. */
    366	regmap_write(priv->regmap, 0x52, RESETIB);
    367
    368	/*
    369	 * Page 0
    370	 */
    371	regmap_write(priv->regmap, 0x03, 0x00);
    372
    373	/* Bring up parts we need from the power down. */
    374	regmap_update_bits(priv->regmap, 0x07, DRI_PD | IO_PD, 0);
    375	regmap_update_bits(priv->regmap, 0x08, DRI_PDDRI | PDDAC | PANEN, 0);
    376	regmap_update_bits(priv->regmap, 0x09, DPD | GCKOFF |
    377					       HDMI_PD | VGA_PD, 0);
    378	regmap_update_bits(priv->regmap, 0x0a, HD_DVIB, 0);
    379
    380	/* Horizontal input timing. */
    381	regmap_write(priv->regmap, 0x0b, (mode->htotal >> 8) << 3 |
    382					 (mode->hdisplay >> 8));
    383	regmap_write(priv->regmap, 0x0c, mode->hdisplay);
    384	regmap_write(priv->regmap, 0x0d, mode->htotal);
    385	regmap_write(priv->regmap, 0x0e, (hsynclen >> 8) << 3 |
    386					 (hbporch >> 8));
    387	regmap_write(priv->regmap, 0x0f, hbporch);
    388	regmap_write(priv->regmap, 0x10, hsynclen);
    389
    390	/* Vertical input timing. */
    391	regmap_write(priv->regmap, 0x11, (mode->vtotal >> 8) << 3 |
    392					 (mode->vdisplay >> 8));
    393	regmap_write(priv->regmap, 0x12, mode->vdisplay);
    394	regmap_write(priv->regmap, 0x13, mode->vtotal);
    395	regmap_write(priv->regmap, 0x14, ((vsynclen >> 8) << 3) |
    396					 (vbporch >> 8));
    397	regmap_write(priv->regmap, 0x15, vbporch);
    398	regmap_write(priv->regmap, 0x16, vsynclen);
    399
    400	/* Input color swap. */
    401	regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR);
    402
    403	/* Input clock and sync polarity. */
    404	regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16);
    405	regmap_update_bits(priv->regmap, 0x19, HPO_I | VPO_I | GCLKFREQ,
    406			   (mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_I : 0 |
    407			   (mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_I : 0 |
    408			   mode->clock >> 16);
    409	regmap_write(priv->regmap, 0x1a, mode->clock >> 8);
    410	regmap_write(priv->regmap, 0x1b, mode->clock);
    411
    412	/* Horizontal output timing. */
    413	regmap_write(priv->regmap, 0x1f, (mode->htotal >> 8) << 3 |
    414					 (mode->hdisplay >> 8));
    415	regmap_write(priv->regmap, 0x20, mode->hdisplay);
    416	regmap_write(priv->regmap, 0x21, mode->htotal);
    417
    418	/* Vertical output timing. */
    419	regmap_write(priv->regmap, 0x25, (mode->vtotal >> 8) << 3 |
    420					 (mode->vdisplay >> 8));
    421	regmap_write(priv->regmap, 0x26, mode->vdisplay);
    422	regmap_write(priv->regmap, 0x27, mode->vtotal);
    423
    424	/* VGA channel bypass */
    425	regmap_update_bits(priv->regmap, 0x2b, VFMT, 9);
    426
    427	/* Output sync polarity. */
    428	regmap_update_bits(priv->regmap, 0x2e, HPO_O | VPO_O,
    429			   (mode->flags & DRM_MODE_FLAG_PHSYNC) ? HPO_O : 0 |
    430			   (mode->flags & DRM_MODE_FLAG_PVSYNC) ? VPO_O : 0);
    431
    432	/* HDMI horizontal output timing. */
    433	regmap_update_bits(priv->regmap, 0x54, HWO_HDMI_HI | HOO_HDMI_HI,
    434					       (hsynclen >> 8) << 3 |
    435					       (hbporch >> 8));
    436	regmap_write(priv->regmap, 0x55, hbporch);
    437	regmap_write(priv->regmap, 0x56, hsynclen);
    438
    439	/* HDMI vertical output timing. */
    440	regmap_update_bits(priv->regmap, 0x57, VWO_HDMI_HI | VOO_HDMI_HI,
    441					       (vsynclen >> 8) << 3 |
    442					       (vbporch >> 8));
    443	regmap_write(priv->regmap, 0x58, vbporch);
    444	regmap_write(priv->regmap, 0x59, vsynclen);
    445
    446	/* Pick HDMI, not LVDS. */
    447	regmap_update_bits(priv->regmap, 0x7e, HDMI_LVDS_SEL, HDMI_LVDS_SEL);
    448
    449	/*
    450	 * Page 1
    451	 */
    452	regmap_write(priv->regmap, 0x03, 0x01);
    453
    454	/* No idea what these do, but VGA is wobbly and blinky without them. */
    455	regmap_update_bits(priv->regmap, 0x07, CKINV, CKINV);
    456	regmap_update_bits(priv->regmap, 0x08, DISPON, DISPON);
    457
    458	/* DRI PLL */
    459	regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_DIVSEL, DRI_PLL_DIVSEL);
    460	if (mode->clock <= 40000) {
    461		regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
    462						       DRI_PLL_N1_0 |
    463						       DRI_PLL_N3_1 |
    464						       DRI_PLL_N3_0,
    465						       0);
    466	} else if (mode->clock < 80000) {
    467		regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
    468						       DRI_PLL_N1_0 |
    469						       DRI_PLL_N3_1 |
    470						       DRI_PLL_N3_0,
    471						       DRI_PLL_N3_0 |
    472						       DRI_PLL_N1_0);
    473	} else {
    474		regmap_update_bits(priv->regmap, 0x0c, DRI_PLL_N1_1 |
    475						       DRI_PLL_N1_0 |
    476						       DRI_PLL_N3_1 |
    477						       DRI_PLL_N3_0,
    478						       DRI_PLL_N3_1 |
    479						       DRI_PLL_N1_1);
    480	}
    481
    482	/* This seems to be color calibration for VGA. */
    483	regmap_write(priv->regmap, 0x64, 0x29); /* LSB Blue */
    484	regmap_write(priv->regmap, 0x65, 0x29); /* LSB Green */
    485	regmap_write(priv->regmap, 0x66, 0x29); /* LSB Red */
    486	regmap_write(priv->regmap, 0x67, 0x00); /* MSB Blue */
    487	regmap_write(priv->regmap, 0x68, 0x00); /* MSB Green */
    488	regmap_write(priv->regmap, 0x69, 0x00); /* MSB Red */
    489
    490	regmap_update_bits(priv->regmap, 0x6b, DRI_PD_SER, 0x00);
    491	regmap_update_bits(priv->regmap, 0x6c, DRI_PLL_PD, 0x00);
    492
    493	/*
    494	 * Page 3
    495	 */
    496	regmap_write(priv->regmap, 0x03, 0x03);
    497
    498	/* More bypasses and apparently another HDMI/LVDS selector. */
    499	regmap_update_bits(priv->regmap, 0x28, VGACLK_BP | HM_LV_SEL,
    500					       VGACLK_BP | HM_LV_SEL);
    501	regmap_update_bits(priv->regmap, 0x2a, HDMICLK_BP | HDMI_BP,
    502					       HDMICLK_BP | HDMI_BP);
    503
    504	/*
    505	 * Page 4
    506	 */
    507	regmap_write(priv->regmap, 0x03, 0x04);
    508
    509	/* Output clock. */
    510	regmap_write(priv->regmap, 0x10, mode->clock >> 16);
    511	regmap_write(priv->regmap, 0x11, mode->clock >> 8);
    512	regmap_write(priv->regmap, 0x12, mode->clock);
    513}
    514
    515static const struct drm_bridge_funcs ch7033_bridge_funcs = {
    516	.attach = ch7033_bridge_attach,
    517	.detach = ch7033_bridge_detach,
    518	.mode_valid = ch7033_bridge_mode_valid,
    519	.disable = ch7033_bridge_disable,
    520	.enable = ch7033_bridge_enable,
    521	.mode_set = ch7033_bridge_mode_set,
    522};
    523
    524static const struct regmap_config ch7033_regmap_config = {
    525	.reg_bits = 8,
    526	.val_bits = 8,
    527	.max_register = 0x7f,
    528};
    529
    530static int ch7033_probe(struct i2c_client *client,
    531			const struct i2c_device_id *id)
    532{
    533	struct device *dev = &client->dev;
    534	struct ch7033_priv *priv;
    535	unsigned int val;
    536	int ret;
    537
    538	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    539	if (!priv)
    540		return -ENOMEM;
    541
    542	dev_set_drvdata(dev, priv);
    543
    544	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
    545					  &priv->next_bridge);
    546	if (ret)
    547		return ret;
    548
    549	priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config);
    550	if (IS_ERR(priv->regmap)) {
    551		dev_err(&client->dev, "regmap init failed\n");
    552		return PTR_ERR(priv->regmap);
    553	}
    554
    555	ret = regmap_read(priv->regmap, 0x00, &val);
    556	if (ret < 0) {
    557		dev_err(&client->dev, "error reading the model id: %d\n", ret);
    558		return ret;
    559	}
    560	if ((val & 0xf7) != 0x56) {
    561		dev_err(&client->dev, "the device is not a ch7033\n");
    562		return -ENODEV;
    563	}
    564
    565	regmap_write(priv->regmap, 0x03, 0x04);
    566	ret = regmap_read(priv->regmap, 0x51, &val);
    567	if (ret < 0) {
    568		dev_err(&client->dev, "error reading the model id: %d\n", ret);
    569		return ret;
    570	}
    571	if ((val & 0x0f) != 3) {
    572		dev_err(&client->dev, "unknown revision %u\n", val);
    573		return -ENODEV;
    574	}
    575
    576	INIT_LIST_HEAD(&priv->bridge.list);
    577	priv->bridge.funcs = &ch7033_bridge_funcs;
    578	priv->bridge.of_node = dev->of_node;
    579	drm_bridge_add(&priv->bridge);
    580
    581	dev_info(dev, "Chrontel CH7033 Video Encoder\n");
    582	return 0;
    583}
    584
    585static int ch7033_remove(struct i2c_client *client)
    586{
    587	struct device *dev = &client->dev;
    588	struct ch7033_priv *priv = dev_get_drvdata(dev);
    589
    590	drm_bridge_remove(&priv->bridge);
    591
    592	return 0;
    593}
    594
    595static const struct of_device_id ch7033_dt_ids[] = {
    596	{ .compatible = "chrontel,ch7033", },
    597	{ }
    598};
    599MODULE_DEVICE_TABLE(of, ch7033_dt_ids);
    600
    601static const struct i2c_device_id ch7033_ids[] = {
    602	{ "ch7033", 0 },
    603	{ }
    604};
    605MODULE_DEVICE_TABLE(i2c, ch7033_ids);
    606
    607static struct i2c_driver ch7033_driver = {
    608	.probe = ch7033_probe,
    609	.remove = ch7033_remove,
    610	.driver = {
    611		.name = "ch7033",
    612		.of_match_table = of_match_ptr(ch7033_dt_ids),
    613	},
    614	.id_table = ch7033_ids,
    615};
    616
    617module_i2c_driver(ch7033_driver);
    618
    619MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
    620MODULE_DESCRIPTION("Chrontel CH7033 Video Encoder Driver");
    621MODULE_LICENSE("GPL v2");