2 * (C) 2015 by Martin Prudek prudemar@fel.cvut.cz
3 * (C) 2015 by Pavel Pisa pisa@cmp.felk.cvut.cz
5 * Configuration of the General Purpose Clocks outputs
6 * Inspired by wiringPi written by Gordon Henderson.
24 #include <sys/ioctl.h>
27 #include "rpi_gpclk.h"
29 #define CLK_GPx_CTL(chan) \
30 (rpi_registers_mapping.clk_base[28 + 2 * (chan)])
32 #define CLK_GPx_DIV(chan) \
33 (rpi_registers_mapping.clk_base[29 + 2 * (chan)])
35 #define CLK_CTL_SRC_OSC 1 /* 19.2 MHz */
36 #define CLK_CTL_SRC_PLLC 5 /* 1000 MHz */
37 #define CLK_CTL_SRC_PLLD 6 /* 500 MHz */
38 #define CLK_CTL_SRC_HDMI 7 /* 216 MHz */
40 #define CLK_PASSWD (0x5A<<24)
41 #define CLK_CTL_MASH(x)((x)<<9)
42 #define CLK_CTL_BUSY (1 <<7)
43 #define CLK_CTL_KILL (1 <<5)
44 #define CLK_CTL_ENAB (1 <<4)
45 #define CLK_CTL_SRC(x) ((x)<<0)
47 #define CLK_DIV_DIVI(x) ((x)<<12)
48 #define CLK_DIV_DIVF(x) ((x)<< 0)
50 uint32_t rpi_gpclk_src_to_reg[] = {
51 [RPI_GPCLK_PLLD_500_MHZ] = CLK_CTL_SRC_PLLD,
52 [RPI_GPCLK_OSC_19_MHZ_2] = CLK_CTL_SRC_OSC,
53 [RPI_GPCLK_HDMI_216_MHZ] = CLK_CTL_SRC_HDMI,
54 [RPI_GPCLK_PLLC_1000_MHZ] = CLK_CTL_SRC_PLLD,
57 int rpi_gpclk_setup(int chan, int source, int div_int, int div_frac)
62 if (!rpi_registers_mapping.mapping_initialized)
65 if ((source < 0) || (source > sizeof(rpi_gpclk_src_to_reg) /
66 sizeof(*rpi_gpclk_src_to_reg) ))
69 if ((div_int < 2) || (div_int > 4095))
72 if ((div_frac < 0) || (div_frac > 4095))
75 if ((MASH < 0) || (MASH > 3))
78 clksrc = rpi_gpclk_src_to_reg[source];
80 CLK_GPx_CTL(chan) = CLK_PASSWD | CLK_CTL_KILL;
82 while (CLK_GPx_CTL(chan) & CLK_CTL_BUSY){
86 CLK_GPx_DIV(chan) = (CLK_PASSWD | CLK_DIV_DIVI(div_int) | CLK_DIV_DIVF(div_frac));
90 CLK_GPx_CTL(chan) = (CLK_PASSWD | CLK_CTL_MASH(MASH) | CLK_CTL_SRC(clksrc));
94 CLK_GPx_CTL(chan) |= (CLK_PASSWD | CLK_CTL_ENAB);