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 #ifdef CONFIG_PM_SLEEP
41 static int ehci_npcm7xx_drv_suspend(struct device
*dev
)
43 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
44 bool do_wakeup
= device_may_wakeup(dev
);
46 return ehci_suspend(hcd
, do_wakeup
);
49 static int ehci_npcm7xx_drv_resume(struct device
*dev
)
51 struct usb_hcd
*hcd
= dev_get_drvdata(dev
);
53 ehci_resume(hcd
, false);
56 #endif /* CONFIG_PM_SLEEP */
58 static SIMPLE_DEV_PM_OPS(ehci_npcm7xx_pm_ops
, ehci_npcm7xx_drv_suspend
,
59 ehci_npcm7xx_drv_resume
);
61 static int npcm7xx_ehci_hcd_drv_probe(struct platform_device
*pdev
)
65 struct regmap
*gcr_regmap
;
66 struct regmap
*rst_regmap
;
67 const struct hc_driver
*driver
= &ehci_npcm7xx_hc_driver
;
71 dev_dbg(&pdev
->dev
, "initializing npcm7xx ehci USB Controller\n");
73 gcr_regmap
= syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
74 if (IS_ERR(gcr_regmap
)) {
75 dev_err(&pdev
->dev
, "%s: failed to find nuvoton,npcm750-gcr\n",
77 return PTR_ERR(gcr_regmap
);
80 rst_regmap
= syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
81 if (IS_ERR(rst_regmap
)) {
82 dev_err(&pdev
->dev
, "%s: failed to find nuvoton,npcm750-rst\n",
84 return PTR_ERR(rst_regmap
);
87 /********* phy init ******/
89 regmap_update_bits(rst_regmap
, IPSRST2_OFFSET
,
90 (0x1 << 26), (0x1 << 26));
91 regmap_update_bits(rst_regmap
, IPSRST3_OFFSET
,
92 (0x1 << 25), (0x1 << 25));
93 regmap_update_bits(gcr_regmap
, USB2PHYCTL_OFFSET
,
99 regmap_update_bits(rst_regmap
, IPSRST3_OFFSET
,
102 udelay(50); // enable phy
104 regmap_update_bits(gcr_regmap
, USB2PHYCTL_OFFSET
,
105 (0x1 << 28), (0x1 << 28));
108 regmap_update_bits(rst_regmap
, IPSRST2_OFFSET
,
114 irq
= platform_get_irq(pdev
, 0);
121 * Right now device-tree probed devices don't get dma_mask set.
122 * Since shared usb code relies on it, set it here for now.
123 * Once we have dma capability bindings this can go away.
125 retval
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
129 hcd
= usb_create_hcd(driver
, &pdev
->dev
, dev_name(&pdev
->dev
));
135 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
136 hcd
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
137 if (IS_ERR(hcd
->regs
)) {
138 retval
= PTR_ERR(hcd
->regs
);
141 hcd
->rsrc_start
= res
->start
;
142 hcd
->rsrc_len
= resource_size(res
);
144 /* registers start at offset 0x0 */
145 hcd_to_ehci(hcd
)->caps
= hcd
->regs
;
147 retval
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
151 device_wakeup_enable(hcd
->self
.controller
);
157 dev_err(&pdev
->dev
, "init fail, %d\n", retval
);
162 static int npcm7xx_ehci_hcd_drv_remove(struct platform_device
*pdev
)
164 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
173 static const struct of_device_id npcm7xx_ehci_id_table
[] = {
174 { .compatible
= "nuvoton,npcm750-ehci" },
177 MODULE_DEVICE_TABLE(of
, npcm7xx_ehci_id_table
);
179 static struct platform_driver npcm7xx_ehci_hcd_driver
= {
180 .probe
= npcm7xx_ehci_hcd_drv_probe
,
181 .remove
= npcm7xx_ehci_hcd_drv_remove
,
182 .shutdown
= usb_hcd_platform_shutdown
,
184 .name
= "npcm7xx-ehci",
185 .bus
= &platform_bus_type
,
186 .pm
= &ehci_npcm7xx_pm_ops
,
187 .of_match_table
= npcm7xx_ehci_id_table
,
191 static int __init
ehci_npcm7xx_init(void)
196 pr_info("%s: " DRIVER_DESC
"\n", hcd_name
);
198 ehci_init_driver(&ehci_npcm7xx_hc_driver
, NULL
);
199 return platform_driver_register(&npcm7xx_ehci_hcd_driver
);
201 module_init(ehci_npcm7xx_init
);
203 static void __exit
ehci_npcm7xx_cleanup(void)
205 platform_driver_unregister(&npcm7xx_ehci_hcd_driver
);
207 module_exit(ehci_npcm7xx_cleanup
);
209 MODULE_DESCRIPTION(DRIVER_DESC
);
210 MODULE_ALIAS("platform:npcm7xx-ehci");
211 MODULE_AUTHOR("Avi Fishman");
212 MODULE_LICENSE("GPL v2");