1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Samsung Exynos SoC series Display Port PHY driver |
4 | * |
5 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. |
6 | * Author: Jingoo Han <jg1.han@samsung.com> |
7 | */ |
8 | |
9 | #include <linux/err.h> |
10 | #include <linux/io.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/mfd/syscon.h> |
14 | #include <linux/of.h> |
15 | #include <linux/phy/phy.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/regmap.h> |
18 | #include <linux/soc/samsung/exynos-regs-pmu.h> |
19 | |
20 | struct exynos_dp_video_phy_drvdata { |
21 | u32 phy_ctrl_offset; |
22 | }; |
23 | |
24 | struct exynos_dp_video_phy { |
25 | struct regmap *regs; |
26 | const struct exynos_dp_video_phy_drvdata *drvdata; |
27 | }; |
28 | |
29 | static int exynos_dp_video_phy_power_on(struct phy *phy) |
30 | { |
31 | struct exynos_dp_video_phy *state = phy_get_drvdata(phy); |
32 | |
33 | /* Disable power isolation on DP-PHY */ |
34 | return regmap_update_bits(map: state->regs, reg: state->drvdata->phy_ctrl_offset, |
35 | EXYNOS4_PHY_ENABLE, EXYNOS4_PHY_ENABLE); |
36 | } |
37 | |
38 | static int exynos_dp_video_phy_power_off(struct phy *phy) |
39 | { |
40 | struct exynos_dp_video_phy *state = phy_get_drvdata(phy); |
41 | |
42 | /* Enable power isolation on DP-PHY */ |
43 | return regmap_update_bits(map: state->regs, reg: state->drvdata->phy_ctrl_offset, |
44 | EXYNOS4_PHY_ENABLE, val: 0); |
45 | } |
46 | |
47 | static const struct phy_ops exynos_dp_video_phy_ops = { |
48 | .power_on = exynos_dp_video_phy_power_on, |
49 | .power_off = exynos_dp_video_phy_power_off, |
50 | .owner = THIS_MODULE, |
51 | }; |
52 | |
53 | static const struct exynos_dp_video_phy_drvdata exynos5250_dp_video_phy = { |
54 | .phy_ctrl_offset = EXYNOS5_DPTX_PHY_CONTROL, |
55 | }; |
56 | |
57 | static const struct exynos_dp_video_phy_drvdata exynos5420_dp_video_phy = { |
58 | .phy_ctrl_offset = EXYNOS5420_DPTX_PHY_CONTROL, |
59 | }; |
60 | |
61 | static const struct of_device_id exynos_dp_video_phy_of_match[] = { |
62 | { |
63 | .compatible = "samsung,exynos5250-dp-video-phy" , |
64 | .data = &exynos5250_dp_video_phy, |
65 | }, { |
66 | .compatible = "samsung,exynos5420-dp-video-phy" , |
67 | .data = &exynos5420_dp_video_phy, |
68 | }, |
69 | { }, |
70 | }; |
71 | MODULE_DEVICE_TABLE(of, exynos_dp_video_phy_of_match); |
72 | |
73 | static int exynos_dp_video_phy_probe(struct platform_device *pdev) |
74 | { |
75 | struct exynos_dp_video_phy *state; |
76 | struct device *dev = &pdev->dev; |
77 | struct phy_provider *phy_provider; |
78 | struct phy *phy; |
79 | |
80 | state = devm_kzalloc(dev, size: sizeof(*state), GFP_KERNEL); |
81 | if (!state) |
82 | return -ENOMEM; |
83 | |
84 | state->regs = syscon_node_to_regmap(np: dev->parent->of_node); |
85 | if (IS_ERR(ptr: state->regs)) |
86 | /* Backwards compatible way */ |
87 | state->regs = syscon_regmap_lookup_by_phandle(np: dev->of_node, |
88 | property: "samsung,pmu-syscon" ); |
89 | if (IS_ERR(ptr: state->regs)) { |
90 | dev_err(dev, "Failed to lookup PMU regmap\n" ); |
91 | return PTR_ERR(ptr: state->regs); |
92 | } |
93 | |
94 | state->drvdata = of_device_get_match_data(dev); |
95 | |
96 | phy = devm_phy_create(dev, NULL, ops: &exynos_dp_video_phy_ops); |
97 | if (IS_ERR(ptr: phy)) { |
98 | dev_err(dev, "failed to create Display Port PHY\n" ); |
99 | return PTR_ERR(ptr: phy); |
100 | } |
101 | phy_set_drvdata(phy, data: state); |
102 | |
103 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
104 | |
105 | return PTR_ERR_OR_ZERO(ptr: phy_provider); |
106 | } |
107 | |
108 | static struct platform_driver exynos_dp_video_phy_driver = { |
109 | .probe = exynos_dp_video_phy_probe, |
110 | .driver = { |
111 | .name = "exynos-dp-video-phy" , |
112 | .of_match_table = exynos_dp_video_phy_of_match, |
113 | .suppress_bind_attrs = true, |
114 | } |
115 | }; |
116 | module_platform_driver(exynos_dp_video_phy_driver); |
117 | |
118 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>" ); |
119 | MODULE_DESCRIPTION("Samsung Exynos SoC DP PHY driver" ); |
120 | MODULE_LICENSE("GPL v2" ); |
121 | |