1 #include <linux/kernel.h>
2 #include <linux/platform_device.h>
3 #include <linux/delay.h>
4 #include <linux/dma-mapping.h>
6 #include <linux/module.h>
7 #include <linux/slab.h>
11 #include <linux/of_gpio.h>
12 #include <linux/gpio.h>
13 #include "usbdev_rk.h"
14 #include "dwc_otg_regs.h"
16 static struct dwc_otg_control_usb *control_usb;
18 int dwc_otg_check_dpdm(void)
24 EXPORT_SYMBOL(dwc_otg_check_dpdm);
26 #ifdef CONFIG_USB20_OTG
28 void usb20otg_hw_init(void)
30 #ifndef CONFIG_USB20_HOST
31 unsigned int * otg_phy_con1 = (control_usb->grf_uoc1_base + 0x8);
32 unsigned int * otg_phy_con2 = (control_usb->grf_uoc1_base + 0xc);
33 *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16); //enable soft control
34 *otg_phy_con2 = 0x2A|(0x3F<<16); // enter suspend
36 /* usb phy config init
37 * usb phy enter usb mode */
38 unsigned int * otg_phy_con3 = (control_usb->grf_uoc0_base);
39 *otg_phy_con3 = (0x0300 << 16);
41 /* other haredware init,include:
42 * DRV_VBUS GPIO init */
43 gpio_direction_output(control_usb->otg_gpios->gpio, 0);
46 void usb20otg_phy_suspend(void* pdata, int suspend)
48 struct dwc_otg_platform_data *usbpdata=pdata;
49 unsigned int * otg_phy_con1 = (control_usb->grf_uoc0_base + 0x8);
50 unsigned int * otg_phy_con2 = (control_usb->grf_uoc0_base + 0xc);
53 *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16); //enable soft control
54 *otg_phy_con2 = 0x2A|(0x3F<<16); // enter suspend
55 usbpdata->phy_status = 1;
57 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
58 usbpdata->phy_status = 0;
62 void usb20otg_soft_reset(void)
66 void usb20otg_clock_init(void* pdata)
68 struct dwc_otg_platform_data *usbpdata=pdata;
69 struct clk* ahbclk,*phyclk;
71 ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg0");
73 dev_err(usbpdata->dev, "Failed to get hclk_otg0\n");
77 phyclk = devm_clk_get(usbpdata->dev, "otgphy0");
79 dev_err(usbpdata->dev, "Failed to get otgphy0\n");
83 usbpdata->phyclk = phyclk;
84 usbpdata->ahbclk = ahbclk;
87 void usb20otg_clock_enable(void* pdata, int enable)
89 struct dwc_otg_platform_data *usbpdata=pdata;
92 clk_prepare_enable(usbpdata->ahbclk);
93 clk_prepare_enable(usbpdata->phyclk);
95 clk_disable_unprepare(usbpdata->ahbclk);
96 clk_disable_unprepare(usbpdata->phyclk);
100 int usb20otg_get_status(int id)
103 unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
106 case USB_STATUS_BVABLID:
108 ret = (usbgrf_status &(1<<10));
110 case USB_STATUS_DPDM:
112 ret = (usbgrf_status &(3<<11));
116 ret = (usbgrf_status &(1<<13));
125 #ifdef CONFIG_RK_USB_UART
126 void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
128 unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc0_base);
130 if(1 == enter_usb_uart_mode){
132 * note: can't disable otg here! If otg disable, the ID change
133 * interrupt can't be triggered when otg cable connect without
134 * device.At the same time, uart can't be used normally
136 *otg_phy_con1 = (0x0300 | (0x0300 << 16)); //bypass dm
137 }else if(0 == enter_usb_uart_mode){
139 *otg_phy_con1 = (0x0300 << 16); //bypass dm disable
144 void usb20otg_power_enable(int enable)
146 if(0 == enable){//disable otg_drv power
147 gpio_set_value(control_usb->otg_gpios->gpio, 0);
148 }else if(1 == enable){//enable otg_drv power
149 gpio_set_value(control_usb->otg_gpios->gpio, 1);
153 struct dwc_otg_platform_data usb20otg_pdata = {
158 .hw_init=usb20otg_hw_init,
159 .phy_suspend=usb20otg_phy_suspend,
160 .soft_reset=usb20otg_soft_reset,
161 .clock_init=usb20otg_clock_init,
162 .clock_enable=usb20otg_clock_enable,
163 .get_status=usb20otg_get_status,
164 .power_enable=usb20otg_power_enable,
165 #ifdef CONFIG_RK_USB_UART
166 .dwc_otg_uart_mode=dwc_otg_uart_mode,
172 #ifdef CONFIG_USB20_HOST
173 void usb20host_hw_init(void)
175 /* usb phy config init */
177 /* other haredware init,include:
178 * DRV_VBUS GPIO init */
179 gpio_direction_output(control_usb->host_gpios->gpio, 1);
183 void usb20host_phy_suspend(void* pdata, int suspend)
185 struct dwc_otg_platform_data *usbpdata=pdata;
186 unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc1_base + 0x8);
187 unsigned int * otg_phy_con2 = (unsigned int*)(control_usb->grf_uoc1_base + 0xc);
190 *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16); // enable soft control
191 *otg_phy_con2 = 0x2A|(0x3F<<16); // enter suspend
192 usbpdata->phy_status = 1;
194 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
195 usbpdata->phy_status = 0;
199 void usb20host_soft_reset(void)
203 void usb20host_clock_init(void* pdata)
205 struct dwc_otg_platform_data *usbpdata=pdata;
206 struct clk* ahbclk,*phyclk;
208 ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg1");
209 if (IS_ERR(ahbclk)) {
210 dev_err(usbpdata->dev, "Failed to get hclk_otg1\n");
214 phyclk = devm_clk_get(usbpdata->dev, "otgphy1");
215 if (IS_ERR(phyclk)) {
216 dev_err(usbpdata->dev, "Failed to get otgphy1\n");
220 usbpdata->phyclk = phyclk;
221 usbpdata->ahbclk = ahbclk;
224 void usb20host_clock_enable(void* pdata, int enable)
226 struct dwc_otg_platform_data *usbpdata=pdata;
229 clk_prepare_enable(usbpdata->ahbclk);
230 clk_prepare_enable(usbpdata->phyclk);
232 clk_disable_unprepare(usbpdata->ahbclk);
233 clk_disable_unprepare(usbpdata->phyclk);
237 int usb20host_get_status(int id)
240 unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
243 case USB_STATUS_BVABLID:
245 ret = (usbgrf_status &(1<<17));
247 case USB_STATUS_DPDM:
249 ret = (usbgrf_status &(3<<18));
253 ret = (usbgrf_status &(1<<20));
262 void usb20host_power_enable(int enable)
264 if(0 == enable){//disable host_drv power
265 //do not disable power in default
266 }else if(1 == enable){//enable host_drv power
267 gpio_set_value(control_usb->host_gpios->gpio, 1);
271 struct dwc_otg_platform_data usb20host_pdata = {
276 .hw_init=usb20host_hw_init,
277 .phy_suspend=usb20host_phy_suspend,
278 .soft_reset=usb20host_soft_reset,
279 .clock_init=usb20host_clock_init,
280 .clock_enable=usb20host_clock_enable,
281 .get_status=usb20host_get_status,
282 .power_enable=usb20host_power_enable,
286 #ifdef CONFIG_USB_EHCI_RK
287 void rk_hsic_hw_init(void)
289 unsigned int * phy_con0 = (control_usb->grf_uoc0_base);
290 unsigned int * phy_con1 = (control_usb->grf_uoc1_base);
291 unsigned int * phy_con2 = (control_usb->grf_uoc2_base);
292 unsigned int * phy_con3 = (control_usb->grf_uoc3_base);
294 // usb phy config init
295 // hsic phy config init, set hsicphy_txsrtune
296 *phy_con2 = ((0xf<<6)<<16)|(0xf<<6);
298 /* other haredware init
299 * set common_on, in suspend mode, otg/host PLL blocks remain powered
300 * for RK3168 set *phy_con0 = (1<<16)|0;
301 * for Rk3188 set *phy_con1 = (1<<16)|0;
303 *phy_con1 = (1<<16)|0;
305 /* change INCR to INCR16 or INCR8(beats less than 16)
306 * or INCR4(beats less than 8) or SINGLE(beats less than 4)
308 *phy_con3 = 0x00ff00bc;
311 void rk_hsic_clock_init(void* pdata)
313 /* By default, hsicphy_480m's parent is otg phy 480MHz clk
314 * rk3188 must use host phy 480MHz clk, because if otg bypass
315 * to uart mode, otg phy 480MHz clk will be closed automatically
317 struct rkehci_platform_data *usbpdata=pdata;
318 struct clk *ahbclk, *phyclk480m_hsic, *phyclk12m_hsic, *phyclk_otgphy1;
320 phyclk480m_hsic = devm_clk_get(usbpdata->dev, "hsicphy480m");
321 if (IS_ERR(phyclk480m_hsic)) {
322 dev_err(usbpdata->dev, "Failed to get hsicphy480m\n");
326 phyclk12m_hsic = devm_clk_get(usbpdata->dev, "hsicphy12m");
327 if (IS_ERR(phyclk12m_hsic)) {
328 dev_err(usbpdata->dev, "Failed to get hsicphy12m\n");
332 phyclk_otgphy1 = devm_clk_get(usbpdata->dev, "hsic_otgphy1");
333 if (IS_ERR(phyclk_otgphy1)) {
334 dev_err(usbpdata->dev, "Failed to get hsic_otgphy1\n");
338 ahbclk = devm_clk_get(usbpdata->dev, "hclk_hsic");
339 if (IS_ERR(ahbclk)) {
340 dev_err(usbpdata->dev, "Failed to get hclk_hsic\n");
344 clk_set_parent(phyclk480m_hsic, phyclk_otgphy1);
346 usbpdata->hclk_hsic = ahbclk;
347 usbpdata->hsic_phy_480m = phyclk480m_hsic;
348 usbpdata->hsic_phy_12m = phyclk12m_hsic;
351 void rk_hsic_clock_enable(void* pdata, int enable)
353 struct rkehci_platform_data *usbpdata=pdata;
355 if(enable == usbpdata->clk_status)
358 clk_prepare_enable(usbpdata->hclk_hsic);
359 clk_prepare_enable(usbpdata->hsic_phy_480m);
360 clk_prepare_enable(usbpdata->hsic_phy_12m);
361 usbpdata->clk_status = 1;
363 clk_disable_unprepare(usbpdata->hclk_hsic);
364 clk_disable_unprepare(usbpdata->hsic_phy_480m);
365 clk_disable_unprepare(usbpdata->hsic_phy_12m);
366 usbpdata->clk_status = 0;
370 void rk_hsic_soft_reset(void)
375 struct rkehci_platform_data rkhsic_pdata = {
377 .hsic_phy_12m = NULL,
378 .hsic_phy_480m = NULL,
380 .hw_init = rk_hsic_hw_init,
381 .clock_init = rk_hsic_clock_init,
382 .clock_enable = rk_hsic_clock_enable,
383 .soft_reset = rk_hsic_soft_reset,
387 static int dwc_otg_control_usb_probe(struct platform_device *pdev)
389 struct resource *res;
391 struct device_node *np = pdev->dev.of_node;
392 struct clk* hclk_usb_peri;
395 control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
397 dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
402 hclk_usb_peri = devm_clk_get(&pdev->dev, "hclk_usb_peri");
403 if (IS_ERR(hclk_usb_peri)) {
404 dev_err(&pdev->dev, "Failed to get hclk_usb_peri\n");
408 control_usb->hclk_usb_peri = hclk_usb_peri;
409 clk_prepare_enable(hclk_usb_peri);
411 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
413 control_usb->grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
414 if (IS_ERR(control_usb->grf_soc_status0)){
415 ret = PTR_ERR(control_usb->grf_soc_status0);
419 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
421 control_usb->grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
422 if (IS_ERR(control_usb->grf_uoc0_base)){
423 ret = PTR_ERR(control_usb->grf_uoc0_base);
427 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
429 control_usb->grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
430 if (IS_ERR(control_usb->grf_uoc1_base)){
431 ret = PTR_ERR(control_usb->grf_uoc1_base);
435 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
437 control_usb->grf_uoc2_base = devm_ioremap_resource(&pdev->dev, res);
438 if (IS_ERR(control_usb->grf_uoc2_base)){
439 ret = PTR_ERR(control_usb->grf_uoc2_base);
443 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
445 control_usb->grf_uoc3_base = devm_ioremap_resource(&pdev->dev, res);
446 if (IS_ERR(control_usb->grf_uoc3_base)){
447 ret = PTR_ERR(control_usb->grf_uoc3_base);
451 control_usb->host_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
453 gpio = of_get_named_gpio(np, "gpios", 0);
454 if(!gpio_is_valid(gpio)){
455 dev_err(&pdev->dev, "invalid host gpio%d\n", gpio);
459 control_usb->host_gpios->gpio = gpio;
460 err = devm_gpio_request(&pdev->dev, gpio, "host_drv_gpio");
463 "failed to request GPIO%d for host_drv\n",
469 control_usb->otg_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
471 gpio = of_get_named_gpio(np, "gpios", 1);
472 if(!gpio_is_valid(gpio)){
473 dev_err(&pdev->dev, "invalid otg gpio%d\n", gpio);
477 control_usb->otg_gpios->gpio = gpio;
478 err = devm_gpio_request(&pdev->dev, gpio, "otg_drv_gpio");
481 "failed to request GPIO%d for otg_drv\n",
490 clk_disable_unprepare(hclk_usb_peri);
495 static int dwc_otg_control_usb_remove(struct platform_device *pdev)
497 clk_disable_unprepare(control_usb->hclk_usb_peri);
502 static const struct of_device_id dwc_otg_control_usb_id_table[] = {
503 { .compatible = "rockchip,dwc-control-usb" },
506 MODULE_DEVICE_TABLE(of, dwc_otg_control_usb_id_table);
509 static struct platform_driver dwc_otg_control_usb_driver = {
510 .probe = dwc_otg_control_usb_probe,
511 .remove = dwc_otg_control_usb_remove,
513 .name = "dwc-control-usb",
514 .owner = THIS_MODULE,
515 .of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
519 static int __init dwc_otg_control_usb_init(void)
521 return platform_driver_register(&dwc_otg_control_usb_driver);
523 subsys_initcall(dwc_otg_control_usb_init);
525 static void __exit dwc_otg_control_usb_exit(void)
527 platform_driver_unregister(&dwc_otg_control_usb_driver);
530 module_exit(dwc_otg_control_usb_exit);
531 MODULE_ALIAS("platform: dwc_control_usb");
532 MODULE_AUTHOR("RockChip Inc.");
533 MODULE_DESCRIPTION("RockChip Control Module USB Driver");
534 MODULE_LICENSE("GPL v2");