Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: mmp: Add Marvell PXA1908 APMU driver

Add driver for the APMU controller block found on Marvell's PXA1908 SoC.
This driver is incomplete, lacking support for (at least) GPU, VPU, DSI
and CCIC (camera related) clocks.

Signed-off-by: Duje Mihanović <duje.mihanovic@skole.hr>
Link: https://lore.kernel.org/r/20241104-pxa1908-lkml-v13-7-e050609b8d6c@skole.hr
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Duje Mihanović and committed by
Stephen Boyd
03437e85 a89233db

+122 -1
+1 -1
drivers/clk/mmp/Makefile
··· 11 11 obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o pwr-island.o 12 12 obj-$(CONFIG_COMMON_CLK_MMP2_AUDIO) += clk-audio.o 13 13 14 - obj-$(CONFIG_ARCH_MMP) += clk-of-pxa1928.o clk-pxa1908-apbc.o clk-pxa1908-apbcp.o 14 + obj-$(CONFIG_ARCH_MMP) += clk-of-pxa1928.o clk-pxa1908-apbc.o clk-pxa1908-apbcp.o clk-pxa1908-apmu.o
+121
drivers/clk/mmp/clk-pxa1908-apmu.c
··· 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");