1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/clk-provider.h> 3 #include <linux/module.h> 4 #include <linux/platform_device.h> 5 #include <linux/spinlock.h> 6 7 #include <dt-bindings/clock/marvell,pxa1908.h> 8 9 #include "clk.h" 10 11 #define APMU_CLK_GATE_CTRL 0x40 12 #define APMU_CCIC1 0x24 13 #define APMU_ISP 0x38 14 #define APMU_DSI1 0x44 15 #define APMU_DISP1 0x4c 16 #define APMU_CCIC0 0x50 17 #define APMU_SDH0 0x54 18 #define APMU_SDH1 0x58 19 #define APMU_USB 0x5c 20 #define APMU_NF 0x60 21 #define APMU_VPU 0xa4 22 #define APMU_GC 0xcc 23 #define APMU_SDH2 0xe0 24 #define APMU_GC2D 0xf4 25 #define APMU_TRACE 0x108 26 #define APMU_DVC_DFC_DEBUG 0x140 27 28 #define APMU_NR_CLKS 17 29 30 struct pxa1908_clk_unit { 31 struct mmp_clk_unit unit; 32 void __iomem *base; 33 }; 34 35 static DEFINE_SPINLOCK(pll1_lock); 36 static struct mmp_param_general_gate_clk pll1_gate_clks[] = { 37 {PXA1908_CLK_PLL1_D2_GATE, "pll1_d2_gate", "pll1_d2", 0, APMU_CLK_GATE_CTRL, 29, 0, &pll1_lock}, 38 {PXA1908_CLK_PLL1_416_GATE, "pll1_416_gate", "pll1_416", 0, APMU_CLK_GATE_CTRL, 27, 0, &pll1_lock}, 39 {PXA1908_CLK_PLL1_624_GATE, "pll1_624_gate", "pll1_624", 0, APMU_CLK_GATE_CTRL, 26, 0, &pll1_lock}, 40 {PXA1908_CLK_PLL1_832_GATE, "pll1_832_gate", "pll1_832", 0, APMU_CLK_GATE_CTRL, 30, 0, &pll1_lock}, 41 {PXA1908_CLK_PLL1_1248_GATE, "pll1_1248_gate", "pll1_1248", 0, APMU_CLK_GATE_CTRL, 28, 0, &pll1_lock}, 42 }; 43 44 static DEFINE_SPINLOCK(sdh0_lock); 45 static DEFINE_SPINLOCK(sdh1_lock); 46 static DEFINE_SPINLOCK(sdh2_lock); 47 48 static const char * const sdh_parent_names[] = {"pll1_416", "pll1_624"}; 49 50 static struct mmp_clk_mix_config sdh_mix_config = { 51 .reg_info = DEFINE_MIX_REG_INFO(3, 8, 2, 6, 11), 52 }; 53 54 static struct mmp_param_gate_clk apmu_gate_clks[] = { 55 {PXA1908_CLK_USB, "usb_clk", NULL, 0, APMU_USB, 0x9, 0x9, 0x1, 0, NULL}, 56 {PXA1908_CLK_SDH0, "sdh0_clk", "sdh0_mix_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_UNGATE, APMU_SDH0, 0x12, 0x12, 0x0, 0, &sdh0_lock}, 57 {PXA1908_CLK_SDH1, "sdh1_clk", "sdh1_mix_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_UNGATE, APMU_SDH1, 0x12, 0x12, 0x0, 0, &sdh1_lock}, 58 {PXA1908_CLK_SDH2, "sdh2_clk", "sdh2_mix_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_UNGATE, APMU_SDH2, 0x12, 0x12, 0x0, 0, &sdh2_lock} 59 }; 60 61 static void pxa1908_axi_periph_clk_init(struct pxa1908_clk_unit *pxa_unit) 62 { 63 struct mmp_clk_unit *unit = &pxa_unit->unit; 64 65 mmp_register_general_gate_clks(unit, pll1_gate_clks, 66 pxa_unit->base, ARRAY_SIZE(pll1_gate_clks)); 67 68 sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->base + APMU_SDH0; 69 mmp_clk_register_mix(NULL, "sdh0_mix_clk", sdh_parent_names, 70 ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, 71 &sdh_mix_config, &sdh0_lock); 72 sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->base + APMU_SDH1; 73 mmp_clk_register_mix(NULL, "sdh1_mix_clk", sdh_parent_names, 74 ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, 75 &sdh_mix_config, &sdh1_lock); 76 sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->base + APMU_SDH2; 77 mmp_clk_register_mix(NULL, "sdh2_mix_clk", sdh_parent_names, 78 ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, 79 &sdh_mix_config, &sdh2_lock); 80 81 mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->base, 82 ARRAY_SIZE(apmu_gate_clks)); 83 } 84 85 static int pxa1908_apmu_probe(struct platform_device *pdev) 86 { 87 struct pxa1908_clk_unit *pxa_unit; 88 89 pxa_unit = devm_kzalloc(&pdev->dev, sizeof(*pxa_unit), GFP_KERNEL); 90 if (IS_ERR(pxa_unit)) 91 return PTR_ERR(pxa_unit); 92 93 pxa_unit->base = devm_platform_ioremap_resource(pdev, 0); 94 if (IS_ERR(pxa_unit->base)) 95 return PTR_ERR(pxa_unit->base); 96 97 mmp_clk_init(pdev->dev.of_node, &pxa_unit->unit, APMU_NR_CLKS); 98 99 pxa1908_axi_periph_clk_init(pxa_unit); 100 101 return 0; 102 } 103 104 static const struct of_device_id pxa1908_apmu_match_table[] = { 105 { .compatible = "marvell,pxa1908-apmu" }, 106 { } 107 }; 108 MODULE_DEVICE_TABLE(of, pxa1908_apmu_match_table); 109 110 static struct platform_driver pxa1908_apmu_driver = { 111 .probe = pxa1908_apmu_probe, 112 .driver = { 113 .name = "pxa1908-apmu", 114 .of_match_table = pxa1908_apmu_match_table 115 } 116 }; 117 module_platform_driver(pxa1908_apmu_driver); 118 119 MODULE_AUTHOR("Duje Mihanović <duje.mihanovic@skole.hr>"); 120 MODULE_DESCRIPTION("Marvell PXA1908 APMU Clock Driver"); 121 MODULE_LICENSE("GPL"); 122