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

ehci-atmel.c (6298B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Driver for EHCI UHP on Atmel chips
      4 *
      5 *  Copyright (C) 2009 Atmel Corporation,
      6 *                     Nicolas Ferre <nicolas.ferre@atmel.com>
      7 *
      8 *  Based on various ehci-*.c drivers
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/io.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/of.h>
     17#include <linux/of_platform.h>
     18#include <linux/platform_device.h>
     19#include <linux/usb.h>
     20#include <linux/usb/hcd.h>
     21#include <linux/usb/phy.h>
     22#include <linux/usb/of.h>
     23
     24#include "ehci.h"
     25
     26#define DRIVER_DESC "EHCI Atmel driver"
     27
     28static const char hcd_name[] = "ehci-atmel";
     29
     30#define EHCI_INSNREG(index)			((index) * 4 + 0x90)
     31#define EHCI_INSNREG08_HSIC_EN			BIT(2)
     32
     33/* interface and function clocks */
     34#define hcd_to_atmel_ehci_priv(h) \
     35	((struct atmel_ehci_priv *)hcd_to_ehci(h)->priv)
     36
     37struct atmel_ehci_priv {
     38	struct clk *iclk;
     39	struct clk *uclk;
     40	bool clocked;
     41};
     42
     43static struct hc_driver __read_mostly ehci_atmel_hc_driver;
     44
     45static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst = {
     46	.extra_priv_size = sizeof(struct atmel_ehci_priv),
     47};
     48
     49/*-------------------------------------------------------------------------*/
     50
     51static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
     52{
     53	if (atmel_ehci->clocked)
     54		return;
     55
     56	clk_prepare_enable(atmel_ehci->uclk);
     57	clk_prepare_enable(atmel_ehci->iclk);
     58	atmel_ehci->clocked = true;
     59}
     60
     61static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
     62{
     63	if (!atmel_ehci->clocked)
     64		return;
     65
     66	clk_disable_unprepare(atmel_ehci->iclk);
     67	clk_disable_unprepare(atmel_ehci->uclk);
     68	atmel_ehci->clocked = false;
     69}
     70
     71static void atmel_start_ehci(struct platform_device *pdev)
     72{
     73	struct usb_hcd *hcd = platform_get_drvdata(pdev);
     74	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
     75
     76	dev_dbg(&pdev->dev, "start\n");
     77	atmel_start_clock(atmel_ehci);
     78}
     79
     80static void atmel_stop_ehci(struct platform_device *pdev)
     81{
     82	struct usb_hcd *hcd = platform_get_drvdata(pdev);
     83	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
     84
     85	dev_dbg(&pdev->dev, "stop\n");
     86	atmel_stop_clock(atmel_ehci);
     87}
     88
     89/*-------------------------------------------------------------------------*/
     90
     91static int ehci_atmel_drv_probe(struct platform_device *pdev)
     92{
     93	struct usb_hcd *hcd;
     94	const struct hc_driver *driver = &ehci_atmel_hc_driver;
     95	struct resource *res;
     96	struct ehci_hcd *ehci;
     97	struct atmel_ehci_priv *atmel_ehci;
     98	int irq;
     99	int retval;
    100
    101	if (usb_disabled())
    102		return -ENODEV;
    103
    104	pr_debug("Initializing Atmel-SoC USB Host Controller\n");
    105
    106	irq = platform_get_irq(pdev, 0);
    107	if (irq <= 0) {
    108		retval = -ENODEV;
    109		goto fail_create_hcd;
    110	}
    111
    112	/* Right now device-tree probed devices don't get dma_mask set.
    113	 * Since shared usb code relies on it, set it here for now.
    114	 * Once we have dma capability bindings this can go away.
    115	 */
    116	retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
    117	if (retval)
    118		goto fail_create_hcd;
    119
    120	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
    121	if (!hcd) {
    122		retval = -ENOMEM;
    123		goto fail_create_hcd;
    124	}
    125	atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
    126
    127	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    128	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
    129	if (IS_ERR(hcd->regs)) {
    130		retval = PTR_ERR(hcd->regs);
    131		goto fail_request_resource;
    132	}
    133
    134	hcd->rsrc_start = res->start;
    135	hcd->rsrc_len = resource_size(res);
    136
    137	atmel_ehci->iclk = devm_clk_get(&pdev->dev, "ehci_clk");
    138	if (IS_ERR(atmel_ehci->iclk)) {
    139		dev_err(&pdev->dev, "Error getting interface clock\n");
    140		retval = -ENOENT;
    141		goto fail_request_resource;
    142	}
    143
    144	atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
    145	if (IS_ERR(atmel_ehci->uclk)) {
    146		dev_err(&pdev->dev, "failed to get uclk\n");
    147		retval = PTR_ERR(atmel_ehci->uclk);
    148		goto fail_request_resource;
    149	}
    150
    151	ehci = hcd_to_ehci(hcd);
    152	/* registers start at offset 0x0 */
    153	ehci->caps = hcd->regs;
    154
    155	atmel_start_ehci(pdev);
    156
    157	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
    158	if (retval)
    159		goto fail_add_hcd;
    160	device_wakeup_enable(hcd->self.controller);
    161
    162	if (of_usb_get_phy_mode(pdev->dev.of_node) == USBPHY_INTERFACE_MODE_HSIC)
    163		writel(EHCI_INSNREG08_HSIC_EN, hcd->regs + EHCI_INSNREG(8));
    164
    165	return retval;
    166
    167fail_add_hcd:
    168	atmel_stop_ehci(pdev);
    169fail_request_resource:
    170	usb_put_hcd(hcd);
    171fail_create_hcd:
    172	dev_err(&pdev->dev, "init %s fail, %d\n",
    173		dev_name(&pdev->dev), retval);
    174
    175	return retval;
    176}
    177
    178static int ehci_atmel_drv_remove(struct platform_device *pdev)
    179{
    180	struct usb_hcd *hcd = platform_get_drvdata(pdev);
    181
    182	usb_remove_hcd(hcd);
    183	usb_put_hcd(hcd);
    184
    185	atmel_stop_ehci(pdev);
    186
    187	return 0;
    188}
    189
    190static int __maybe_unused ehci_atmel_drv_suspend(struct device *dev)
    191{
    192	struct usb_hcd *hcd = dev_get_drvdata(dev);
    193	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
    194	int ret;
    195
    196	ret = ehci_suspend(hcd, false);
    197	if (ret)
    198		return ret;
    199
    200	atmel_stop_clock(atmel_ehci);
    201	return 0;
    202}
    203
    204static int __maybe_unused ehci_atmel_drv_resume(struct device *dev)
    205{
    206	struct usb_hcd *hcd = dev_get_drvdata(dev);
    207	struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
    208
    209	atmel_start_clock(atmel_ehci);
    210	ehci_resume(hcd, false);
    211	return 0;
    212}
    213
    214#ifdef CONFIG_OF
    215static const struct of_device_id atmel_ehci_dt_ids[] = {
    216	{ .compatible = "atmel,at91sam9g45-ehci" },
    217	{ /* sentinel */ }
    218};
    219
    220MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
    221#endif
    222
    223static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
    224					ehci_atmel_drv_resume);
    225
    226static struct platform_driver ehci_atmel_driver = {
    227	.probe		= ehci_atmel_drv_probe,
    228	.remove		= ehci_atmel_drv_remove,
    229	.shutdown	= usb_hcd_platform_shutdown,
    230	.driver		= {
    231		.name	= "atmel-ehci",
    232		.pm	= &ehci_atmel_pm_ops,
    233		.of_match_table	= of_match_ptr(atmel_ehci_dt_ids),
    234	},
    235};
    236
    237static int __init ehci_atmel_init(void)
    238{
    239	if (usb_disabled())
    240		return -ENODEV;
    241
    242	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
    243	ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides);
    244	return platform_driver_register(&ehci_atmel_driver);
    245}
    246module_init(ehci_atmel_init);
    247
    248static void __exit ehci_atmel_cleanup(void)
    249{
    250	platform_driver_unregister(&ehci_atmel_driver);
    251}
    252module_exit(ehci_atmel_cleanup);
    253
    254MODULE_DESCRIPTION(DRIVER_DESC);
    255MODULE_ALIAS("platform:atmel-ehci");
    256MODULE_AUTHOR("Nicolas Ferre");
    257MODULE_LICENSE("GPL");