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>
7 #include <dt-bindings/clock/marvell,pxa1908.h>
11 #define APBC_UART0 0x0
12 #define APBC_UART1 0x4
15 #define APBC_PWM1 0x10
16 #define APBC_PWM2 0x14
17 #define APBC_PWM3 0x18
18 #define APBC_SSP0 0x1c
19 #define APBC_SSP1 0x20
20 #define APBC_IPC_RST 0x24
22 #define APBC_TWSI0 0x2c
24 #define APBC_SWJTAG 0x40
25 #define APBC_SSP2 0x4c
26 #define APBC_TWSI1 0x60
27 #define APBC_THERMAL 0x6c
28 #define APBC_TWSI3 0x70
30 #define APBC_NR_CLKS 19
32 struct pxa1908_clk_unit
{
33 struct mmp_clk_unit unit
;
37 static DEFINE_SPINLOCK(pwm0_lock
);
38 static DEFINE_SPINLOCK(pwm2_lock
);
40 static DEFINE_SPINLOCK(uart0_lock
);
41 static DEFINE_SPINLOCK(uart1_lock
);
43 static const char * const uart_parent_names
[] = {"pll1_117", "uart_pll"};
44 static const char * const ssp_parent_names
[] = {"pll1_d16", "pll1_d48", "pll1_d24", "pll1_d12"};
46 static struct mmp_param_gate_clk apbc_gate_clks
[] = {
47 {PXA1908_CLK_TWSI0
, "twsi0_clk", "pll1_32", CLK_SET_RATE_PARENT
, APBC_TWSI0
, 0x7, 3, 0, 0, NULL
},
48 {PXA1908_CLK_TWSI1
, "twsi1_clk", "pll1_32", CLK_SET_RATE_PARENT
, APBC_TWSI1
, 0x7, 3, 0, 0, NULL
},
49 {PXA1908_CLK_TWSI3
, "twsi3_clk", "pll1_32", CLK_SET_RATE_PARENT
, APBC_TWSI3
, 0x7, 3, 0, 0, NULL
},
50 {PXA1908_CLK_GPIO
, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT
, APBC_GPIO
, 0x7, 3, 0, 0, NULL
},
51 {PXA1908_CLK_KPC
, "kpc_clk", "clk32", CLK_SET_RATE_PARENT
, APBC_KPC
, 0x7, 3, 0, MMP_CLK_GATE_NEED_DELAY
, NULL
},
52 {PXA1908_CLK_RTC
, "rtc_clk", "clk32", CLK_SET_RATE_PARENT
, APBC_RTC
, 0x87, 0x83, 0, MMP_CLK_GATE_NEED_DELAY
, NULL
},
53 {PXA1908_CLK_PWM0
, "pwm0_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT
, APBC_PWM0
, 0x2, 2, 0, 0, &pwm0_lock
},
54 {PXA1908_CLK_PWM1
, "pwm1_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT
, APBC_PWM1
, 0x6, 2, 0, 0, NULL
},
55 {PXA1908_CLK_PWM2
, "pwm2_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT
, APBC_PWM2
, 0x2, 2, 0, 0, NULL
},
56 {PXA1908_CLK_PWM3
, "pwm3_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT
, APBC_PWM3
, 0x6, 2, 0, 0, NULL
},
57 {PXA1908_CLK_UART0
, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT
, APBC_UART0
, 0x7, 3, 0, 0, &uart0_lock
},
58 {PXA1908_CLK_UART1
, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT
, APBC_UART1
, 0x7, 3, 0, 0, &uart1_lock
},
59 {PXA1908_CLK_THERMAL
, "thermal_clk", NULL
, 0, APBC_THERMAL
, 0x7, 3, 0, 0, NULL
},
60 {PXA1908_CLK_IPC_RST
, "ipc_clk", NULL
, 0, APBC_IPC_RST
, 0x7, 3, 0, 0, NULL
},
61 {PXA1908_CLK_SSP0
, "ssp0_clk", "ssp0_mux", 0, APBC_SSP0
, 0x7, 3, 0, 0, NULL
},
62 {PXA1908_CLK_SSP2
, "ssp2_clk", "ssp2_mux", 0, APBC_SSP2
, 0x7, 3, 0, 0, NULL
},
65 static struct mmp_param_mux_clk apbc_mux_clks
[] = {
66 {0, "uart0_mux", uart_parent_names
, ARRAY_SIZE(uart_parent_names
), CLK_SET_RATE_PARENT
, APBC_UART0
, 4, 3, 0, &uart0_lock
},
67 {0, "uart1_mux", uart_parent_names
, ARRAY_SIZE(uart_parent_names
), CLK_SET_RATE_PARENT
, APBC_UART1
, 4, 3, 0, &uart1_lock
},
68 {0, "ssp0_mux", ssp_parent_names
, ARRAY_SIZE(ssp_parent_names
), 0, APBC_SSP0
, 4, 3, 0, NULL
},
69 {0, "ssp2_mux", ssp_parent_names
, ARRAY_SIZE(ssp_parent_names
), 0, APBC_SSP2
, 4, 3, 0, NULL
},
72 static void pxa1908_apb_periph_clk_init(struct pxa1908_clk_unit
*pxa_unit
)
74 struct mmp_clk_unit
*unit
= &pxa_unit
->unit
;
77 mmp_clk_register_gate(NULL
, "pwm01_apb_share", "pll1_d48",
79 pxa_unit
->base
+ APBC_PWM0
,
80 0x5, 1, 0, 0, &pwm0_lock
);
81 mmp_clk_register_gate(NULL
, "pwm23_apb_share", "pll1_d48",
83 pxa_unit
->base
+ APBC_PWM2
,
84 0x5, 1, 0, 0, &pwm2_lock
);
85 clk
= mmp_clk_register_apbc("swjtag", NULL
,
86 pxa_unit
->base
+ APBC_SWJTAG
, 10, 0, NULL
);
87 mmp_clk_add(unit
, PXA1908_CLK_SWJTAG
, clk
);
88 mmp_register_mux_clks(unit
, apbc_mux_clks
, pxa_unit
->base
,
89 ARRAY_SIZE(apbc_mux_clks
));
90 mmp_register_gate_clks(unit
, apbc_gate_clks
, pxa_unit
->base
,
91 ARRAY_SIZE(apbc_gate_clks
));
94 static int pxa1908_apbc_probe(struct platform_device
*pdev
)
96 struct pxa1908_clk_unit
*pxa_unit
;
98 pxa_unit
= devm_kzalloc(&pdev
->dev
, sizeof(*pxa_unit
), GFP_KERNEL
);
100 return PTR_ERR(pxa_unit
);
102 pxa_unit
->base
= devm_platform_ioremap_resource(pdev
, 0);
103 if (IS_ERR(pxa_unit
->base
))
104 return PTR_ERR(pxa_unit
->base
);
106 mmp_clk_init(pdev
->dev
.of_node
, &pxa_unit
->unit
, APBC_NR_CLKS
);
108 pxa1908_apb_periph_clk_init(pxa_unit
);
113 static const struct of_device_id pxa1908_apbc_match_table
[] = {
114 { .compatible
= "marvell,pxa1908-apbc" },
117 MODULE_DEVICE_TABLE(of
, pxa1908_apbc_match_table
);
119 static struct platform_driver pxa1908_apbc_driver
= {
120 .probe
= pxa1908_apbc_probe
,
122 .name
= "pxa1908-apbc",
123 .of_match_table
= pxa1908_apbc_match_table
126 module_platform_driver(pxa1908_apbc_driver
);
128 MODULE_AUTHOR("Duje Mihanović <duje.mihanovic@skole.hr>");
129 MODULE_DESCRIPTION("Marvell PXA1908 APBC Clock Driver");
130 MODULE_LICENSE("GPL");