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

ohci-exynos.c (7667B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * SAMSUNG EXYNOS USB HOST OHCI Controller
      4 *
      5 * Copyright (C) 2011 Samsung Electronics Co.Ltd
      6 * Author: Jingoo Han <jg1.han@samsung.com>
      7 */
      8
      9#include <linux/clk.h>
     10#include <linux/dma-mapping.h>
     11#include <linux/io.h>
     12#include <linux/kernel.h>
     13#include <linux/module.h>
     14#include <linux/of.h>
     15#include <linux/platform_device.h>
     16#include <linux/phy/phy.h>
     17#include <linux/usb.h>
     18#include <linux/usb/hcd.h>
     19
     20#include "ohci.h"
     21
     22#define DRIVER_DESC "OHCI Exynos driver"
     23
     24static const char hcd_name[] = "ohci-exynos";
     25static struct hc_driver __read_mostly exynos_ohci_hc_driver;
     26
     27#define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv)
     28
     29#define PHY_NUMBER 3
     30
     31struct exynos_ohci_hcd {
     32	struct clk *clk;
     33	struct device_node *of_node;
     34	struct phy *phy[PHY_NUMBER];
     35	bool legacy_phy;
     36};
     37
     38static int exynos_ohci_get_phy(struct device *dev,
     39				struct exynos_ohci_hcd *exynos_ohci)
     40{
     41	struct device_node *child;
     42	struct phy *phy;
     43	int phy_number, num_phys;
     44	int ret;
     45
     46	/* Get PHYs for the controller */
     47	num_phys = of_count_phandle_with_args(dev->of_node, "phys",
     48					      "#phy-cells");
     49	for (phy_number = 0; phy_number < num_phys; phy_number++) {
     50		phy = devm_of_phy_get_by_index(dev, dev->of_node, phy_number);
     51		if (IS_ERR(phy))
     52			return PTR_ERR(phy);
     53		exynos_ohci->phy[phy_number] = phy;
     54	}
     55	if (num_phys > 0)
     56		return 0;
     57
     58	/* Get PHYs using legacy bindings */
     59	for_each_available_child_of_node(dev->of_node, child) {
     60		ret = of_property_read_u32(child, "reg", &phy_number);
     61		if (ret) {
     62			dev_err(dev, "Failed to parse device tree\n");
     63			of_node_put(child);
     64			return ret;
     65		}
     66
     67		if (phy_number >= PHY_NUMBER) {
     68			dev_err(dev, "Invalid number of PHYs\n");
     69			of_node_put(child);
     70			return -EINVAL;
     71		}
     72
     73		phy = devm_of_phy_get(dev, child, NULL);
     74		exynos_ohci->phy[phy_number] = phy;
     75		if (IS_ERR(phy)) {
     76			ret = PTR_ERR(phy);
     77			if (ret == -EPROBE_DEFER) {
     78				of_node_put(child);
     79				return ret;
     80			} else if (ret != -ENOSYS && ret != -ENODEV) {
     81				dev_err(dev,
     82					"Error retrieving usb2 phy: %d\n", ret);
     83				of_node_put(child);
     84				return ret;
     85			}
     86		}
     87	}
     88
     89	exynos_ohci->legacy_phy = true;
     90	return 0;
     91}
     92
     93static int exynos_ohci_phy_enable(struct device *dev)
     94{
     95	struct usb_hcd *hcd = dev_get_drvdata(dev);
     96	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
     97	int i;
     98	int ret = 0;
     99
    100	for (i = 0; ret == 0 && i < PHY_NUMBER; i++)
    101		if (!IS_ERR(exynos_ohci->phy[i]))
    102			ret = phy_power_on(exynos_ohci->phy[i]);
    103	if (ret)
    104		for (i--; i >= 0; i--)
    105			if (!IS_ERR(exynos_ohci->phy[i]))
    106				phy_power_off(exynos_ohci->phy[i]);
    107
    108	return ret;
    109}
    110
    111static void exynos_ohci_phy_disable(struct device *dev)
    112{
    113	struct usb_hcd *hcd = dev_get_drvdata(dev);
    114	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
    115	int i;
    116
    117	for (i = 0; i < PHY_NUMBER; i++)
    118		if (!IS_ERR(exynos_ohci->phy[i]))
    119			phy_power_off(exynos_ohci->phy[i]);
    120}
    121
    122static int exynos_ohci_probe(struct platform_device *pdev)
    123{
    124	struct exynos_ohci_hcd *exynos_ohci;
    125	struct usb_hcd *hcd;
    126	struct resource *res;
    127	int irq;
    128	int err;
    129
    130	/*
    131	 * Right now device-tree probed devices don't get dma_mask set.
    132	 * Since shared usb code relies on it, set it here for now.
    133	 * Once we move to full device tree support this will vanish off.
    134	 */
    135	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
    136	if (err)
    137		return err;
    138
    139	hcd = usb_create_hcd(&exynos_ohci_hc_driver,
    140				&pdev->dev, dev_name(&pdev->dev));
    141	if (!hcd) {
    142		dev_err(&pdev->dev, "Unable to create HCD\n");
    143		return -ENOMEM;
    144	}
    145
    146	exynos_ohci = to_exynos_ohci(hcd);
    147
    148	err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci);
    149	if (err)
    150		goto fail_clk;
    151
    152	exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost");
    153
    154	if (IS_ERR(exynos_ohci->clk)) {
    155		dev_err(&pdev->dev, "Failed to get usbhost clock\n");
    156		err = PTR_ERR(exynos_ohci->clk);
    157		goto fail_clk;
    158	}
    159
    160	err = clk_prepare_enable(exynos_ohci->clk);
    161	if (err)
    162		goto fail_clk;
    163
    164	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    165	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
    166	if (IS_ERR(hcd->regs)) {
    167		err = PTR_ERR(hcd->regs);
    168		goto fail_io;
    169	}
    170	hcd->rsrc_start = res->start;
    171	hcd->rsrc_len = resource_size(res);
    172
    173	irq = platform_get_irq(pdev, 0);
    174	if (irq < 0) {
    175		err = irq;
    176		goto fail_io;
    177	}
    178
    179	platform_set_drvdata(pdev, hcd);
    180
    181	err = exynos_ohci_phy_enable(&pdev->dev);
    182	if (err) {
    183		dev_err(&pdev->dev, "Failed to enable USB phy\n");
    184		goto fail_io;
    185	}
    186
    187	/*
    188	 * Workaround: reset of_node pointer to avoid conflict between legacy
    189	 * Exynos OHCI port subnodes and generic USB device bindings
    190	 */
    191	exynos_ohci->of_node = pdev->dev.of_node;
    192	if (exynos_ohci->legacy_phy)
    193		pdev->dev.of_node = NULL;
    194
    195	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
    196	if (err) {
    197		dev_err(&pdev->dev, "Failed to add USB HCD\n");
    198		goto fail_add_hcd;
    199	}
    200	device_wakeup_enable(hcd->self.controller);
    201	return 0;
    202
    203fail_add_hcd:
    204	exynos_ohci_phy_disable(&pdev->dev);
    205	pdev->dev.of_node = exynos_ohci->of_node;
    206fail_io:
    207	clk_disable_unprepare(exynos_ohci->clk);
    208fail_clk:
    209	usb_put_hcd(hcd);
    210	return err;
    211}
    212
    213static int exynos_ohci_remove(struct platform_device *pdev)
    214{
    215	struct usb_hcd *hcd = platform_get_drvdata(pdev);
    216	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
    217
    218	pdev->dev.of_node = exynos_ohci->of_node;
    219
    220	usb_remove_hcd(hcd);
    221
    222	exynos_ohci_phy_disable(&pdev->dev);
    223
    224	clk_disable_unprepare(exynos_ohci->clk);
    225
    226	usb_put_hcd(hcd);
    227
    228	return 0;
    229}
    230
    231static void exynos_ohci_shutdown(struct platform_device *pdev)
    232{
    233	struct usb_hcd *hcd = platform_get_drvdata(pdev);
    234
    235	if (hcd->driver->shutdown)
    236		hcd->driver->shutdown(hcd);
    237}
    238
    239#ifdef CONFIG_PM
    240static int exynos_ohci_suspend(struct device *dev)
    241{
    242	struct usb_hcd *hcd = dev_get_drvdata(dev);
    243	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);
    244	bool do_wakeup = device_may_wakeup(dev);
    245	int rc = ohci_suspend(hcd, do_wakeup);
    246
    247	if (rc)
    248		return rc;
    249
    250	exynos_ohci_phy_disable(dev);
    251
    252	clk_disable_unprepare(exynos_ohci->clk);
    253
    254	return 0;
    255}
    256
    257static int exynos_ohci_resume(struct device *dev)
    258{
    259	struct usb_hcd *hcd			= dev_get_drvdata(dev);
    260	struct exynos_ohci_hcd *exynos_ohci	= to_exynos_ohci(hcd);
    261	int ret;
    262
    263	clk_prepare_enable(exynos_ohci->clk);
    264
    265	ret = exynos_ohci_phy_enable(dev);
    266	if (ret) {
    267		dev_err(dev, "Failed to enable USB phy\n");
    268		clk_disable_unprepare(exynos_ohci->clk);
    269		return ret;
    270	}
    271
    272	ohci_resume(hcd, false);
    273
    274	return 0;
    275}
    276#else
    277#define exynos_ohci_suspend	NULL
    278#define exynos_ohci_resume	NULL
    279#endif
    280
    281static const struct ohci_driver_overrides exynos_overrides __initconst = {
    282	.extra_priv_size =	sizeof(struct exynos_ohci_hcd),
    283};
    284
    285static const struct dev_pm_ops exynos_ohci_pm_ops = {
    286	.suspend	= exynos_ohci_suspend,
    287	.resume		= exynos_ohci_resume,
    288};
    289
    290#ifdef CONFIG_OF
    291static const struct of_device_id exynos_ohci_match[] = {
    292	{ .compatible = "samsung,exynos4210-ohci" },
    293	{},
    294};
    295MODULE_DEVICE_TABLE(of, exynos_ohci_match);
    296#endif
    297
    298static struct platform_driver exynos_ohci_driver = {
    299	.probe		= exynos_ohci_probe,
    300	.remove		= exynos_ohci_remove,
    301	.shutdown	= exynos_ohci_shutdown,
    302	.driver = {
    303		.name	= "exynos-ohci",
    304		.pm	= &exynos_ohci_pm_ops,
    305		.of_match_table	= of_match_ptr(exynos_ohci_match),
    306	}
    307};
    308static int __init ohci_exynos_init(void)
    309{
    310	if (usb_disabled())
    311		return -ENODEV;
    312
    313	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
    314	ohci_init_driver(&exynos_ohci_hc_driver, &exynos_overrides);
    315	return platform_driver_register(&exynos_ohci_driver);
    316}
    317module_init(ohci_exynos_init);
    318
    319static void __exit ohci_exynos_cleanup(void)
    320{
    321	platform_driver_unregister(&exynos_ohci_driver);
    322}
    323module_exit(ohci_exynos_cleanup);
    324
    325MODULE_ALIAS("platform:exynos-ohci");
    326MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
    327MODULE_LICENSE("GPL v2");