cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-sun9i-usb.c (4565B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Allwinner sun9i USB phy driver
      4 *
      5 * Copyright (C) 2014-2015 Chen-Yu Tsai <wens@csie.org>
      6 *
      7 * Based on phy-sun4i-usb.c from
      8 * Hans de Goede <hdegoede@redhat.com>
      9 *
     10 * and code from
     11 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
     12 */
     13
     14#include <linux/clk.h>
     15#include <linux/err.h>
     16#include <linux/io.h>
     17#include <linux/module.h>
     18#include <linux/phy/phy.h>
     19#include <linux/usb/of.h>
     20#include <linux/platform_device.h>
     21#include <linux/reset.h>
     22
     23#define SUNXI_AHB_INCR16_BURST_EN	BIT(11)
     24#define SUNXI_AHB_INCR8_BURST_EN	BIT(10)
     25#define SUNXI_AHB_INCR4_BURST_EN	BIT(9)
     26#define SUNXI_AHB_INCRX_ALIGN_EN	BIT(8)
     27#define SUNXI_ULPI_BYPASS_EN		BIT(0)
     28
     29/* usb1 HSIC specific bits */
     30#define SUNXI_EHCI_HS_FORCE		BIT(20)
     31#define SUNXI_HSIC_CONNECT_DET		BIT(17)
     32#define SUNXI_HSIC_CONNECT_INT		BIT(16)
     33#define SUNXI_HSIC			BIT(1)
     34
     35struct sun9i_usb_phy {
     36	struct phy *phy;
     37	void __iomem *pmu;
     38	struct reset_control *reset;
     39	struct clk *clk;
     40	struct clk *hsic_clk;
     41	enum usb_phy_interface type;
     42};
     43
     44static void sun9i_usb_phy_passby(struct sun9i_usb_phy *phy, int enable)
     45{
     46	u32 bits, reg_value;
     47
     48	bits = SUNXI_AHB_INCR16_BURST_EN | SUNXI_AHB_INCR8_BURST_EN |
     49		SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN |
     50		SUNXI_ULPI_BYPASS_EN;
     51
     52	if (phy->type == USBPHY_INTERFACE_MODE_HSIC)
     53		bits |= SUNXI_HSIC | SUNXI_EHCI_HS_FORCE |
     54			SUNXI_HSIC_CONNECT_DET | SUNXI_HSIC_CONNECT_INT;
     55
     56	reg_value = readl(phy->pmu);
     57
     58	if (enable)
     59		reg_value |= bits;
     60	else
     61		reg_value &= ~bits;
     62
     63	writel(reg_value, phy->pmu);
     64}
     65
     66static int sun9i_usb_phy_init(struct phy *_phy)
     67{
     68	struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
     69	int ret;
     70
     71	ret = clk_prepare_enable(phy->clk);
     72	if (ret)
     73		goto err_clk;
     74
     75	ret = clk_prepare_enable(phy->hsic_clk);
     76	if (ret)
     77		goto err_hsic_clk;
     78
     79	ret = reset_control_deassert(phy->reset);
     80	if (ret)
     81		goto err_reset;
     82
     83	sun9i_usb_phy_passby(phy, 1);
     84	return 0;
     85
     86err_reset:
     87	clk_disable_unprepare(phy->hsic_clk);
     88
     89err_hsic_clk:
     90	clk_disable_unprepare(phy->clk);
     91
     92err_clk:
     93	return ret;
     94}
     95
     96static int sun9i_usb_phy_exit(struct phy *_phy)
     97{
     98	struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
     99
    100	sun9i_usb_phy_passby(phy, 0);
    101	reset_control_assert(phy->reset);
    102	clk_disable_unprepare(phy->hsic_clk);
    103	clk_disable_unprepare(phy->clk);
    104
    105	return 0;
    106}
    107
    108static const struct phy_ops sun9i_usb_phy_ops = {
    109	.init		= sun9i_usb_phy_init,
    110	.exit		= sun9i_usb_phy_exit,
    111	.owner		= THIS_MODULE,
    112};
    113
    114static int sun9i_usb_phy_probe(struct platform_device *pdev)
    115{
    116	struct sun9i_usb_phy *phy;
    117	struct device *dev = &pdev->dev;
    118	struct device_node *np = dev->of_node;
    119	struct phy_provider *phy_provider;
    120
    121	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
    122	if (!phy)
    123		return -ENOMEM;
    124
    125	phy->type = of_usb_get_phy_mode(np);
    126	if (phy->type == USBPHY_INTERFACE_MODE_HSIC) {
    127		phy->clk = devm_clk_get(dev, "hsic_480M");
    128		if (IS_ERR(phy->clk)) {
    129			dev_err(dev, "failed to get hsic_480M clock\n");
    130			return PTR_ERR(phy->clk);
    131		}
    132
    133		phy->hsic_clk = devm_clk_get(dev, "hsic_12M");
    134		if (IS_ERR(phy->hsic_clk)) {
    135			dev_err(dev, "failed to get hsic_12M clock\n");
    136			return PTR_ERR(phy->hsic_clk);
    137		}
    138
    139		phy->reset = devm_reset_control_get(dev, "hsic");
    140		if (IS_ERR(phy->reset)) {
    141			dev_err(dev, "failed to get reset control\n");
    142			return PTR_ERR(phy->reset);
    143		}
    144	} else {
    145		phy->clk = devm_clk_get(dev, "phy");
    146		if (IS_ERR(phy->clk)) {
    147			dev_err(dev, "failed to get phy clock\n");
    148			return PTR_ERR(phy->clk);
    149		}
    150
    151		phy->reset = devm_reset_control_get(dev, "phy");
    152		if (IS_ERR(phy->reset)) {
    153			dev_err(dev, "failed to get reset control\n");
    154			return PTR_ERR(phy->reset);
    155		}
    156	}
    157
    158	phy->pmu = devm_platform_ioremap_resource(pdev, 0);
    159	if (IS_ERR(phy->pmu))
    160		return PTR_ERR(phy->pmu);
    161
    162	phy->phy = devm_phy_create(dev, NULL, &sun9i_usb_phy_ops);
    163	if (IS_ERR(phy->phy)) {
    164		dev_err(dev, "failed to create PHY\n");
    165		return PTR_ERR(phy->phy);
    166	}
    167
    168	phy_set_drvdata(phy->phy, phy);
    169	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    170
    171	return PTR_ERR_OR_ZERO(phy_provider);
    172}
    173
    174static const struct of_device_id sun9i_usb_phy_of_match[] = {
    175	{ .compatible = "allwinner,sun9i-a80-usb-phy" },
    176	{ },
    177};
    178MODULE_DEVICE_TABLE(of, sun9i_usb_phy_of_match);
    179
    180static struct platform_driver sun9i_usb_phy_driver = {
    181	.probe	= sun9i_usb_phy_probe,
    182	.driver = {
    183		.of_match_table	= sun9i_usb_phy_of_match,
    184		.name  = "sun9i-usb-phy",
    185	}
    186};
    187module_platform_driver(sun9i_usb_phy_driver);
    188
    189MODULE_DESCRIPTION("Allwinner sun9i USB phy driver");
    190MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
    191MODULE_LICENSE("GPL");