| .. | .. |
|---|
| 18 | 18 | */ |
|---|
| 19 | 19 | |
|---|
| 20 | 20 | #include <linux/clk-provider.h> |
|---|
| 21 | +#include <linux/io.h> |
|---|
| 21 | 22 | #include <linux/mfd/syscon.h> |
|---|
| 22 | 23 | #include <linux/of.h> |
|---|
| 23 | 24 | #include <linux/of_device.h> |
|---|
| .. | .. |
|---|
| 56 | 57 | struct clk_periph_driver_data { |
|---|
| 57 | 58 | struct clk_hw_onecell_data *hw_data; |
|---|
| 58 | 59 | spinlock_t lock; |
|---|
| 60 | + void __iomem *reg; |
|---|
| 61 | + |
|---|
| 62 | + /* Storage registers for suspend/resume operations */ |
|---|
| 63 | + u32 tbg_sel; |
|---|
| 64 | + u32 div_sel0; |
|---|
| 65 | + u32 div_sel1; |
|---|
| 66 | + u32 div_sel2; |
|---|
| 67 | + u32 clk_sel; |
|---|
| 68 | + u32 clk_dis; |
|---|
| 59 | 69 | }; |
|---|
| 60 | 70 | |
|---|
| 61 | 71 | struct clk_double_div { |
|---|
| .. | .. |
|---|
| 294 | 304 | PERIPH_CLK_FULL_DD(sdio, 11, 14, DIV_SEL0, DIV_SEL0, 3, 6); |
|---|
| 295 | 305 | PERIPH_CLK_FULL_DD(usb32_usb2_sys, 16, 16, DIV_SEL0, DIV_SEL0, 9, 12); |
|---|
| 296 | 306 | PERIPH_CLK_FULL_DD(usb32_ss_sys, 17, 18, DIV_SEL0, DIV_SEL0, 15, 18); |
|---|
| 307 | +static PERIPH_GATE(pcie, 14); |
|---|
| 297 | 308 | |
|---|
| 298 | 309 | static struct clk_periph_data data_sb[] = { |
|---|
| 299 | 310 | REF_CLK_MUX_DD(gbe_50), |
|---|
| .. | .. |
|---|
| 309 | 320 | REF_CLK_FULL_DD(sdio), |
|---|
| 310 | 321 | REF_CLK_FULL_DD(usb32_usb2_sys), |
|---|
| 311 | 322 | REF_CLK_FULL_DD(usb32_ss_sys), |
|---|
| 323 | + REF_CLK_GATE(pcie, "gbe_core"), |
|---|
| 312 | 324 | { }, |
|---|
| 313 | 325 | }; |
|---|
| 314 | 326 | |
|---|
| .. | .. |
|---|
| 679 | 691 | return PTR_ERR_OR_ZERO(*hw); |
|---|
| 680 | 692 | } |
|---|
| 681 | 693 | |
|---|
| 694 | +static int __maybe_unused armada_3700_periph_clock_suspend(struct device *dev) |
|---|
| 695 | +{ |
|---|
| 696 | + struct clk_periph_driver_data *data = dev_get_drvdata(dev); |
|---|
| 697 | + |
|---|
| 698 | + data->tbg_sel = readl(data->reg + TBG_SEL); |
|---|
| 699 | + data->div_sel0 = readl(data->reg + DIV_SEL0); |
|---|
| 700 | + data->div_sel1 = readl(data->reg + DIV_SEL1); |
|---|
| 701 | + data->div_sel2 = readl(data->reg + DIV_SEL2); |
|---|
| 702 | + data->clk_sel = readl(data->reg + CLK_SEL); |
|---|
| 703 | + data->clk_dis = readl(data->reg + CLK_DIS); |
|---|
| 704 | + |
|---|
| 705 | + return 0; |
|---|
| 706 | +} |
|---|
| 707 | + |
|---|
| 708 | +static int __maybe_unused armada_3700_periph_clock_resume(struct device *dev) |
|---|
| 709 | +{ |
|---|
| 710 | + struct clk_periph_driver_data *data = dev_get_drvdata(dev); |
|---|
| 711 | + |
|---|
| 712 | + /* Follow the same order than what the Cortex-M3 does (ATF code) */ |
|---|
| 713 | + writel(data->clk_dis, data->reg + CLK_DIS); |
|---|
| 714 | + writel(data->div_sel0, data->reg + DIV_SEL0); |
|---|
| 715 | + writel(data->div_sel1, data->reg + DIV_SEL1); |
|---|
| 716 | + writel(data->div_sel2, data->reg + DIV_SEL2); |
|---|
| 717 | + writel(data->tbg_sel, data->reg + TBG_SEL); |
|---|
| 718 | + writel(data->clk_sel, data->reg + CLK_SEL); |
|---|
| 719 | + |
|---|
| 720 | + return 0; |
|---|
| 721 | +} |
|---|
| 722 | + |
|---|
| 723 | +static const struct dev_pm_ops armada_3700_periph_clock_pm_ops = { |
|---|
| 724 | + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(armada_3700_periph_clock_suspend, |
|---|
| 725 | + armada_3700_periph_clock_resume) |
|---|
| 726 | +}; |
|---|
| 727 | + |
|---|
| 682 | 728 | static int armada_3700_periph_clock_probe(struct platform_device *pdev) |
|---|
| 683 | 729 | { |
|---|
| 684 | 730 | struct clk_periph_driver_data *driver_data; |
|---|
| .. | .. |
|---|
| 687 | 733 | struct device *dev = &pdev->dev; |
|---|
| 688 | 734 | int num_periph = 0, i, ret; |
|---|
| 689 | 735 | struct resource *res; |
|---|
| 690 | | - void __iomem *reg; |
|---|
| 691 | 736 | |
|---|
| 692 | 737 | data = of_device_get_match_data(dev); |
|---|
| 693 | 738 | if (!data) |
|---|
| .. | .. |
|---|
| 695 | 740 | |
|---|
| 696 | 741 | while (data[num_periph].name) |
|---|
| 697 | 742 | num_periph++; |
|---|
| 698 | | - |
|---|
| 699 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 700 | | - reg = devm_ioremap_resource(dev, res); |
|---|
| 701 | | - if (IS_ERR(reg)) |
|---|
| 702 | | - return PTR_ERR(reg); |
|---|
| 703 | 743 | |
|---|
| 704 | 744 | driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL); |
|---|
| 705 | 745 | if (!driver_data) |
|---|
| .. | .. |
|---|
| 713 | 753 | return -ENOMEM; |
|---|
| 714 | 754 | driver_data->hw_data->num = num_periph; |
|---|
| 715 | 755 | |
|---|
| 756 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 757 | + driver_data->reg = devm_ioremap_resource(dev, res); |
|---|
| 758 | + if (IS_ERR(driver_data->reg)) |
|---|
| 759 | + return PTR_ERR(driver_data->reg); |
|---|
| 760 | + |
|---|
| 716 | 761 | spin_lock_init(&driver_data->lock); |
|---|
| 717 | 762 | |
|---|
| 718 | 763 | for (i = 0; i < num_periph; i++) { |
|---|
| 719 | 764 | struct clk_hw **hw = &driver_data->hw_data->hws[i]; |
|---|
| 720 | | - |
|---|
| 721 | | - if (armada_3700_add_composite_clk(&data[i], reg, |
|---|
| 765 | + if (armada_3700_add_composite_clk(&data[i], driver_data->reg, |
|---|
| 722 | 766 | &driver_data->lock, dev, hw)) |
|---|
| 723 | 767 | dev_err(dev, "Can't register periph clock %s\n", |
|---|
| 724 | 768 | data[i].name); |
|---|
| .. | .. |
|---|
| 756 | 800 | .driver = { |
|---|
| 757 | 801 | .name = "marvell-armada-3700-periph-clock", |
|---|
| 758 | 802 | .of_match_table = armada_3700_periph_clock_of_match, |
|---|
| 803 | + .pm = &armada_3700_periph_clock_pm_ops, |
|---|
| 759 | 804 | }, |
|---|
| 760 | 805 | }; |
|---|
| 761 | 806 | |
|---|