1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/mfd/syscon.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/phy/phy.h> 11 #include <linux/regmap.h> 12 13 #include <drm/bridge/dw_hdmi.h> 14 #include <drm/drm_edid.h> 15 #include <drm/drm_of.h> 16 #include <drm/drm_probe_helper.h> 17 18 #include "rockchip_drm_drv.h" 19 #include "rockchip_drm_vop.h" 20 21 #define RK3228_GRF_SOC_CON2 0x0408 22 #define RK3228_HDMI_SDAIN_MSK BIT(14) 23 #define RK3228_HDMI_SCLIN_MSK BIT(13) 24 #define RK3228_GRF_SOC_CON6 0x0418 25 #define RK3228_HDMI_HPD_VSEL BIT(6) 26 #define RK3228_HDMI_SDA_VSEL BIT(5) 27 #define RK3228_HDMI_SCL_VSEL BIT(4) 28 29 #define RK3288_GRF_SOC_CON6 0x025C 30 #define RK3288_HDMI_LCDC_SEL BIT(4) 31 #define RK3328_GRF_SOC_CON2 0x0408 32 33 #define RK3328_HDMI_SDAIN_MSK BIT(11) 34 #define RK3328_HDMI_SCLIN_MSK BIT(10) 35 #define RK3328_HDMI_HPD_IOE BIT(2) 36 #define RK3328_GRF_SOC_CON3 0x040c 37 /* need to be unset if hdmi or i2c should control voltage */ 38 #define RK3328_HDMI_SDA5V_GRF BIT(15) 39 #define RK3328_HDMI_SCL5V_GRF BIT(14) 40 #define RK3328_HDMI_HPD5V_GRF BIT(13) 41 #define RK3328_HDMI_CEC5V_GRF BIT(12) 42 #define RK3328_GRF_SOC_CON4 0x0410 43 #define RK3328_HDMI_HPD_SARADC BIT(13) 44 #define RK3328_HDMI_CEC_5V BIT(11) 45 #define RK3328_HDMI_SDA_5V BIT(10) 46 #define RK3328_HDMI_SCL_5V BIT(9) 47 #define RK3328_HDMI_HPD_5V BIT(8) 48 49 #define RK3399_GRF_SOC_CON20 0x6250 50 #define RK3399_HDMI_LCDC_SEL BIT(6) 51 52 #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) 53 54 /** 55 * struct rockchip_hdmi_chip_data - splite the grf setting of kind of chips 56 * @lcdsel_grf_reg: grf register offset of lcdc select 57 * @lcdsel_big: reg value of selecting vop big for HDMI 58 * @lcdsel_lit: reg value of selecting vop little for HDMI 59 */ 60 struct rockchip_hdmi_chip_data { 61 int lcdsel_grf_reg; 62 u32 lcdsel_big; 63 u32 lcdsel_lit; 64 }; 65 66 struct rockchip_hdmi { 67 struct device *dev; 68 struct regmap *regmap; 69 struct drm_encoder encoder; 70 const struct rockchip_hdmi_chip_data *chip_data; 71 struct clk *vpll_clk; 72 struct clk *grf_clk; 73 struct dw_hdmi *hdmi; 74 struct phy *phy; 75 }; 76 77 #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) 78 79 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { 80 { 81 27000000, { 82 { 0x00b3, 0x0000}, 83 { 0x2153, 0x0000}, 84 { 0x40f3, 0x0000} 85 }, 86 }, { 87 36000000, { 88 { 0x00b3, 0x0000}, 89 { 0x2153, 0x0000}, 90 { 0x40f3, 0x0000} 91 }, 92 }, { 93 40000000, { 94 { 0x00b3, 0x0000}, 95 { 0x2153, 0x0000}, 96 { 0x40f3, 0x0000} 97 }, 98 }, { 99 54000000, { 100 { 0x0072, 0x0001}, 101 { 0x2142, 0x0001}, 102 { 0x40a2, 0x0001}, 103 }, 104 }, { 105 65000000, { 106 { 0x0072, 0x0001}, 107 { 0x2142, 0x0001}, 108 { 0x40a2, 0x0001}, 109 }, 110 }, { 111 66000000, { 112 { 0x013e, 0x0003}, 113 { 0x217e, 0x0002}, 114 { 0x4061, 0x0002} 115 }, 116 }, { 117 74250000, { 118 { 0x0072, 0x0001}, 119 { 0x2145, 0x0002}, 120 { 0x4061, 0x0002} 121 }, 122 }, { 123 83500000, { 124 { 0x0072, 0x0001}, 125 }, 126 }, { 127 108000000, { 128 { 0x0051, 0x0002}, 129 { 0x2145, 0x0002}, 130 { 0x4061, 0x0002} 131 }, 132 }, { 133 106500000, { 134 { 0x0051, 0x0002}, 135 { 0x2145, 0x0002}, 136 { 0x4061, 0x0002} 137 }, 138 }, { 139 146250000, { 140 { 0x0051, 0x0002}, 141 { 0x2145, 0x0002}, 142 { 0x4061, 0x0002} 143 }, 144 }, { 145 148500000, { 146 { 0x0051, 0x0003}, 147 { 0x214c, 0x0003}, 148 { 0x4064, 0x0003} 149 }, 150 }, { 151 ~0UL, { 152 { 0x00a0, 0x000a }, 153 { 0x2001, 0x000f }, 154 { 0x4002, 0x000f }, 155 }, 156 } 157 }; 158 159 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { 160 /* pixelclk bpp8 bpp10 bpp12 */ 161 { 162 40000000, { 0x0018, 0x0018, 0x0018 }, 163 }, { 164 65000000, { 0x0028, 0x0028, 0x0028 }, 165 }, { 166 66000000, { 0x0038, 0x0038, 0x0038 }, 167 }, { 168 74250000, { 0x0028, 0x0038, 0x0038 }, 169 }, { 170 83500000, { 0x0028, 0x0038, 0x0038 }, 171 }, { 172 146250000, { 0x0038, 0x0038, 0x0038 }, 173 }, { 174 148500000, { 0x0000, 0x0038, 0x0038 }, 175 }, { 176 ~0UL, { 0x0000, 0x0000, 0x0000}, 177 } 178 }; 179 180 static const struct dw_hdmi_phy_config rockchip_phy_config[] = { 181 /*pixelclk symbol term vlev*/ 182 { 74250000, 0x8009, 0x0004, 0x0272}, 183 { 148500000, 0x802b, 0x0004, 0x028d}, 184 { 297000000, 0x8039, 0x0005, 0x028d}, 185 { ~0UL, 0x0000, 0x0000, 0x0000} 186 }; 187 188 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) 189 { 190 struct device_node *np = hdmi->dev->of_node; 191 192 hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 193 if (IS_ERR(hdmi->regmap)) { 194 DRM_DEV_ERROR(hdmi->dev, "Unable to get rockchip,grf\n"); 195 return PTR_ERR(hdmi->regmap); 196 } 197 198 hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll"); 199 if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) { 200 hdmi->vpll_clk = NULL; 201 } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { 202 return -EPROBE_DEFER; 203 } else if (IS_ERR(hdmi->vpll_clk)) { 204 DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); 205 return PTR_ERR(hdmi->vpll_clk); 206 } 207 208 hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf"); 209 if (PTR_ERR(hdmi->grf_clk) == -ENOENT) { 210 hdmi->grf_clk = NULL; 211 } else if (PTR_ERR(hdmi->grf_clk) == -EPROBE_DEFER) { 212 return -EPROBE_DEFER; 213 } else if (IS_ERR(hdmi->grf_clk)) { 214 DRM_DEV_ERROR(hdmi->dev, "failed to get grf clock\n"); 215 return PTR_ERR(hdmi->grf_clk); 216 } 217 218 return 0; 219 } 220 221 static enum drm_mode_status 222 dw_hdmi_rockchip_mode_valid(struct drm_connector *connector, 223 const struct drm_display_mode *mode) 224 { 225 const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; 226 int pclk = mode->clock * 1000; 227 bool valid = false; 228 int i; 229 230 for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { 231 if (pclk == mpll_cfg[i].mpixelclock) { 232 valid = true; 233 break; 234 } 235 } 236 237 return (valid) ? MODE_OK : MODE_BAD; 238 } 239 240 static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = { 241 .destroy = drm_encoder_cleanup, 242 }; 243 244 static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) 245 { 246 } 247 248 static bool 249 dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, 250 const struct drm_display_mode *mode, 251 struct drm_display_mode *adj_mode) 252 { 253 return true; 254 } 255 256 static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, 257 struct drm_display_mode *mode, 258 struct drm_display_mode *adj_mode) 259 { 260 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); 261 262 clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); 263 } 264 265 static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) 266 { 267 struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); 268 u32 val; 269 int ret; 270 271 if (hdmi->chip_data->lcdsel_grf_reg < 0) 272 return; 273 274 ret = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); 275 if (ret) 276 val = hdmi->chip_data->lcdsel_lit; 277 else 278 val = hdmi->chip_data->lcdsel_big; 279 280 ret = clk_prepare_enable(hdmi->grf_clk); 281 if (ret < 0) { 282 DRM_DEV_ERROR(hdmi->dev, "failed to enable grfclk %d\n", ret); 283 return; 284 } 285 286 ret = regmap_write(hdmi->regmap, hdmi->chip_data->lcdsel_grf_reg, val); 287 if (ret != 0) 288 DRM_DEV_ERROR(hdmi->dev, "Could not write to GRF: %d\n", ret); 289 290 clk_disable_unprepare(hdmi->grf_clk); 291 DRM_DEV_DEBUG(hdmi->dev, "vop %s output to hdmi\n", 292 ret ? "LIT" : "BIG"); 293 } 294 295 static int 296 dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, 297 struct drm_crtc_state *crtc_state, 298 struct drm_connector_state *conn_state) 299 { 300 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 301 302 s->output_mode = ROCKCHIP_OUT_MODE_AAAA; 303 s->output_type = DRM_MODE_CONNECTOR_HDMIA; 304 305 return 0; 306 } 307 308 static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { 309 .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, 310 .mode_set = dw_hdmi_rockchip_encoder_mode_set, 311 .enable = dw_hdmi_rockchip_encoder_enable, 312 .disable = dw_hdmi_rockchip_encoder_disable, 313 .atomic_check = dw_hdmi_rockchip_encoder_atomic_check, 314 }; 315 316 static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data, 317 struct drm_display_mode *mode) 318 { 319 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 320 321 return phy_power_on(hdmi->phy); 322 } 323 324 static void dw_hdmi_rockchip_genphy_disable(struct dw_hdmi *dw_hdmi, void *data) 325 { 326 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 327 328 phy_power_off(hdmi->phy); 329 } 330 331 static void dw_hdmi_rk3228_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) 332 { 333 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 334 335 dw_hdmi_phy_setup_hpd(dw_hdmi, data); 336 337 regmap_write(hdmi->regmap, 338 RK3228_GRF_SOC_CON6, 339 HIWORD_UPDATE(RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL | 340 RK3228_HDMI_SCL_VSEL, 341 RK3228_HDMI_HPD_VSEL | RK3228_HDMI_SDA_VSEL | 342 RK3228_HDMI_SCL_VSEL)); 343 344 regmap_write(hdmi->regmap, 345 RK3228_GRF_SOC_CON2, 346 HIWORD_UPDATE(RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK, 347 RK3228_HDMI_SDAIN_MSK | RK3228_HDMI_SCLIN_MSK)); 348 } 349 350 static enum drm_connector_status 351 dw_hdmi_rk3328_read_hpd(struct dw_hdmi *dw_hdmi, void *data) 352 { 353 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 354 enum drm_connector_status status; 355 356 status = dw_hdmi_phy_read_hpd(dw_hdmi, data); 357 358 if (status == connector_status_connected) 359 regmap_write(hdmi->regmap, 360 RK3328_GRF_SOC_CON4, 361 HIWORD_UPDATE(RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V, 362 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V)); 363 else 364 regmap_write(hdmi->regmap, 365 RK3328_GRF_SOC_CON4, 366 HIWORD_UPDATE(0, RK3328_HDMI_SDA_5V | 367 RK3328_HDMI_SCL_5V)); 368 return status; 369 } 370 371 static void dw_hdmi_rk3328_setup_hpd(struct dw_hdmi *dw_hdmi, void *data) 372 { 373 struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; 374 375 dw_hdmi_phy_setup_hpd(dw_hdmi, data); 376 377 /* Enable and map pins to 3V grf-controlled io-voltage */ 378 regmap_write(hdmi->regmap, 379 RK3328_GRF_SOC_CON4, 380 HIWORD_UPDATE(0, RK3328_HDMI_HPD_SARADC | RK3328_HDMI_CEC_5V | 381 RK3328_HDMI_SDA_5V | RK3328_HDMI_SCL_5V | 382 RK3328_HDMI_HPD_5V)); 383 regmap_write(hdmi->regmap, 384 RK3328_GRF_SOC_CON3, 385 HIWORD_UPDATE(0, RK3328_HDMI_SDA5V_GRF | RK3328_HDMI_SCL5V_GRF | 386 RK3328_HDMI_HPD5V_GRF | 387 RK3328_HDMI_CEC5V_GRF)); 388 regmap_write(hdmi->regmap, 389 RK3328_GRF_SOC_CON2, 390 HIWORD_UPDATE(RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK, 391 RK3328_HDMI_SDAIN_MSK | RK3328_HDMI_SCLIN_MSK | 392 RK3328_HDMI_HPD_IOE)); 393 } 394 395 static const struct dw_hdmi_phy_ops rk3228_hdmi_phy_ops = { 396 .init = dw_hdmi_rockchip_genphy_init, 397 .disable = dw_hdmi_rockchip_genphy_disable, 398 .read_hpd = dw_hdmi_phy_read_hpd, 399 .update_hpd = dw_hdmi_phy_update_hpd, 400 .setup_hpd = dw_hdmi_rk3228_setup_hpd, 401 }; 402 403 static struct rockchip_hdmi_chip_data rk3228_chip_data = { 404 .lcdsel_grf_reg = -1, 405 }; 406 407 static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { 408 .mode_valid = dw_hdmi_rockchip_mode_valid, 409 .mpll_cfg = rockchip_mpll_cfg, 410 .cur_ctr = rockchip_cur_ctr, 411 .phy_config = rockchip_phy_config, 412 .phy_data = &rk3228_chip_data, 413 .phy_ops = &rk3228_hdmi_phy_ops, 414 .phy_name = "inno_dw_hdmi_phy2", 415 .phy_force_vendor = true, 416 }; 417 418 static struct rockchip_hdmi_chip_data rk3288_chip_data = { 419 .lcdsel_grf_reg = RK3288_GRF_SOC_CON6, 420 .lcdsel_big = HIWORD_UPDATE(0, RK3288_HDMI_LCDC_SEL), 421 .lcdsel_lit = HIWORD_UPDATE(RK3288_HDMI_LCDC_SEL, RK3288_HDMI_LCDC_SEL), 422 }; 423 424 static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = { 425 .mode_valid = dw_hdmi_rockchip_mode_valid, 426 .mpll_cfg = rockchip_mpll_cfg, 427 .cur_ctr = rockchip_cur_ctr, 428 .phy_config = rockchip_phy_config, 429 .phy_data = &rk3288_chip_data, 430 }; 431 432 static const struct dw_hdmi_phy_ops rk3328_hdmi_phy_ops = { 433 .init = dw_hdmi_rockchip_genphy_init, 434 .disable = dw_hdmi_rockchip_genphy_disable, 435 .read_hpd = dw_hdmi_rk3328_read_hpd, 436 .update_hpd = dw_hdmi_phy_update_hpd, 437 .setup_hpd = dw_hdmi_rk3328_setup_hpd, 438 }; 439 440 static struct rockchip_hdmi_chip_data rk3328_chip_data = { 441 .lcdsel_grf_reg = -1, 442 }; 443 444 static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { 445 .mode_valid = dw_hdmi_rockchip_mode_valid, 446 .mpll_cfg = rockchip_mpll_cfg, 447 .cur_ctr = rockchip_cur_ctr, 448 .phy_config = rockchip_phy_config, 449 .phy_data = &rk3328_chip_data, 450 .phy_ops = &rk3328_hdmi_phy_ops, 451 .phy_name = "inno_dw_hdmi_phy2", 452 .phy_force_vendor = true, 453 .use_drm_infoframe = true, 454 }; 455 456 static struct rockchip_hdmi_chip_data rk3399_chip_data = { 457 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, 458 .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), 459 .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), 460 }; 461 462 static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { 463 .mode_valid = dw_hdmi_rockchip_mode_valid, 464 .mpll_cfg = rockchip_mpll_cfg, 465 .cur_ctr = rockchip_cur_ctr, 466 .phy_config = rockchip_phy_config, 467 .phy_data = &rk3399_chip_data, 468 .use_drm_infoframe = true, 469 }; 470 471 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { 472 { .compatible = "rockchip,rk3228-dw-hdmi", 473 .data = &rk3228_hdmi_drv_data 474 }, 475 { .compatible = "rockchip,rk3288-dw-hdmi", 476 .data = &rk3288_hdmi_drv_data 477 }, 478 { .compatible = "rockchip,rk3328-dw-hdmi", 479 .data = &rk3328_hdmi_drv_data 480 }, 481 { .compatible = "rockchip,rk3399-dw-hdmi", 482 .data = &rk3399_hdmi_drv_data 483 }, 484 {}, 485 }; 486 MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids); 487 488 static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, 489 void *data) 490 { 491 struct platform_device *pdev = to_platform_device(dev); 492 struct dw_hdmi_plat_data *plat_data; 493 const struct of_device_id *match; 494 struct drm_device *drm = data; 495 struct drm_encoder *encoder; 496 struct rockchip_hdmi *hdmi; 497 int ret; 498 499 if (!pdev->dev.of_node) 500 return -ENODEV; 501 502 hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); 503 if (!hdmi) 504 return -ENOMEM; 505 506 match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node); 507 plat_data = devm_kmemdup(&pdev->dev, match->data, 508 sizeof(*plat_data), GFP_KERNEL); 509 if (!plat_data) 510 return -ENOMEM; 511 512 hdmi->dev = &pdev->dev; 513 hdmi->chip_data = plat_data->phy_data; 514 plat_data->phy_data = hdmi; 515 encoder = &hdmi->encoder; 516 517 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 518 /* 519 * If we failed to find the CRTC(s) which this encoder is 520 * supposed to be connected to, it's because the CRTC has 521 * not been registered yet. Defer probing, and hope that 522 * the required CRTC is added later. 523 */ 524 if (encoder->possible_crtcs == 0) 525 return -EPROBE_DEFER; 526 527 ret = rockchip_hdmi_parse_dt(hdmi); 528 if (ret) { 529 DRM_DEV_ERROR(hdmi->dev, "Unable to parse OF data\n"); 530 return ret; 531 } 532 533 ret = clk_prepare_enable(hdmi->vpll_clk); 534 if (ret) { 535 DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n", 536 ret); 537 return ret; 538 } 539 540 hdmi->phy = devm_phy_optional_get(dev, "hdmi"); 541 if (IS_ERR(hdmi->phy)) { 542 ret = PTR_ERR(hdmi->phy); 543 if (ret != -EPROBE_DEFER) 544 DRM_DEV_ERROR(hdmi->dev, "failed to get phy\n"); 545 return ret; 546 } 547 548 drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); 549 drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs, 550 DRM_MODE_ENCODER_TMDS, NULL); 551 552 platform_set_drvdata(pdev, hdmi); 553 554 hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); 555 556 /* 557 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), 558 * which would have called the encoder cleanup. Do it manually. 559 */ 560 if (IS_ERR(hdmi->hdmi)) { 561 ret = PTR_ERR(hdmi->hdmi); 562 drm_encoder_cleanup(encoder); 563 clk_disable_unprepare(hdmi->vpll_clk); 564 } 565 566 return ret; 567 } 568 569 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, 570 void *data) 571 { 572 struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); 573 574 dw_hdmi_unbind(hdmi->hdmi); 575 clk_disable_unprepare(hdmi->vpll_clk); 576 } 577 578 static const struct component_ops dw_hdmi_rockchip_ops = { 579 .bind = dw_hdmi_rockchip_bind, 580 .unbind = dw_hdmi_rockchip_unbind, 581 }; 582 583 static int dw_hdmi_rockchip_probe(struct platform_device *pdev) 584 { 585 return component_add(&pdev->dev, &dw_hdmi_rockchip_ops); 586 } 587 588 static int dw_hdmi_rockchip_remove(struct platform_device *pdev) 589 { 590 component_del(&pdev->dev, &dw_hdmi_rockchip_ops); 591 592 return 0; 593 } 594 595 static int __maybe_unused dw_hdmi_rockchip_resume(struct device *dev) 596 { 597 struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); 598 599 dw_hdmi_resume(hdmi->hdmi); 600 601 return 0; 602 } 603 604 static const struct dev_pm_ops dw_hdmi_rockchip_pm = { 605 SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_rockchip_resume) 606 }; 607 608 struct platform_driver dw_hdmi_rockchip_pltfm_driver = { 609 .probe = dw_hdmi_rockchip_probe, 610 .remove = dw_hdmi_rockchip_remove, 611 .driver = { 612 .name = "dwhdmi-rockchip", 613 .pm = &dw_hdmi_rockchip_pm, 614 .of_match_table = dw_hdmi_rockchip_dt_ids, 615 }, 616 }; 617