Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Renesas R-Car USB2.0 clock selector
0004  *
0005  * Copyright (C) 2017 Renesas Electronics Corp.
0006  *
0007  * Based on renesas-cpg-mssr.c
0008  *
0009  * Copyright (C) 2015 Glider bvba
0010  */
0011 
0012 #include <linux/clk.h>
0013 #include <linux/clk-provider.h>
0014 #include <linux/device.h>
0015 #include <linux/init.h>
0016 #include <linux/io.h>
0017 #include <linux/module.h>
0018 #include <linux/of_device.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/pm.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/reset.h>
0023 #include <linux/slab.h>
0024 
0025 #define USB20_CLKSET0       0x00
0026 #define CLKSET0_INTCLK_EN   BIT(11)
0027 #define CLKSET0_PRIVATE     BIT(0)
0028 #define CLKSET0_EXTAL_ONLY  (CLKSET0_INTCLK_EN | CLKSET0_PRIVATE)
0029 
0030 static const struct clk_bulk_data rcar_usb2_clocks[] = {
0031     { .id = "ehci_ohci", },
0032     { .id = "hs-usb-if", },
0033 };
0034 
0035 struct usb2_clock_sel_priv {
0036     void __iomem *base;
0037     struct clk_hw hw;
0038     struct clk_bulk_data clks[ARRAY_SIZE(rcar_usb2_clocks)];
0039     struct reset_control *rsts;
0040     bool extal;
0041     bool xtal;
0042 };
0043 #define to_priv(_hw)    container_of(_hw, struct usb2_clock_sel_priv, hw)
0044 
0045 static void usb2_clock_sel_enable_extal_only(struct usb2_clock_sel_priv *priv)
0046 {
0047     u16 val = readw(priv->base + USB20_CLKSET0);
0048 
0049     pr_debug("%s: enter %d %d %x\n", __func__,
0050          priv->extal, priv->xtal, val);
0051 
0052     if (priv->extal && !priv->xtal && val != CLKSET0_EXTAL_ONLY)
0053         writew(CLKSET0_EXTAL_ONLY, priv->base + USB20_CLKSET0);
0054 }
0055 
0056 static void usb2_clock_sel_disable_extal_only(struct usb2_clock_sel_priv *priv)
0057 {
0058     if (priv->extal && !priv->xtal)
0059         writew(CLKSET0_PRIVATE, priv->base + USB20_CLKSET0);
0060 }
0061 
0062 static int usb2_clock_sel_enable(struct clk_hw *hw)
0063 {
0064     struct usb2_clock_sel_priv *priv = to_priv(hw);
0065     int ret;
0066 
0067     ret = reset_control_deassert(priv->rsts);
0068     if (ret)
0069         return ret;
0070 
0071     ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clks), priv->clks);
0072     if (ret) {
0073         reset_control_assert(priv->rsts);
0074         return ret;
0075     }
0076 
0077     usb2_clock_sel_enable_extal_only(priv);
0078 
0079     return 0;
0080 }
0081 
0082 static void usb2_clock_sel_disable(struct clk_hw *hw)
0083 {
0084     struct usb2_clock_sel_priv *priv = to_priv(hw);
0085 
0086     usb2_clock_sel_disable_extal_only(priv);
0087 
0088     clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clks), priv->clks);
0089     reset_control_assert(priv->rsts);
0090 }
0091 
0092 /*
0093  * This module seems a mux, but this driver assumes a gate because
0094  * ehci/ohci platform drivers don't support clk_set_parent() for now.
0095  * If this driver acts as a gate, ehci/ohci-platform drivers don't need
0096  * any modification.
0097  */
0098 static const struct clk_ops usb2_clock_sel_clock_ops = {
0099     .enable = usb2_clock_sel_enable,
0100     .disable = usb2_clock_sel_disable,
0101 };
0102 
0103 static const struct of_device_id rcar_usb2_clock_sel_match[] = {
0104     { .compatible = "renesas,rcar-gen3-usb2-clock-sel" },
0105     { }
0106 };
0107 
0108 static int rcar_usb2_clock_sel_suspend(struct device *dev)
0109 {
0110     struct usb2_clock_sel_priv *priv = dev_get_drvdata(dev);
0111 
0112     usb2_clock_sel_disable_extal_only(priv);
0113     pm_runtime_put(dev);
0114 
0115     return 0;
0116 }
0117 
0118 static int rcar_usb2_clock_sel_resume(struct device *dev)
0119 {
0120     struct usb2_clock_sel_priv *priv = dev_get_drvdata(dev);
0121 
0122     pm_runtime_get_sync(dev);
0123     usb2_clock_sel_enable_extal_only(priv);
0124 
0125     return 0;
0126 }
0127 
0128 static int rcar_usb2_clock_sel_remove(struct platform_device *pdev)
0129 {
0130     struct device *dev = &pdev->dev;
0131 
0132     of_clk_del_provider(dev->of_node);
0133     pm_runtime_put(dev);
0134     pm_runtime_disable(dev);
0135 
0136     return 0;
0137 }
0138 
0139 static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
0140 {
0141     struct device *dev = &pdev->dev;
0142     struct device_node *np = dev->of_node;
0143     struct usb2_clock_sel_priv *priv;
0144     struct clk *clk;
0145     struct clk_init_data init = {};
0146     int ret;
0147 
0148     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0149     if (!priv)
0150         return -ENOMEM;
0151 
0152     priv->base = devm_platform_ioremap_resource(pdev, 0);
0153     if (IS_ERR(priv->base))
0154         return PTR_ERR(priv->base);
0155 
0156     memcpy(priv->clks, rcar_usb2_clocks, sizeof(priv->clks));
0157     ret = devm_clk_bulk_get(dev, ARRAY_SIZE(priv->clks), priv->clks);
0158     if (ret < 0)
0159         return ret;
0160 
0161     priv->rsts = devm_reset_control_array_get_shared(dev);
0162     if (IS_ERR(priv->rsts))
0163         return PTR_ERR(priv->rsts);
0164 
0165     clk = devm_clk_get(dev, "usb_extal");
0166     if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
0167         priv->extal = !!clk_get_rate(clk);
0168         clk_disable_unprepare(clk);
0169     }
0170     clk = devm_clk_get(dev, "usb_xtal");
0171     if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
0172         priv->xtal = !!clk_get_rate(clk);
0173         clk_disable_unprepare(clk);
0174     }
0175 
0176     if (!priv->extal && !priv->xtal) {
0177         dev_err(dev, "This driver needs usb_extal or usb_xtal\n");
0178         return -ENOENT;
0179     }
0180 
0181     pm_runtime_enable(dev);
0182     pm_runtime_get_sync(dev);
0183     platform_set_drvdata(pdev, priv);
0184     dev_set_drvdata(dev, priv);
0185 
0186     init.name = "rcar_usb2_clock_sel";
0187     init.ops = &usb2_clock_sel_clock_ops;
0188     priv->hw.init = &init;
0189 
0190     ret = devm_clk_hw_register(dev, &priv->hw);
0191     if (ret)
0192         goto pm_put;
0193 
0194     ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
0195     if (ret)
0196         goto pm_put;
0197 
0198     return 0;
0199 
0200 pm_put:
0201     pm_runtime_put(dev);
0202     pm_runtime_disable(dev);
0203     return ret;
0204 }
0205 
0206 static const struct dev_pm_ops rcar_usb2_clock_sel_pm_ops = {
0207     .suspend    = rcar_usb2_clock_sel_suspend,
0208     .resume     = rcar_usb2_clock_sel_resume,
0209 };
0210 
0211 static struct platform_driver rcar_usb2_clock_sel_driver = {
0212     .driver     = {
0213         .name   = "rcar-usb2-clock-sel",
0214         .of_match_table = rcar_usb2_clock_sel_match,
0215         .pm = &rcar_usb2_clock_sel_pm_ops,
0216     },
0217     .probe      = rcar_usb2_clock_sel_probe,
0218     .remove     = rcar_usb2_clock_sel_remove,
0219 };
0220 builtin_platform_driver(rcar_usb2_clock_sel_driver);
0221 
0222 MODULE_DESCRIPTION("Renesas R-Car USB2 clock selector Driver");
0223 MODULE_LICENSE("GPL v2");