| .. | .. | 
|---|
| 5 | 5 |  | 
|---|
| 6 | 6 | #include <linux/delay.h> | 
|---|
| 7 | 7 | #include <linux/of_address.h> | 
|---|
|  | 8 | +#include <linux/of_platform.h> | 
|---|
| 8 | 9 |  | 
|---|
| 9 | 10 | #include "sun8i_dw_hdmi.h" | 
|---|
| 10 | 11 |  | 
|---|
| .. | .. | 
|---|
| 13 | 14 | * it is set in BSP driver. | 
|---|
| 14 | 15 | */ | 
|---|
| 15 | 16 | #define I2C_ADDR	0x69 | 
|---|
|  | 17 | + | 
|---|
|  | 18 | +static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = { | 
|---|
|  | 19 | +	{ | 
|---|
|  | 20 | +		30666000, { | 
|---|
|  | 21 | +			{ 0x00b3, 0x0000 }, | 
|---|
|  | 22 | +			{ 0x2153, 0x0000 }, | 
|---|
|  | 23 | +			{ 0x40f3, 0x0000 }, | 
|---|
|  | 24 | +		}, | 
|---|
|  | 25 | +	},  { | 
|---|
|  | 26 | +		36800000, { | 
|---|
|  | 27 | +			{ 0x00b3, 0x0000 }, | 
|---|
|  | 28 | +			{ 0x2153, 0x0000 }, | 
|---|
|  | 29 | +			{ 0x40a2, 0x0001 }, | 
|---|
|  | 30 | +		}, | 
|---|
|  | 31 | +	},  { | 
|---|
|  | 32 | +		46000000, { | 
|---|
|  | 33 | +			{ 0x00b3, 0x0000 }, | 
|---|
|  | 34 | +			{ 0x2142, 0x0001 }, | 
|---|
|  | 35 | +			{ 0x40a2, 0x0001 }, | 
|---|
|  | 36 | +		}, | 
|---|
|  | 37 | +	},  { | 
|---|
|  | 38 | +		61333000, { | 
|---|
|  | 39 | +			{ 0x0072, 0x0001 }, | 
|---|
|  | 40 | +			{ 0x2142, 0x0001 }, | 
|---|
|  | 41 | +			{ 0x40a2, 0x0001 }, | 
|---|
|  | 42 | +		}, | 
|---|
|  | 43 | +	},  { | 
|---|
|  | 44 | +		73600000, { | 
|---|
|  | 45 | +			{ 0x0072, 0x0001 }, | 
|---|
|  | 46 | +			{ 0x2142, 0x0001 }, | 
|---|
|  | 47 | +			{ 0x4061, 0x0002 }, | 
|---|
|  | 48 | +		}, | 
|---|
|  | 49 | +	},  { | 
|---|
|  | 50 | +		92000000, { | 
|---|
|  | 51 | +			{ 0x0072, 0x0001 }, | 
|---|
|  | 52 | +			{ 0x2145, 0x0002 }, | 
|---|
|  | 53 | +			{ 0x4061, 0x0002 }, | 
|---|
|  | 54 | +		}, | 
|---|
|  | 55 | +	},  { | 
|---|
|  | 56 | +		122666000, { | 
|---|
|  | 57 | +			{ 0x0051, 0x0002 }, | 
|---|
|  | 58 | +			{ 0x2145, 0x0002 }, | 
|---|
|  | 59 | +			{ 0x4061, 0x0002 }, | 
|---|
|  | 60 | +		}, | 
|---|
|  | 61 | +	},  { | 
|---|
|  | 62 | +		147200000, { | 
|---|
|  | 63 | +			{ 0x0051, 0x0002 }, | 
|---|
|  | 64 | +			{ 0x2145, 0x0002 }, | 
|---|
|  | 65 | +			{ 0x4064, 0x0003 }, | 
|---|
|  | 66 | +		}, | 
|---|
|  | 67 | +	},  { | 
|---|
|  | 68 | +		184000000, { | 
|---|
|  | 69 | +			{ 0x0051, 0x0002 }, | 
|---|
|  | 70 | +			{ 0x214c, 0x0003 }, | 
|---|
|  | 71 | +			{ 0x4064, 0x0003 }, | 
|---|
|  | 72 | +		}, | 
|---|
|  | 73 | +	},  { | 
|---|
|  | 74 | +		226666000, { | 
|---|
|  | 75 | +			{ 0x0040, 0x0003 }, | 
|---|
|  | 76 | +			{ 0x214c, 0x0003 }, | 
|---|
|  | 77 | +			{ 0x4064, 0x0003 }, | 
|---|
|  | 78 | +		}, | 
|---|
|  | 79 | +	},  { | 
|---|
|  | 80 | +		272000000, { | 
|---|
|  | 81 | +			{ 0x0040, 0x0003 }, | 
|---|
|  | 82 | +			{ 0x214c, 0x0003 }, | 
|---|
|  | 83 | +			{ 0x5a64, 0x0003 }, | 
|---|
|  | 84 | +		}, | 
|---|
|  | 85 | +	},  { | 
|---|
|  | 86 | +		340000000, { | 
|---|
|  | 87 | +			{ 0x0040, 0x0003 }, | 
|---|
|  | 88 | +			{ 0x3b4c, 0x0003 }, | 
|---|
|  | 89 | +			{ 0x5a64, 0x0003 }, | 
|---|
|  | 90 | +		}, | 
|---|
|  | 91 | +	},  { | 
|---|
|  | 92 | +		594000000, { | 
|---|
|  | 93 | +			{ 0x1a40, 0x0003 }, | 
|---|
|  | 94 | +			{ 0x3b4c, 0x0003 }, | 
|---|
|  | 95 | +			{ 0x5a64, 0x0003 }, | 
|---|
|  | 96 | +		}, | 
|---|
|  | 97 | +	}, { | 
|---|
|  | 98 | +		~0UL, { | 
|---|
|  | 99 | +			{ 0x0000, 0x0000 }, | 
|---|
|  | 100 | +			{ 0x0000, 0x0000 }, | 
|---|
|  | 101 | +			{ 0x0000, 0x0000 }, | 
|---|
|  | 102 | +		}, | 
|---|
|  | 103 | +	} | 
|---|
|  | 104 | +}; | 
|---|
|  | 105 | + | 
|---|
|  | 106 | +static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = { | 
|---|
|  | 107 | +	/* pixelclk    bpp8    bpp10   bpp12 */ | 
|---|
|  | 108 | +	{ 27000000,  { 0x0012, 0x0000, 0x0000 }, }, | 
|---|
|  | 109 | +	{ 74250000,  { 0x0013, 0x001a, 0x001b }, }, | 
|---|
|  | 110 | +	{ 148500000, { 0x0019, 0x0033, 0x0034 }, }, | 
|---|
|  | 111 | +	{ 297000000, { 0x0019, 0x001b, 0x001b }, }, | 
|---|
|  | 112 | +	{ 594000000, { 0x0010, 0x001b, 0x001b }, }, | 
|---|
|  | 113 | +	{ ~0UL,      { 0x0000, 0x0000, 0x0000 }, } | 
|---|
|  | 114 | +}; | 
|---|
|  | 115 | + | 
|---|
|  | 116 | +static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = { | 
|---|
|  | 117 | +	/*pixelclk   symbol   term   vlev*/ | 
|---|
|  | 118 | +	{ 27000000,  0x8009, 0x0007, 0x02b0 }, | 
|---|
|  | 119 | +	{ 74250000,  0x8009, 0x0006, 0x022d }, | 
|---|
|  | 120 | +	{ 148500000, 0x8029, 0x0006, 0x0270 }, | 
|---|
|  | 121 | +	{ 297000000, 0x8039, 0x0005, 0x01ab }, | 
|---|
|  | 122 | +	{ 594000000, 0x8029, 0x0000, 0x008a }, | 
|---|
|  | 123 | +	{ ~0UL,	     0x0000, 0x0000, 0x0000} | 
|---|
|  | 124 | +}; | 
|---|
| 16 | 125 |  | 
|---|
| 17 | 126 | static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi, | 
|---|
| 18 | 127 | struct sun8i_hdmi_phy *phy, | 
|---|
| .. | .. | 
|---|
| 225 | 334 | } | 
|---|
| 226 | 335 |  | 
|---|
| 227 | 336 | static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data, | 
|---|
| 228 |  | -				 struct drm_display_mode *mode) | 
|---|
|  | 337 | +				 const struct drm_display_info *display, | 
|---|
|  | 338 | +				 const struct drm_display_mode *mode) | 
|---|
| 229 | 339 | { | 
|---|
| 230 | 340 | struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data; | 
|---|
| 231 | 341 | u32 val = 0; | 
|---|
| .. | .. | 
|---|
| 280 | 390 | .setup_hpd = &dw_hdmi_phy_setup_hpd, | 
|---|
| 281 | 391 | }; | 
|---|
| 282 | 392 |  | 
|---|
|  | 393 | +static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy) | 
|---|
|  | 394 | +{ | 
|---|
|  | 395 | +	/* enable read access to HDMI controller */ | 
|---|
|  | 396 | +	regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG, | 
|---|
|  | 397 | +		     SUN8I_HDMI_PHY_READ_EN_MAGIC); | 
|---|
|  | 398 | + | 
|---|
|  | 399 | +	/* unscramble register offsets */ | 
|---|
|  | 400 | +	regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG, | 
|---|
|  | 401 | +		     SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC); | 
|---|
|  | 402 | +} | 
|---|
|  | 403 | + | 
|---|
|  | 404 | +static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy) | 
|---|
|  | 405 | +{ | 
|---|
|  | 406 | +	regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, | 
|---|
|  | 407 | +			   SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, | 
|---|
|  | 408 | +			   SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN); | 
|---|
|  | 409 | + | 
|---|
|  | 410 | +	regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG, | 
|---|
|  | 411 | +			   0xffff0000, 0x80c00000); | 
|---|
|  | 412 | +} | 
|---|
|  | 413 | + | 
|---|
| 283 | 414 | static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy) | 
|---|
| 284 | 415 | { | 
|---|
|  | 416 | +	sun8i_hdmi_phy_unlock(phy); | 
|---|
|  | 417 | + | 
|---|
| 285 | 418 | regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG, | 
|---|
| 286 | 419 | SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK, | 
|---|
| 287 | 420 | SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK); | 
|---|
| .. | .. | 
|---|
| 298 | 431 | static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy) | 
|---|
| 299 | 432 | { | 
|---|
| 300 | 433 | unsigned int val; | 
|---|
|  | 434 | + | 
|---|
|  | 435 | +	sun8i_hdmi_phy_unlock(phy); | 
|---|
| 301 | 436 |  | 
|---|
| 302 | 437 | regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0); | 
|---|
| 303 | 438 | regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, | 
|---|
| .. | .. | 
|---|
| 371 | 506 | phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2; | 
|---|
| 372 | 507 | } | 
|---|
| 373 | 508 |  | 
|---|
| 374 |  | -void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) | 
|---|
|  | 509 | +int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy) | 
|---|
| 375 | 510 | { | 
|---|
| 376 |  | -	/* enable read access to HDMI controller */ | 
|---|
| 377 |  | -	regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG, | 
|---|
| 378 |  | -		     SUN8I_HDMI_PHY_READ_EN_MAGIC); | 
|---|
|  | 511 | +	int ret; | 
|---|
| 379 | 512 |  | 
|---|
| 380 |  | -	/* unscramble register offsets */ | 
|---|
| 381 |  | -	regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG, | 
|---|
| 382 |  | -		     SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC); | 
|---|
|  | 513 | +	ret = reset_control_deassert(phy->rst_phy); | 
|---|
|  | 514 | +	if (ret) { | 
|---|
|  | 515 | +		dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret); | 
|---|
|  | 516 | +		return ret; | 
|---|
|  | 517 | +	} | 
|---|
|  | 518 | + | 
|---|
|  | 519 | +	ret = clk_prepare_enable(phy->clk_bus); | 
|---|
|  | 520 | +	if (ret) { | 
|---|
|  | 521 | +		dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret); | 
|---|
|  | 522 | +		goto err_assert_rst_phy; | 
|---|
|  | 523 | +	} | 
|---|
|  | 524 | + | 
|---|
|  | 525 | +	ret = clk_prepare_enable(phy->clk_mod); | 
|---|
|  | 526 | +	if (ret) { | 
|---|
|  | 527 | +		dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret); | 
|---|
|  | 528 | +		goto err_disable_clk_bus; | 
|---|
|  | 529 | +	} | 
|---|
|  | 530 | + | 
|---|
|  | 531 | +	if (phy->variant->has_phy_clk) { | 
|---|
|  | 532 | +		ret = sun8i_phy_clk_create(phy, phy->dev, | 
|---|
|  | 533 | +					   phy->variant->has_second_pll); | 
|---|
|  | 534 | +		if (ret) { | 
|---|
|  | 535 | +			dev_err(phy->dev, "Couldn't create the PHY clock\n"); | 
|---|
|  | 536 | +			goto err_disable_clk_mod; | 
|---|
|  | 537 | +		} | 
|---|
|  | 538 | + | 
|---|
|  | 539 | +		clk_prepare_enable(phy->clk_phy); | 
|---|
|  | 540 | +	} | 
|---|
| 383 | 541 |  | 
|---|
| 384 | 542 | phy->variant->phy_init(phy); | 
|---|
|  | 543 | + | 
|---|
|  | 544 | +	return 0; | 
|---|
|  | 545 | + | 
|---|
|  | 546 | +err_disable_clk_mod: | 
|---|
|  | 547 | +	clk_disable_unprepare(phy->clk_mod); | 
|---|
|  | 548 | +err_disable_clk_bus: | 
|---|
|  | 549 | +	clk_disable_unprepare(phy->clk_bus); | 
|---|
|  | 550 | +err_assert_rst_phy: | 
|---|
|  | 551 | +	reset_control_assert(phy->rst_phy); | 
|---|
|  | 552 | + | 
|---|
|  | 553 | +	return ret; | 
|---|
| 385 | 554 | } | 
|---|
| 386 | 555 |  | 
|---|
| 387 |  | -const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void) | 
|---|
|  | 556 | +void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy) | 
|---|
| 388 | 557 | { | 
|---|
| 389 |  | -	return &sun8i_hdmi_phy_ops; | 
|---|
|  | 558 | +	clk_disable_unprepare(phy->clk_mod); | 
|---|
|  | 559 | +	clk_disable_unprepare(phy->clk_bus); | 
|---|
|  | 560 | +	clk_disable_unprepare(phy->clk_phy); | 
|---|
|  | 561 | + | 
|---|
|  | 562 | +	reset_control_assert(phy->rst_phy); | 
|---|
| 390 | 563 | } | 
|---|
| 391 | 564 |  | 
|---|
| 392 |  | -static struct regmap_config sun8i_hdmi_phy_regmap_config = { | 
|---|
|  | 565 | +void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy, | 
|---|
|  | 566 | +			    struct dw_hdmi_plat_data *plat_data) | 
|---|
|  | 567 | +{ | 
|---|
|  | 568 | +	struct sun8i_hdmi_phy_variant *variant = phy->variant; | 
|---|
|  | 569 | + | 
|---|
|  | 570 | +	if (variant->is_custom_phy) { | 
|---|
|  | 571 | +		plat_data->phy_ops = &sun8i_hdmi_phy_ops; | 
|---|
|  | 572 | +		plat_data->phy_name = "sun8i_dw_hdmi_phy"; | 
|---|
|  | 573 | +		plat_data->phy_data = phy; | 
|---|
|  | 574 | +	} else { | 
|---|
|  | 575 | +		plat_data->mpll_cfg = variant->mpll_cfg; | 
|---|
|  | 576 | +		plat_data->cur_ctr = variant->cur_ctr; | 
|---|
|  | 577 | +		plat_data->phy_config = variant->phy_cfg; | 
|---|
|  | 578 | +	} | 
|---|
|  | 579 | +} | 
|---|
|  | 580 | + | 
|---|
|  | 581 | +static const struct regmap_config sun8i_hdmi_phy_regmap_config = { | 
|---|
| 393 | 582 | .reg_bits	= 32, | 
|---|
| 394 | 583 | .val_bits	= 32, | 
|---|
| 395 | 584 | .reg_stride	= 4, | 
|---|
| .. | .. | 
|---|
| 397 | 586 | .name		= "phy" | 
|---|
| 398 | 587 | }; | 
|---|
| 399 | 588 |  | 
|---|
| 400 |  | -static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = { | 
|---|
| 401 |  | -	.has_phy_clk = true, | 
|---|
| 402 |  | -	.phy_init = &sun8i_hdmi_phy_init_h3, | 
|---|
| 403 |  | -	.phy_disable = &sun8i_hdmi_phy_disable_h3, | 
|---|
| 404 |  | -	.phy_config = &sun8i_hdmi_phy_config_h3, | 
|---|
| 405 |  | -}; | 
|---|
| 406 |  | - | 
|---|
| 407 | 589 | static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { | 
|---|
|  | 590 | +	.is_custom_phy = true, | 
|---|
| 408 | 591 | .phy_init = &sun8i_hdmi_phy_init_a83t, | 
|---|
| 409 | 592 | .phy_disable = &sun8i_hdmi_phy_disable_a83t, | 
|---|
| 410 | 593 | .phy_config = &sun8i_hdmi_phy_config_a83t, | 
|---|
| .. | .. | 
|---|
| 412 | 595 |  | 
|---|
| 413 | 596 | static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { | 
|---|
| 414 | 597 | .has_phy_clk = true, | 
|---|
|  | 598 | +	.is_custom_phy = true, | 
|---|
| 415 | 599 | .phy_init = &sun8i_hdmi_phy_init_h3, | 
|---|
| 416 | 600 | .phy_disable = &sun8i_hdmi_phy_disable_h3, | 
|---|
| 417 | 601 | .phy_config = &sun8i_hdmi_phy_config_h3, | 
|---|
| 418 | 602 | }; | 
|---|
| 419 | 603 |  | 
|---|
|  | 604 | +static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = { | 
|---|
|  | 605 | +	.has_phy_clk = true, | 
|---|
|  | 606 | +	.has_second_pll = true, | 
|---|
|  | 607 | +	.is_custom_phy = true, | 
|---|
|  | 608 | +	.phy_init = &sun8i_hdmi_phy_init_h3, | 
|---|
|  | 609 | +	.phy_disable = &sun8i_hdmi_phy_disable_h3, | 
|---|
|  | 610 | +	.phy_config = &sun8i_hdmi_phy_config_h3, | 
|---|
|  | 611 | +}; | 
|---|
|  | 612 | + | 
|---|
|  | 613 | +static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = { | 
|---|
|  | 614 | +	.has_phy_clk = true, | 
|---|
|  | 615 | +	.is_custom_phy = true, | 
|---|
|  | 616 | +	.phy_init = &sun8i_hdmi_phy_init_h3, | 
|---|
|  | 617 | +	.phy_disable = &sun8i_hdmi_phy_disable_h3, | 
|---|
|  | 618 | +	.phy_config = &sun8i_hdmi_phy_config_h3, | 
|---|
|  | 619 | +}; | 
|---|
|  | 620 | + | 
|---|
|  | 621 | +static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = { | 
|---|
|  | 622 | +	.cur_ctr  = sun50i_h6_cur_ctr, | 
|---|
|  | 623 | +	.mpll_cfg = sun50i_h6_mpll_cfg, | 
|---|
|  | 624 | +	.phy_cfg  = sun50i_h6_phy_config, | 
|---|
|  | 625 | +	.phy_init = &sun50i_hdmi_phy_init_h6, | 
|---|
|  | 626 | +}; | 
|---|
|  | 627 | + | 
|---|
| 420 | 628 | static const struct of_device_id sun8i_hdmi_phy_of_table[] = { | 
|---|
| 421 |  | -	{ | 
|---|
| 422 |  | -		.compatible = "allwinner,sun50i-a64-hdmi-phy", | 
|---|
| 423 |  | -		.data = &sun50i_a64_hdmi_phy, | 
|---|
| 424 |  | -	}, | 
|---|
| 425 | 629 | { | 
|---|
| 426 | 630 | .compatible = "allwinner,sun8i-a83t-hdmi-phy", | 
|---|
| 427 | 631 | .data = &sun8i_a83t_hdmi_phy, | 
|---|
| .. | .. | 
|---|
| 430 | 634 | .compatible = "allwinner,sun8i-h3-hdmi-phy", | 
|---|
| 431 | 635 | .data = &sun8i_h3_hdmi_phy, | 
|---|
| 432 | 636 | }, | 
|---|
|  | 637 | +	{ | 
|---|
|  | 638 | +		.compatible = "allwinner,sun8i-r40-hdmi-phy", | 
|---|
|  | 639 | +		.data = &sun8i_r40_hdmi_phy, | 
|---|
|  | 640 | +	}, | 
|---|
|  | 641 | +	{ | 
|---|
|  | 642 | +		.compatible = "allwinner,sun50i-a64-hdmi-phy", | 
|---|
|  | 643 | +		.data = &sun50i_a64_hdmi_phy, | 
|---|
|  | 644 | +	}, | 
|---|
|  | 645 | +	{ | 
|---|
|  | 646 | +		.compatible = "allwinner,sun50i-h6-hdmi-phy", | 
|---|
|  | 647 | +		.data = &sun50i_h6_hdmi_phy, | 
|---|
|  | 648 | +	}, | 
|---|
| 433 | 649 | { /* sentinel */ } | 
|---|
| 434 | 650 | }; | 
|---|
| 435 | 651 |  | 
|---|
| 436 |  | -int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) | 
|---|
|  | 652 | +int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node) | 
|---|
|  | 653 | +{ | 
|---|
|  | 654 | +	struct platform_device *pdev = of_find_device_by_node(node); | 
|---|
|  | 655 | +	struct sun8i_hdmi_phy *phy; | 
|---|
|  | 656 | + | 
|---|
|  | 657 | +	if (!pdev) | 
|---|
|  | 658 | +		return -EPROBE_DEFER; | 
|---|
|  | 659 | + | 
|---|
|  | 660 | +	phy = platform_get_drvdata(pdev); | 
|---|
|  | 661 | +	if (!phy) | 
|---|
|  | 662 | +		return -EPROBE_DEFER; | 
|---|
|  | 663 | + | 
|---|
|  | 664 | +	hdmi->phy = phy; | 
|---|
|  | 665 | + | 
|---|
|  | 666 | +	put_device(&pdev->dev); | 
|---|
|  | 667 | + | 
|---|
|  | 668 | +	return 0; | 
|---|
|  | 669 | +} | 
|---|
|  | 670 | + | 
|---|
|  | 671 | +static int sun8i_hdmi_phy_probe(struct platform_device *pdev) | 
|---|
| 437 | 672 | { | 
|---|
| 438 | 673 | const struct of_device_id *match; | 
|---|
| 439 |  | -	struct device *dev = hdmi->dev; | 
|---|
|  | 674 | +	struct device *dev = &pdev->dev; | 
|---|
|  | 675 | +	struct device_node *node = dev->of_node; | 
|---|
| 440 | 676 | struct sun8i_hdmi_phy *phy; | 
|---|
| 441 | 677 | struct resource res; | 
|---|
| 442 | 678 | void __iomem *regs; | 
|---|
| .. | .. | 
|---|
| 453 | 689 | return -ENOMEM; | 
|---|
| 454 | 690 |  | 
|---|
| 455 | 691 | phy->variant = (struct sun8i_hdmi_phy_variant *)match->data; | 
|---|
|  | 692 | +	phy->dev = dev; | 
|---|
| 456 | 693 |  | 
|---|
| 457 | 694 | ret = of_address_to_resource(node, 0, &res); | 
|---|
| 458 | 695 | if (ret) { | 
|---|
| .. | .. | 
|---|
| 511 | 748 | goto err_put_clk_pll1; | 
|---|
| 512 | 749 | } | 
|---|
| 513 | 750 |  | 
|---|
| 514 |  | -	ret = reset_control_deassert(phy->rst_phy); | 
|---|
| 515 |  | -	if (ret) { | 
|---|
| 516 |  | -		dev_err(dev, "Cannot deassert phy reset control: %d\n", ret); | 
|---|
| 517 |  | -		goto err_put_rst_phy; | 
|---|
| 518 |  | -	} | 
|---|
| 519 |  | - | 
|---|
| 520 |  | -	ret = clk_prepare_enable(phy->clk_bus); | 
|---|
| 521 |  | -	if (ret) { | 
|---|
| 522 |  | -		dev_err(dev, "Cannot enable bus clock: %d\n", ret); | 
|---|
| 523 |  | -		goto err_deassert_rst_phy; | 
|---|
| 524 |  | -	} | 
|---|
| 525 |  | - | 
|---|
| 526 |  | -	ret = clk_prepare_enable(phy->clk_mod); | 
|---|
| 527 |  | -	if (ret) { | 
|---|
| 528 |  | -		dev_err(dev, "Cannot enable mod clock: %d\n", ret); | 
|---|
| 529 |  | -		goto err_disable_clk_bus; | 
|---|
| 530 |  | -	} | 
|---|
| 531 |  | - | 
|---|
| 532 |  | -	if (phy->variant->has_phy_clk) { | 
|---|
| 533 |  | -		ret = sun8i_phy_clk_create(phy, dev, | 
|---|
| 534 |  | -					   phy->variant->has_second_pll); | 
|---|
| 535 |  | -		if (ret) { | 
|---|
| 536 |  | -			dev_err(dev, "Couldn't create the PHY clock\n"); | 
|---|
| 537 |  | -			goto err_disable_clk_mod; | 
|---|
| 538 |  | -		} | 
|---|
| 539 |  | - | 
|---|
| 540 |  | -		clk_prepare_enable(phy->clk_phy); | 
|---|
| 541 |  | -	} | 
|---|
| 542 |  | - | 
|---|
| 543 |  | -	hdmi->phy = phy; | 
|---|
|  | 751 | +	platform_set_drvdata(pdev, phy); | 
|---|
| 544 | 752 |  | 
|---|
| 545 | 753 | return 0; | 
|---|
| 546 | 754 |  | 
|---|
| 547 |  | -err_disable_clk_mod: | 
|---|
| 548 |  | -	clk_disable_unprepare(phy->clk_mod); | 
|---|
| 549 |  | -err_disable_clk_bus: | 
|---|
| 550 |  | -	clk_disable_unprepare(phy->clk_bus); | 
|---|
| 551 |  | -err_deassert_rst_phy: | 
|---|
| 552 |  | -	reset_control_assert(phy->rst_phy); | 
|---|
| 553 |  | -err_put_rst_phy: | 
|---|
| 554 |  | -	reset_control_put(phy->rst_phy); | 
|---|
| 555 | 755 | err_put_clk_pll1: | 
|---|
| 556 | 756 | clk_put(phy->clk_pll1); | 
|---|
| 557 | 757 | err_put_clk_pll0: | 
|---|
| .. | .. | 
|---|
| 564 | 764 | return ret; | 
|---|
| 565 | 765 | } | 
|---|
| 566 | 766 |  | 
|---|
| 567 |  | -void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi) | 
|---|
|  | 767 | +static int sun8i_hdmi_phy_remove(struct platform_device *pdev) | 
|---|
| 568 | 768 | { | 
|---|
| 569 |  | -	struct sun8i_hdmi_phy *phy = hdmi->phy; | 
|---|
| 570 |  | - | 
|---|
| 571 |  | -	clk_disable_unprepare(phy->clk_mod); | 
|---|
| 572 |  | -	clk_disable_unprepare(phy->clk_bus); | 
|---|
| 573 |  | -	clk_disable_unprepare(phy->clk_phy); | 
|---|
| 574 |  | - | 
|---|
| 575 |  | -	reset_control_assert(phy->rst_phy); | 
|---|
|  | 769 | +	struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev); | 
|---|
| 576 | 770 |  | 
|---|
| 577 | 771 | reset_control_put(phy->rst_phy); | 
|---|
| 578 | 772 |  | 
|---|
| .. | .. | 
|---|
| 580 | 774 | clk_put(phy->clk_pll1); | 
|---|
| 581 | 775 | clk_put(phy->clk_mod); | 
|---|
| 582 | 776 | clk_put(phy->clk_bus); | 
|---|
|  | 777 | +	return 0; | 
|---|
| 583 | 778 | } | 
|---|
|  | 779 | + | 
|---|
|  | 780 | +struct platform_driver sun8i_hdmi_phy_driver = { | 
|---|
|  | 781 | +	.probe  = sun8i_hdmi_phy_probe, | 
|---|
|  | 782 | +	.remove = sun8i_hdmi_phy_remove, | 
|---|
|  | 783 | +	.driver = { | 
|---|
|  | 784 | +		.name = "sun8i-hdmi-phy", | 
|---|
|  | 785 | +		.of_match_table = sun8i_hdmi_phy_of_table, | 
|---|
|  | 786 | +	}, | 
|---|
|  | 787 | +}; | 
|---|