1 // SPDX-License-Identifier: GPL-2.0
3 * Nuvoton NPCM7xx driver for EHCI HCD
5 * Copyright (C) 2018 Nuvoton Technologies,
6 * Avi Fishman <avi.fishman@nuvoton.com> <avifishman70@gmail.com>
7 * Tomer Maimon <tomer.maimon@nuvoton.com> <tmaimon77@gmail.com>
9 * Based on various ehci-spear.c driver
13 #include <linux/dma-mapping.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
18 #include <linux/platform_device.h>
20 #include <linux/usb.h>
21 #include <linux/usb/hcd.h>
25 #include <linux/regmap.h>
26 #include <linux/mfd/syscon.h>
28 #define DRIVER_DESC "EHCI npcm7xx driver"
30 static const char hcd_name
[] = "npcm7xx-ehci";
32 #define USB2PHYCTL_OFFSET 0x144
34 #define IPSRST2_OFFSET 0x24
35 #define IPSRST3_OFFSET 0x34
38 static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver
;
40 static int __maybe_unused
ehci_npcm7xx_drv_suspend(struct device
*dev
)
42 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
43 bool do_wakeup
= device_may_wakeup(dev
);
45 return ehci_suspend(hcd
, do_wakeup
);
48 static int __maybe_unused
ehci_npcm7xx_drv_resume(struct device
*dev
)
50 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
52 ehci_resume(hcd
, false);
56 static SIMPLE_DEV_PM_OPS(ehci_npcm7xx_pm_ops
, ehci_npcm7xx_drv_suspend
,
57 ehci_npcm7xx_drv_resume
);
59 static int npcm7xx_ehci_hcd_drv_probe(struct platform_device
*pdev
)
63 struct regmap
*gcr_regmap
;
64 struct regmap
*rst_regmap
;
65 const struct hc_driver
*driver
= &ehci_npcm7xx_hc_driver
;
69 dev_dbg(&pdev
->dev
, "initializing npcm7xx ehci USB Controller\n");
71 gcr_regmap
= syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
72 if (IS_ERR(gcr_regmap
)) {
73 dev_err(&pdev
->dev
, "%s: failed to find nuvoton,npcm750-gcr\n",
75 return PTR_ERR(gcr_regmap
);
78 rst_regmap
= syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
79 if (IS_ERR(rst_regmap
)) {
80 dev_err(&pdev
->dev
, "%s: failed to find nuvoton,npcm750-rst\n",
82 return PTR_ERR(rst_regmap
);
85 /********* phy init ******/
87 regmap_update_bits(rst_regmap
, IPSRST2_OFFSET
,
88 (0x1 << 26), (0x1 << 26));
89 regmap_update_bits(rst_regmap
, IPSRST3_OFFSET
,
90 (0x1 << 25), (0x1 << 25));
91 regmap_update_bits(gcr_regmap
, USB2PHYCTL_OFFSET
,
97 regmap_update_bits(rst_regmap
, IPSRST3_OFFSET
,
100 udelay(50); // enable phy
102 regmap_update_bits(gcr_regmap
, USB2PHYCTL_OFFSET
,
103 (0x1 << 28), (0x1 << 28));
106 regmap_update_bits(rst_regmap
, IPSRST2_OFFSET
,
112 irq
= platform_get_irq(pdev
, 0);
119 * Right now device-tree probed devices don't get dma_mask set.
120 * Since shared usb code relies on it, set it here for now.
121 * Once we have dma capability bindings this can go away.
123 retval
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
127 hcd
= usb_create_hcd(driver
, &pdev
->dev
, dev_name(&pdev
->dev
));
133 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
134 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
135 if (IS_ERR(hcd
->regs
)) {
136 retval
= PTR_ERR(hcd
->regs
);
139 hcd
->rsrc_start
= res
->start
;
140 hcd
->rsrc_len
= resource_size(res
);
142 /* registers start at offset 0x0 */
143 hcd_to_ehci(hcd
)->caps
= hcd
->regs
;
145 retval
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
149 device_wakeup_enable(hcd
->self
.controller
);
155 dev_err(&pdev
->dev
, "init fail, %d\n", retval
);
160 static int npcm7xx_ehci_hcd_drv_remove(struct platform_device
*pdev
)
162 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
171 static const struct of_device_id npcm7xx_ehci_id_table
[] = {
172 { .compatible
= "nuvoton,npcm750-ehci" },
175 MODULE_DEVICE_TABLE(of
, npcm7xx_ehci_id_table
);
177 static struct platform_driver npcm7xx_ehci_hcd_driver
= {
178 .probe
= npcm7xx_ehci_hcd_drv_probe
,
179 .remove
= npcm7xx_ehci_hcd_drv_remove
,
180 .shutdown
= usb_hcd_platform_shutdown
,
182 .name
= "npcm7xx-ehci",
183 .bus
= &platform_bus_type
,
184 .pm
= pm_ptr(&ehci_npcm7xx_pm_ops
),
185 .of_match_table
= npcm7xx_ehci_id_table
,
189 static int __init
ehci_npcm7xx_init(void)
194 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
196 ehci_init_driver(&ehci_npcm7xx_hc_driver
, NULL
);
197 return platform_driver_register(&npcm7xx_ehci_hcd_driver
);
199 module_init(ehci_npcm7xx_init
);
201 static void __exit
ehci_npcm7xx_cleanup(void)
203 platform_driver_unregister(&npcm7xx_ehci_hcd_driver
);
205 module_exit(ehci_npcm7xx_cleanup
);
207 MODULE_DESCRIPTION(DRIVER_DESC
);
208 MODULE_ALIAS("platform:npcm7xx-ehci");
209 MODULE_AUTHOR("Avi Fishman");
210 MODULE_LICENSE("GPL v2");