blob: 274ac0b1f936e1064acb723ca5825d816c8cd94c [file] [log] [blame]
/*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is"
* without any warranty of any kind, whether express or implied.
*/
#include <dt-bindings/phy/phy.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
struct ls1024a_usb3_phy {
struct phy *phy;
void __iomem *reg;
struct reset_control *rstc;
};
static int ls1024a_usb_phy_init(struct phy *phy)
{
struct ls1024a_usb3_phy *lu_phy;
u32 val;
lu_phy = phy_get_drvdata(phy);
if (!lu_phy)
return -ENODEV;
if (!reset_control_status(lu_phy->rstc)) {
reset_control_assert(lu_phy->rstc);
udelay(1000);
}
writel(0x00E00080, lu_phy->reg + 0x10);
/* TODO: Support 48 MHz refclock and external clock */
#if 0
//Configuration for internal clock
if(usb3_clk_internal)
{
printk(KERN_INFO "USB3.0 clock selected: internal\n", __func__);
if(HAL_get_ref_clk() == REF_CLK_24MHZ)
#endif
val = 0x420E82A8;
#if 0
else
val = 0x420E82A9;
}
else
{
val = 0x4209927A;
printk(KERN_INFO "USB3.0 clock selected: external\n", __func__);
}
#endif
writel(val, lu_phy->reg + 0x20);
writel(0x69C34F53, lu_phy->reg + 0x24);
writel(0x0005D815, lu_phy->reg + 0x28);
writel(0x00000801, lu_phy->reg + 0x2C);
reset_control_deassert(lu_phy->rstc);
udelay(1000);
return 0;
}
static struct phy_ops ls1024a_usb_phy_ops = {
.init = ls1024a_usb_phy_init,
.owner = THIS_MODULE,
};
static int ls1024a_usb_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *reg;
struct reset_control *rstc;
struct resource *res;
struct ls1024a_usb3_phy *lu_phy;
lu_phy = devm_kzalloc(dev, sizeof(*lu_phy), GFP_KERNEL);
if (!lu_phy)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(reg))
return PTR_ERR(reg);
rstc = devm_reset_control_get(&pdev->dev, "phy");
if (IS_ERR(rstc))
return PTR_ERR(rstc);
phy = devm_phy_create(dev, NULL, &ls1024a_usb_phy_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
lu_phy->phy = phy;
lu_phy->reg = reg;
lu_phy->rstc = rstc;
dev_set_drvdata(dev, lu_phy);
phy_set_drvdata(phy, lu_phy);
phy_provider = devm_of_phy_provider_register(&pdev->dev,
of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id phy_of_match[] = {
{ .compatible = "fsl,ls1024a-usb3-phy", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, phy_of_match);
static struct platform_driver ls1024a_usb_phy_driver = {
.probe = ls1024a_usb_phy_probe,
.driver = {
.of_match_table = phy_of_match,
.name = "ls1024a-usb3-phy",
.owner = THIS_MODULE,
}
};
module_platform_driver(ls1024a_usb_phy_driver);
MODULE_DESCRIPTION("Freescale QorIQ LS1024A USB3 PHY");
MODULE_AUTHOR("Daniel Mentz <danielmentz@google.com>");
MODULE_LICENSE("GPL v2");