diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2014-06-25 23:22:56 +0530 |
---|---|---|
committer | Kishon Vijay Abraham I <kishon@ti.com> | 2014-07-22 12:46:10 +0530 |
commit | 99bbd48c2065552fd2d224c9f065dcac9b7e25ce (patch) | |
tree | 472b73a962d52f4d809353fbac2375dd5c0462fe | |
parent | 57416c23e3ab57e65ba6e7c2e30fb40ba85035a6 (diff) | |
download | linux-stable-99bbd48c2065552fd2d224c9f065dcac9b7e25ce.tar.gz linux-stable-99bbd48c2065552fd2d224c9f065dcac9b7e25ce.tar.bz2 linux-stable-99bbd48c2065552fd2d224c9f065dcac9b7e25ce.zip |
phy: phy-omap-pipe3: Add support for PCIe PHY
PCIe PHY uses an external pll instead of the internal pll used by SATA
and USB3. So added support in pipe3 PHY to use external pll.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Reviewed-by: Roger Quadros <rogerq@ti.com>
-rw-r--r-- | Documentation/devicetree/bindings/phy/ti-phy.txt | 11 | ||||
-rw-r--r-- | drivers/phy/phy-ti-pipe3.c | 103 |
2 files changed, 91 insertions, 23 deletions
diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index 9ce458f32945..b50e1c10a05d 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -56,8 +56,8 @@ usb2phy@4a0ad080 { TI PIPE3 PHY Required properties: - - compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata". - "ti,omap-usb3" is deprecated. + - compatible: Should be "ti,phy-usb3", "ti,phy-pipe3-sata" or + "ti,phy-pipe3-pcie. "ti,omap-usb3" is deprecated. - reg : Address and length of the register set for the device. - reg-names: The names of the register addresses corresponding to the registers filled in "reg". @@ -69,10 +69,17 @@ Required properties: * "wkupclk" - wakeup clock. * "sysclk" - system clock. * "refclk" - reference clock. + * "dpll_ref" - external dpll ref clk + * "dpll_ref_m2" - external dpll ref clk + * "phy-div" - divider for apll + * "div-clk" - apll clock Optional properties: - ctrl-module : phandle of the control module used by PHY driver to power on the PHY. + - id: If there are multiple instance of the same type, in order to + differentiate between each instance "id" can be used (e.g., multi-lane PCIe + PHY). If "id" is not provided, it is set to default value of '1'. This is usually a subnode of ocp2scp to which it is connected. diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 591367654613..6174f4b1a5de 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -80,7 +80,9 @@ struct ti_pipe3 { struct clk *wkupclk; struct clk *sys_clk; struct clk *refclk; + struct clk *div_clk; struct pipe3_dpll_map *dpll_map; + u8 id; }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -215,6 +217,9 @@ static int ti_pipe3_init(struct phy *x) u32 val; int ret = 0; + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) + return 0; + /* Bring it out of IDLE if it is IDLE */ val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); if (val & PLL_IDLE) { @@ -238,8 +243,11 @@ static int ti_pipe3_exit(struct phy *x) u32 val; unsigned long timeout; - /* SATA DPLL can't be powered down due to Errata i783 */ - if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) + /* SATA DPLL can't be powered down due to Errata i783 and PCIe + * does not have internal DPLL + */ + if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") || + of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) return 0; /* Put DPLL in IDLE mode */ @@ -286,32 +294,41 @@ static int ti_pipe3_probe(struct platform_device *pdev) struct device_node *control_node; struct platform_device *control_pdev; const struct of_device_id *match; - - match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev); - if (!match) - return -EINVAL; + struct clk *clk; phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); if (!phy) { dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n"); return -ENOMEM; } + phy->dev = &pdev->dev; - phy->dpll_map = (struct pipe3_dpll_map *)match->data; - if (!phy->dpll_map) { - dev_err(&pdev->dev, "no DPLL data\n"); - return -EINVAL; - } + if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { + match = of_match_device(of_match_ptr(ti_pipe3_id_table), + &pdev->dev); + if (!match) + return -EINVAL; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); - phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(phy->pll_ctrl_base)) - return PTR_ERR(phy->pll_ctrl_base); + phy->dpll_map = (struct pipe3_dpll_map *)match->data; + if (!phy->dpll_map) { + dev_err(&pdev->dev, "no DPLL data\n"); + return -EINVAL; + } - phy->dev = &pdev->dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "pll_ctrl"); + phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(phy->pll_ctrl_base)) + return PTR_ERR(phy->pll_ctrl_base); - if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { + phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); + if (IS_ERR(phy->sys_clk)) { + dev_err(&pdev->dev, "unable to get sysclk\n"); + return -EINVAL; + } + } + if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { phy->wkupclk = devm_clk_get(phy->dev, "wkupclk"); if (IS_ERR(phy->wkupclk)) { dev_err(&pdev->dev, "unable to get wkupclk\n"); @@ -328,10 +345,38 @@ static int ti_pipe3_probe(struct platform_device *pdev) phy->refclk = ERR_PTR(-ENODEV); } - phy->sys_clk = devm_clk_get(phy->dev, "sysclk"); - if (IS_ERR(phy->sys_clk)) { - dev_err(&pdev->dev, "unable to get sysclk\n"); - return -EINVAL; + if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { + if (of_property_read_u8(node, "id", &phy->id) < 0) + phy->id = 1; + + clk = devm_clk_get(phy->dev, "dpll_ref"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get dpll ref clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 1500000000); + + clk = devm_clk_get(phy->dev, "dpll_ref_m2"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get dpll ref m2 clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 100000000); + + clk = devm_clk_get(phy->dev, "phy-div"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get phy-div clk\n"); + return PTR_ERR(clk); + } + clk_set_rate(clk, 100000000); + + phy->div_clk = devm_clk_get(phy->dev, "div-clk"); + if (IS_ERR(phy->div_clk)) { + dev_err(&pdev->dev, "unable to get div-clk\n"); + return PTR_ERR(phy->div_clk); + } + } else { + phy->div_clk = ERR_PTR(-ENODEV); } control_node = of_parse_phandle(node, "ctrl-module", 0); @@ -387,6 +432,8 @@ static int ti_pipe3_runtime_suspend(struct device *dev) clk_disable_unprepare(phy->wkupclk); if (!IS_ERR(phy->refclk)) clk_disable_unprepare(phy->refclk); + if (!IS_ERR(phy->div_clk)) + clk_disable_unprepare(phy->div_clk); return 0; } @@ -412,8 +459,19 @@ static int ti_pipe3_runtime_resume(struct device *dev) } } + if (!IS_ERR(phy->div_clk)) { + ret = clk_prepare_enable(phy->div_clk); + if (ret) { + dev_err(phy->dev, "Failed to enable div_clk %d\n", ret); + goto err3; + } + } return 0; +err3: + if (!IS_ERR(phy->wkupclk)) + clk_disable_unprepare(phy->wkupclk); + err2: if (!IS_ERR(phy->refclk)) clk_disable_unprepare(phy->refclk); @@ -446,6 +504,9 @@ static const struct of_device_id ti_pipe3_id_table[] = { .compatible = "ti,phy-pipe3-sata", .data = dpll_map_sata, }, + { + .compatible = "ti,phy-pipe3-pcie", + }, {} }; MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); |