diff options
author | David Lechner <david@lechnology.com> | 2018-03-15 22:52:35 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2018-03-20 13:16:26 -0400 |
commit | 58e1e2d2cd89a4aa77212eae64dd4824374e83f4 (patch) | |
tree | 746b90051104e52ab9cbda74bf989e6983178dfd /drivers | |
parent | 1e88a8d64f221208801bb279ee7452df0b6d609f (diff) |
clk: davinci: cfgchip: Add TI DA8XX USB PHY clocks
This adds a new driver for the USB PHY clocks in the CFGCHIP2 syscon
register on TI DA8XX-type SoCs.
The USB0 (USB 2.0) PHY clock is an interesting case because it calls
clk_enable() in a reentrant way. The USB 2.0 PSC only has to be enabled
temporarily while we are locking the PLL, which takes place during the
clk_enable() callback.
Signed-off-by: David Lechner <david@lechnology.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/davinci/da8xx-cfgchip.c | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index 880a77ace273..c971111d2601 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c | |||
@@ -343,6 +343,349 @@ static int __init of_da850_async3_init(struct device *dev, struct regmap *regmap | |||
343 | return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap); | 343 | return of_da8xx_cfgchip_init_mux_clock(dev, &da850_async3_info, regmap); |
344 | } | 344 | } |
345 | 345 | ||
346 | /* --- USB 2.0 PHY clock --- */ | ||
347 | |||
348 | struct da8xx_usb0_clk48 { | ||
349 | struct clk_hw hw; | ||
350 | struct clk *fck; | ||
351 | struct regmap *regmap; | ||
352 | }; | ||
353 | |||
354 | #define to_da8xx_usb0_clk48(_hw) \ | ||
355 | container_of((_hw), struct da8xx_usb0_clk48, hw) | ||
356 | |||
357 | static int da8xx_usb0_clk48_prepare(struct clk_hw *hw) | ||
358 | { | ||
359 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
360 | |||
361 | /* The USB 2.0 PSC clock is only needed temporarily during the USB 2.0 | ||
362 | * PHY clock enable, but since clk_prepare() can't be called in an | ||
363 | * atomic context (i.e. in clk_enable()), we have to prepare it here. | ||
364 | */ | ||
365 | return clk_prepare(usb0->fck); | ||
366 | } | ||
367 | |||
368 | static void da8xx_usb0_clk48_unprepare(struct clk_hw *hw) | ||
369 | { | ||
370 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
371 | |||
372 | clk_unprepare(usb0->fck); | ||
373 | } | ||
374 | |||
375 | static int da8xx_usb0_clk48_enable(struct clk_hw *hw) | ||
376 | { | ||
377 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
378 | unsigned int mask, val; | ||
379 | int ret; | ||
380 | |||
381 | /* Locking the USB 2.O PLL requires that the USB 2.O PSC is enabled | ||
382 | * temporaily. It can be turned back off once the PLL is locked. | ||
383 | */ | ||
384 | clk_enable(usb0->fck); | ||
385 | |||
386 | /* Turn on the USB 2.0 PHY, but just the PLL, and not OTG. The USB 1.1 | ||
387 | * PHY may use the USB 2.0 PLL clock without USB 2.0 OTG being used. | ||
388 | */ | ||
389 | mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_PHY_PLLON; | ||
390 | val = CFGCHIP2_PHY_PLLON; | ||
391 | |||
392 | regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); | ||
393 | ret = regmap_read_poll_timeout(usb0->regmap, CFGCHIP(2), val, | ||
394 | val & CFGCHIP2_PHYCLKGD, 0, 500000); | ||
395 | |||
396 | clk_disable(usb0->fck); | ||
397 | |||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static void da8xx_usb0_clk48_disable(struct clk_hw *hw) | ||
402 | { | ||
403 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
404 | unsigned int val; | ||
405 | |||
406 | val = CFGCHIP2_PHYPWRDN; | ||
407 | regmap_write_bits(usb0->regmap, CFGCHIP(2), val, val); | ||
408 | } | ||
409 | |||
410 | static int da8xx_usb0_clk48_is_enabled(struct clk_hw *hw) | ||
411 | { | ||
412 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
413 | unsigned int val; | ||
414 | |||
415 | regmap_read(usb0->regmap, CFGCHIP(2), &val); | ||
416 | |||
417 | return !!(val & CFGCHIP2_PHYCLKGD); | ||
418 | } | ||
419 | |||
420 | static unsigned long da8xx_usb0_clk48_recalc_rate(struct clk_hw *hw, | ||
421 | unsigned long parent_rate) | ||
422 | { | ||
423 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
424 | unsigned int mask, val; | ||
425 | |||
426 | /* The parent clock rate must be one of the following */ | ||
427 | mask = CFGCHIP2_REFFREQ_MASK; | ||
428 | switch (parent_rate) { | ||
429 | case 12000000: | ||
430 | val = CFGCHIP2_REFFREQ_12MHZ; | ||
431 | break; | ||
432 | case 13000000: | ||
433 | val = CFGCHIP2_REFFREQ_13MHZ; | ||
434 | break; | ||
435 | case 19200000: | ||
436 | val = CFGCHIP2_REFFREQ_19_2MHZ; | ||
437 | break; | ||
438 | case 20000000: | ||
439 | val = CFGCHIP2_REFFREQ_20MHZ; | ||
440 | break; | ||
441 | case 24000000: | ||
442 | val = CFGCHIP2_REFFREQ_24MHZ; | ||
443 | break; | ||
444 | case 26000000: | ||
445 | val = CFGCHIP2_REFFREQ_26MHZ; | ||
446 | break; | ||
447 | case 38400000: | ||
448 | val = CFGCHIP2_REFFREQ_38_4MHZ; | ||
449 | break; | ||
450 | case 40000000: | ||
451 | val = CFGCHIP2_REFFREQ_40MHZ; | ||
452 | break; | ||
453 | case 48000000: | ||
454 | val = CFGCHIP2_REFFREQ_48MHZ; | ||
455 | break; | ||
456 | default: | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | regmap_write_bits(usb0->regmap, CFGCHIP(2), mask, val); | ||
461 | |||
462 | /* USB 2.0 PLL always supplies 48MHz */ | ||
463 | return 48000000; | ||
464 | } | ||
465 | |||
466 | static long da8xx_usb0_clk48_round_rate(struct clk_hw *hw, unsigned long rate, | ||
467 | unsigned long *parent_rate) | ||
468 | { | ||
469 | return 48000000; | ||
470 | } | ||
471 | |||
472 | static int da8xx_usb0_clk48_set_parent(struct clk_hw *hw, u8 index) | ||
473 | { | ||
474 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
475 | |||
476 | return regmap_write_bits(usb0->regmap, CFGCHIP(2), | ||
477 | CFGCHIP2_USB2PHYCLKMUX, | ||
478 | index ? CFGCHIP2_USB2PHYCLKMUX : 0); | ||
479 | } | ||
480 | |||
481 | static u8 da8xx_usb0_clk48_get_parent(struct clk_hw *hw) | ||
482 | { | ||
483 | struct da8xx_usb0_clk48 *usb0 = to_da8xx_usb0_clk48(hw); | ||
484 | unsigned int val; | ||
485 | |||
486 | regmap_read(usb0->regmap, CFGCHIP(2), &val); | ||
487 | |||
488 | return (val & CFGCHIP2_USB2PHYCLKMUX) ? 1 : 0; | ||
489 | } | ||
490 | |||
491 | static const struct clk_ops da8xx_usb0_clk48_ops = { | ||
492 | .prepare = da8xx_usb0_clk48_prepare, | ||
493 | .unprepare = da8xx_usb0_clk48_unprepare, | ||
494 | .enable = da8xx_usb0_clk48_enable, | ||
495 | .disable = da8xx_usb0_clk48_disable, | ||
496 | .is_enabled = da8xx_usb0_clk48_is_enabled, | ||
497 | .recalc_rate = da8xx_usb0_clk48_recalc_rate, | ||
498 | .round_rate = da8xx_usb0_clk48_round_rate, | ||
499 | .set_parent = da8xx_usb0_clk48_set_parent, | ||
500 | .get_parent = da8xx_usb0_clk48_get_parent, | ||
501 | }; | ||
502 | |||
503 | static struct da8xx_usb0_clk48 * | ||
504 | da8xx_cfgchip_register_usb0_clk48(struct device *dev, | ||
505 | struct regmap *regmap) | ||
506 | { | ||
507 | const char * const parent_names[] = { "usb_refclkin", "pll0_auxclk" }; | ||
508 | struct clk *fck_clk; | ||
509 | struct da8xx_usb0_clk48 *usb0; | ||
510 | struct clk_init_data init; | ||
511 | int ret; | ||
512 | |||
513 | fck_clk = devm_clk_get(dev, "fck"); | ||
514 | if (IS_ERR(fck_clk)) { | ||
515 | if (PTR_ERR(fck_clk) != -EPROBE_DEFER) | ||
516 | dev_err(dev, "Missing fck clock\n"); | ||
517 | return ERR_CAST(fck_clk); | ||
518 | } | ||
519 | |||
520 | usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL); | ||
521 | if (!usb0) | ||
522 | return ERR_PTR(-ENOMEM); | ||
523 | |||
524 | init.name = "usb0_clk48"; | ||
525 | init.ops = &da8xx_usb0_clk48_ops; | ||
526 | init.parent_names = parent_names; | ||
527 | init.num_parents = 2; | ||
528 | |||
529 | usb0->hw.init = &init; | ||
530 | usb0->fck = fck_clk; | ||
531 | usb0->regmap = regmap; | ||
532 | |||
533 | ret = devm_clk_hw_register(dev, &usb0->hw); | ||
534 | if (ret < 0) | ||
535 | return ERR_PTR(ret); | ||
536 | |||
537 | return usb0; | ||
538 | } | ||
539 | |||
540 | /* --- USB 1.1 PHY clock --- */ | ||
541 | |||
542 | struct da8xx_usb1_clk48 { | ||
543 | struct clk_hw hw; | ||
544 | struct regmap *regmap; | ||
545 | }; | ||
546 | |||
547 | #define to_da8xx_usb1_clk48(_hw) \ | ||
548 | container_of((_hw), struct da8xx_usb1_clk48, hw) | ||
549 | |||
550 | static int da8xx_usb1_clk48_set_parent(struct clk_hw *hw, u8 index) | ||
551 | { | ||
552 | struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw); | ||
553 | |||
554 | return regmap_write_bits(usb1->regmap, CFGCHIP(2), | ||
555 | CFGCHIP2_USB1PHYCLKMUX, | ||
556 | index ? CFGCHIP2_USB1PHYCLKMUX : 0); | ||
557 | } | ||
558 | |||
559 | static u8 da8xx_usb1_clk48_get_parent(struct clk_hw *hw) | ||
560 | { | ||
561 | struct da8xx_usb1_clk48 *usb1 = to_da8xx_usb1_clk48(hw); | ||
562 | unsigned int val; | ||
563 | |||
564 | regmap_read(usb1->regmap, CFGCHIP(2), &val); | ||
565 | |||
566 | return (val & CFGCHIP2_USB1PHYCLKMUX) ? 1 : 0; | ||
567 | } | ||
568 | |||
569 | static const struct clk_ops da8xx_usb1_clk48_ops = { | ||
570 | .set_parent = da8xx_usb1_clk48_set_parent, | ||
571 | .get_parent = da8xx_usb1_clk48_get_parent, | ||
572 | }; | ||
573 | |||
574 | /** | ||
575 | * da8xx_cfgchip_register_usb1_clk48 - Register a new USB 1.1 PHY clock | ||
576 | * @regmap: The CFGCHIP regmap | ||
577 | */ | ||
578 | static struct da8xx_usb1_clk48 * | ||
579 | da8xx_cfgchip_register_usb1_clk48(struct device *dev, | ||
580 | struct regmap *regmap) | ||
581 | { | ||
582 | const char * const parent_names[] = { "usb0_clk48", "usb_refclkin" }; | ||
583 | struct da8xx_usb1_clk48 *usb1; | ||
584 | struct clk_init_data init; | ||
585 | int ret; | ||
586 | |||
587 | usb1 = devm_kzalloc(dev, sizeof(*usb1), GFP_KERNEL); | ||
588 | if (!usb1) | ||
589 | return ERR_PTR(-ENOMEM); | ||
590 | |||
591 | init.name = "usb1_clk48"; | ||
592 | init.ops = &da8xx_usb1_clk48_ops; | ||
593 | init.parent_names = parent_names; | ||
594 | init.num_parents = 2; | ||
595 | |||
596 | usb1->hw.init = &init; | ||
597 | usb1->regmap = regmap; | ||
598 | |||
599 | ret = devm_clk_hw_register(dev, &usb1->hw); | ||
600 | if (ret < 0) | ||
601 | return ERR_PTR(ret); | ||
602 | |||
603 | return usb1; | ||
604 | } | ||
605 | |||
606 | static int da8xx_cfgchip_register_usb_phy_clk(struct device *dev, | ||
607 | struct regmap *regmap) | ||
608 | { | ||
609 | struct da8xx_usb0_clk48 *usb0; | ||
610 | struct da8xx_usb1_clk48 *usb1; | ||
611 | struct clk_hw *parent; | ||
612 | |||
613 | usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap); | ||
614 | if (IS_ERR(usb0)) | ||
615 | return PTR_ERR(usb0); | ||
616 | |||
617 | /* | ||
618 | * All existing boards use pll0_auxclk as the parent and new boards | ||
619 | * should use device tree, so hard-coding the value (1) here. | ||
620 | */ | ||
621 | parent = clk_hw_get_parent_by_index(&usb0->hw, 1); | ||
622 | if (parent) | ||
623 | clk_set_parent(usb0->hw.clk, parent->clk); | ||
624 | else | ||
625 | dev_warn(dev, "Failed to find usb0 parent clock\n"); | ||
626 | |||
627 | usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap); | ||
628 | if (IS_ERR(usb1)) | ||
629 | return PTR_ERR(usb1); | ||
630 | |||
631 | /* | ||
632 | * All existing boards use usb0_clk48 as the parent and new boards | ||
633 | * should use device tree, so hard-coding the value (0) here. | ||
634 | */ | ||
635 | parent = clk_hw_get_parent_by_index(&usb1->hw, 0); | ||
636 | if (parent) | ||
637 | clk_set_parent(usb1->hw.clk, parent->clk); | ||
638 | else | ||
639 | dev_warn(dev, "Failed to find usb1 parent clock\n"); | ||
640 | |||
641 | clk_hw_register_clkdev(&usb0->hw, "usb0_clk48", "da8xx-usb-phy"); | ||
642 | clk_hw_register_clkdev(&usb1->hw, "usb1_clk48", "da8xx-usb-phy"); | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int of_da8xx_usb_phy_clk_init(struct device *dev, struct regmap *regmap) | ||
648 | { | ||
649 | struct clk_hw_onecell_data *clk_data; | ||
650 | struct da8xx_usb0_clk48 *usb0; | ||
651 | struct da8xx_usb1_clk48 *usb1; | ||
652 | |||
653 | clk_data = devm_kzalloc(dev, sizeof(*clk_data) + 2 * | ||
654 | sizeof(*clk_data->hws), GFP_KERNEL); | ||
655 | if (!clk_data) | ||
656 | return -ENOMEM; | ||
657 | |||
658 | clk_data->num = 2; | ||
659 | |||
660 | usb0 = da8xx_cfgchip_register_usb0_clk48(dev, regmap); | ||
661 | if (IS_ERR(usb0)) { | ||
662 | if (PTR_ERR(usb0) == -EPROBE_DEFER) | ||
663 | return -EPROBE_DEFER; | ||
664 | |||
665 | dev_warn(dev, "Failed to register usb0_clk48 (%ld)\n", | ||
666 | PTR_ERR(usb0)); | ||
667 | |||
668 | clk_data->hws[0] = ERR_PTR(-ENOENT); | ||
669 | } else { | ||
670 | clk_data->hws[0] = &usb0->hw; | ||
671 | } | ||
672 | |||
673 | usb1 = da8xx_cfgchip_register_usb1_clk48(dev, regmap); | ||
674 | if (IS_ERR(usb1)) { | ||
675 | if (PTR_ERR(usb0) == -EPROBE_DEFER) | ||
676 | return -EPROBE_DEFER; | ||
677 | |||
678 | dev_warn(dev, "Failed to register usb1_clk48 (%ld)\n", | ||
679 | PTR_ERR(usb1)); | ||
680 | |||
681 | clk_data->hws[1] = ERR_PTR(-ENOENT); | ||
682 | } else { | ||
683 | clk_data->hws[1] = &usb1->hw; | ||
684 | } | ||
685 | |||
686 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); | ||
687 | } | ||
688 | |||
346 | /* --- platform device --- */ | 689 | /* --- platform device --- */ |
347 | 690 | ||
348 | static const struct of_device_id da8xx_cfgchip_of_match[] = { | 691 | static const struct of_device_id da8xx_cfgchip_of_match[] = { |
@@ -362,6 +705,10 @@ static const struct of_device_id da8xx_cfgchip_of_match[] = { | |||
362 | .compatible = "ti,da850-async3-clksrc", | 705 | .compatible = "ti,da850-async3-clksrc", |
363 | .data = of_da850_async3_init, | 706 | .data = of_da850_async3_init, |
364 | }, | 707 | }, |
708 | { | ||
709 | .compatible = "ti,da830-usb-phy-clocks", | ||
710 | .data = of_da8xx_usb_phy_clk_init, | ||
711 | }, | ||
365 | { } | 712 | { } |
366 | }; | 713 | }; |
367 | 714 | ||
@@ -382,6 +729,10 @@ static const struct platform_device_id da8xx_cfgchip_id_table[] = { | |||
382 | .name = "da850-async3-clksrc", | 729 | .name = "da850-async3-clksrc", |
383 | .driver_data = (kernel_ulong_t)da850_cfgchip_register_async3, | 730 | .driver_data = (kernel_ulong_t)da850_cfgchip_register_async3, |
384 | }, | 731 | }, |
732 | { | ||
733 | .name = "da830-usb-phy-clks", | ||
734 | .driver_data = (kernel_ulong_t)da8xx_cfgchip_register_usb_phy_clk, | ||
735 | }, | ||
385 | { } | 736 | { } |
386 | }; | 737 | }; |
387 | 738 | ||