0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_device.h>
0015 #include <linux/phy/phy.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/spinlock.h>
0018 #include "phy-samsung-usb2.h"
0019
0020 static int samsung_usb2_phy_power_on(struct phy *phy)
0021 {
0022 struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
0023 struct samsung_usb2_phy_driver *drv = inst->drv;
0024 int ret;
0025
0026 dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
0027 inst->cfg->label);
0028
0029 if (drv->vbus) {
0030 ret = regulator_enable(drv->vbus);
0031 if (ret)
0032 goto err_regulator;
0033 }
0034
0035 ret = clk_prepare_enable(drv->clk);
0036 if (ret)
0037 goto err_main_clk;
0038 ret = clk_prepare_enable(drv->ref_clk);
0039 if (ret)
0040 goto err_instance_clk;
0041 if (inst->cfg->power_on) {
0042 spin_lock(&drv->lock);
0043 ret = inst->cfg->power_on(inst);
0044 spin_unlock(&drv->lock);
0045 if (ret)
0046 goto err_power_on;
0047 }
0048
0049 return 0;
0050
0051 err_power_on:
0052 clk_disable_unprepare(drv->ref_clk);
0053 err_instance_clk:
0054 clk_disable_unprepare(drv->clk);
0055 err_main_clk:
0056 if (drv->vbus)
0057 regulator_disable(drv->vbus);
0058 err_regulator:
0059 return ret;
0060 }
0061
0062 static int samsung_usb2_phy_power_off(struct phy *phy)
0063 {
0064 struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
0065 struct samsung_usb2_phy_driver *drv = inst->drv;
0066 int ret = 0;
0067
0068 dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
0069 inst->cfg->label);
0070 if (inst->cfg->power_off) {
0071 spin_lock(&drv->lock);
0072 ret = inst->cfg->power_off(inst);
0073 spin_unlock(&drv->lock);
0074 if (ret)
0075 return ret;
0076 }
0077 clk_disable_unprepare(drv->ref_clk);
0078 clk_disable_unprepare(drv->clk);
0079 if (drv->vbus)
0080 ret = regulator_disable(drv->vbus);
0081
0082 return ret;
0083 }
0084
0085 static const struct phy_ops samsung_usb2_phy_ops = {
0086 .power_on = samsung_usb2_phy_power_on,
0087 .power_off = samsung_usb2_phy_power_off,
0088 .owner = THIS_MODULE,
0089 };
0090
0091 static struct phy *samsung_usb2_phy_xlate(struct device *dev,
0092 struct of_phandle_args *args)
0093 {
0094 struct samsung_usb2_phy_driver *drv;
0095
0096 drv = dev_get_drvdata(dev);
0097 if (!drv)
0098 return ERR_PTR(-EINVAL);
0099
0100 if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
0101 return ERR_PTR(-ENODEV);
0102
0103 return drv->instances[args->args[0]].phy;
0104 }
0105
0106 static const struct of_device_id samsung_usb2_phy_of_match[] = {
0107 #ifdef CONFIG_PHY_EXYNOS4X12_USB2
0108 {
0109 .compatible = "samsung,exynos3250-usb2-phy",
0110 .data = &exynos3250_usb2_phy_config,
0111 },
0112 #endif
0113 #ifdef CONFIG_PHY_EXYNOS4210_USB2
0114 {
0115 .compatible = "samsung,exynos4210-usb2-phy",
0116 .data = &exynos4210_usb2_phy_config,
0117 },
0118 #endif
0119 #ifdef CONFIG_PHY_EXYNOS4X12_USB2
0120 {
0121 .compatible = "samsung,exynos4x12-usb2-phy",
0122 .data = &exynos4x12_usb2_phy_config,
0123 },
0124 #endif
0125 #ifdef CONFIG_PHY_EXYNOS5250_USB2
0126 {
0127 .compatible = "samsung,exynos5250-usb2-phy",
0128 .data = &exynos5250_usb2_phy_config,
0129 },
0130 {
0131 .compatible = "samsung,exynos5420-usb2-phy",
0132 .data = &exynos5420_usb2_phy_config,
0133 },
0134 #endif
0135 #ifdef CONFIG_PHY_S5PV210_USB2
0136 {
0137 .compatible = "samsung,s5pv210-usb2-phy",
0138 .data = &s5pv210_usb2_phy_config,
0139 },
0140 #endif
0141 { },
0142 };
0143 MODULE_DEVICE_TABLE(of, samsung_usb2_phy_of_match);
0144
0145 static int samsung_usb2_phy_probe(struct platform_device *pdev)
0146 {
0147 const struct samsung_usb2_phy_config *cfg;
0148 struct device *dev = &pdev->dev;
0149 struct phy_provider *phy_provider;
0150 struct samsung_usb2_phy_driver *drv;
0151 int i, ret;
0152
0153 if (!pdev->dev.of_node) {
0154 dev_err(dev, "This driver is required to be instantiated from device tree\n");
0155 return -EINVAL;
0156 }
0157
0158 cfg = of_device_get_match_data(dev);
0159 if (!cfg)
0160 return -EINVAL;
0161
0162 drv = devm_kzalloc(dev, struct_size(drv, instances, cfg->num_phys),
0163 GFP_KERNEL);
0164 if (!drv)
0165 return -ENOMEM;
0166
0167 dev_set_drvdata(dev, drv);
0168 spin_lock_init(&drv->lock);
0169
0170 drv->cfg = cfg;
0171 drv->dev = dev;
0172
0173 drv->reg_phy = devm_platform_ioremap_resource(pdev, 0);
0174 if (IS_ERR(drv->reg_phy)) {
0175 dev_err(dev, "Failed to map register memory (phy)\n");
0176 return PTR_ERR(drv->reg_phy);
0177 }
0178
0179 drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
0180 "samsung,pmureg-phandle");
0181 if (IS_ERR(drv->reg_pmu)) {
0182 dev_err(dev, "Failed to map PMU registers (via syscon)\n");
0183 return PTR_ERR(drv->reg_pmu);
0184 }
0185
0186 if (drv->cfg->has_mode_switch) {
0187 drv->reg_sys = syscon_regmap_lookup_by_phandle(
0188 pdev->dev.of_node, "samsung,sysreg-phandle");
0189 if (IS_ERR(drv->reg_sys)) {
0190 dev_err(dev, "Failed to map system registers (via syscon)\n");
0191 return PTR_ERR(drv->reg_sys);
0192 }
0193 }
0194
0195 drv->clk = devm_clk_get(dev, "phy");
0196 if (IS_ERR(drv->clk)) {
0197 dev_err(dev, "Failed to get clock of phy controller\n");
0198 return PTR_ERR(drv->clk);
0199 }
0200
0201 drv->ref_clk = devm_clk_get(dev, "ref");
0202 if (IS_ERR(drv->ref_clk)) {
0203 dev_err(dev, "Failed to get reference clock for the phy controller\n");
0204 return PTR_ERR(drv->ref_clk);
0205 }
0206
0207 drv->ref_rate = clk_get_rate(drv->ref_clk);
0208 if (drv->cfg->rate_to_clk) {
0209 ret = drv->cfg->rate_to_clk(drv->ref_rate, &drv->ref_reg_val);
0210 if (ret)
0211 return ret;
0212 }
0213
0214 drv->vbus = devm_regulator_get(dev, "vbus");
0215 if (IS_ERR(drv->vbus)) {
0216 ret = PTR_ERR(drv->vbus);
0217 if (ret == -EPROBE_DEFER)
0218 return ret;
0219 drv->vbus = NULL;
0220 }
0221
0222 for (i = 0; i < drv->cfg->num_phys; i++) {
0223 char *label = drv->cfg->phys[i].label;
0224 struct samsung_usb2_phy_instance *p = &drv->instances[i];
0225
0226 dev_dbg(dev, "Creating phy \"%s\"\n", label);
0227 p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops);
0228 if (IS_ERR(p->phy)) {
0229 dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
0230 label);
0231 return PTR_ERR(p->phy);
0232 }
0233
0234 p->cfg = &drv->cfg->phys[i];
0235 p->drv = drv;
0236 phy_set_bus_width(p->phy, 8);
0237 phy_set_drvdata(p->phy, p);
0238 }
0239
0240 phy_provider = devm_of_phy_provider_register(dev,
0241 samsung_usb2_phy_xlate);
0242 if (IS_ERR(phy_provider)) {
0243 dev_err(drv->dev, "Failed to register phy provider\n");
0244 return PTR_ERR(phy_provider);
0245 }
0246
0247 return 0;
0248 }
0249
0250 static struct platform_driver samsung_usb2_phy_driver = {
0251 .probe = samsung_usb2_phy_probe,
0252 .driver = {
0253 .of_match_table = samsung_usb2_phy_of_match,
0254 .name = "samsung-usb2-phy",
0255 .suppress_bind_attrs = true,
0256 }
0257 };
0258
0259 module_platform_driver(samsung_usb2_phy_driver);
0260 MODULE_DESCRIPTION("Samsung S5P/Exynos SoC USB PHY driver");
0261 MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
0262 MODULE_LICENSE("GPL v2");
0263 MODULE_ALIAS("platform:samsung-usb2-phy");