📄 clock.c
字号:
.set_parent = s3c2412_setparent_i2s, .round_rate = s3c2412_roundrate_clksrc,};static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent){ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); if (parent == &clk_usysclk) clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK; else if (parent == &clk_h) clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK; else return -EINVAL; clk->parent = parent; __raw_writel(clksrc, S3C2412_CLKSRC); return 0;}static unsigned long s3c2412_getrate_cam(struct clk *clk){ unsigned long parent_rate = clk_get_rate(clk->parent); unsigned long div = __raw_readl(S3C2410_CLKDIVN); div &= S3C2412_CLKDIVN_CAMDIV_MASK; div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT; return parent_rate / (div + 1);}static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate){ unsigned long parent_rate = clk_get_rate(clk->parent); unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); rate = s3c2412_roundrate_clksrc(clk, rate); clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK; clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT; __raw_writel(clkdivn, S3C2410_CLKDIVN); return 0;}static struct clk clk_cam = { .name = "camif-upll", /* same as 2440 name */ .id = -1, .get_rate = s3c2412_getrate_cam, .set_rate = s3c2412_setrate_cam, .set_parent = s3c2412_setparent_cam, .round_rate = s3c2412_roundrate_clksrc,};/* standard clock definitions */static struct clk init_clocks_disable[] = { { .name = "nand", .id = -1, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_NAND, }, { .name = "sdi", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_SDI, }, { .name = "adc", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_ADC, }, { .name = "i2c", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_IIC, }, { .name = "iis", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_IIS, }, { .name = "spi", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_SPI, }};static struct clk init_clocks[] = { { .name = "dma", .id = 0, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_DMA0, }, { .name = "dma", .id = 1, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_DMA1, }, { .name = "dma", .id = 2, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_DMA2, }, { .name = "dma", .id = 3, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_DMA3, }, { .name = "lcd", .id = -1, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_LCDC, }, { .name = "gpio", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_GPIO, }, { .name = "usb-host", .id = -1, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_USBH, }, { .name = "usb-device", .id = -1, .parent = &clk_h, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_USBD, }, { .name = "timers", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_PWMT, }, { .name = "uart", .id = 0, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_UART0, }, { .name = "uart", .id = 1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_UART1, }, { .name = "uart", .id = 2, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_UART2, }, { .name = "rtc", .id = -1, .parent = &clk_p, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_RTC, }, { .name = "watchdog", .id = -1, .parent = &clk_p, .ctrlbit = 0, }, { .name = "usb-bus-gadget", .id = -1, .parent = &clk_usb_bus, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_USB_DEV48, }, { .name = "usb-bus-host", .id = -1, .parent = &clk_usb_bus, .enable = s3c2412_clkcon_enable, .ctrlbit = S3C2412_CLKCON_USB_HOST48, }};/* clocks to add where we need to check their parentage */struct clk_init { struct clk *clk; unsigned int bit; struct clk *src_0; struct clk *src_1;};static struct clk_init clks_src[] __initdata = { { .clk = &clk_usysclk, .bit = S3C2412_CLKSRC_USBCLK_HCLK, .src_0 = &clk_urefclk, .src_1 = &clk_upll, }, { .clk = &clk_i2s, .bit = S3C2412_CLKSRC_I2SCLK_MPLL, .src_0 = &clk_erefclk, .src_1 = &clk_mpll, }, { .clk = &clk_cam, .bit = S3C2412_CLKSRC_CAMCLK_HCLK, .src_0 = &clk_usysclk, .src_1 = &clk_h, }, { .clk = &clk_msysclk, .bit = S3C2412_CLKSRC_MSYSCLK_MPLL, .src_0 = &clk_mdivclk, .src_1 = &clk_mpll, }, { .clk = &clk_uart, .bit = S3C2412_CLKSRC_UARTCLK_MPLL, .src_0 = &clk_erefclk, .src_1 = &clk_mpll, }, { .clk = &clk_usbsrc, .bit = S3C2412_CLKSRC_USBCLK_HCLK, .src_0 = &clk_usysclk, .src_1 = &clk_h, },};/* s3c2412_clk_initparents * * Initialise the parents for the clocks that we get at start-time*/static void __init s3c2412_clk_initparents(void){ unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); struct clk_init *cip = clks_src; struct clk *src; int ptr; int ret; for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) { ret = s3c24xx_register_clock(cip->clk); if (ret < 0) { printk(KERN_ERR "Failed to register clock %s (%d)\n", cip->clk->name, ret); } src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0; printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name); clk_set_parent(cip->clk, src); }}/* clocks to add straight away */static struct clk *clks[] __initdata = { &clk_ext, &clk_usb_bus, &clk_erefclk, &clk_urefclk, &clk_mrefclk,};int __init s3c2412_baseclk_add(void){ unsigned long clkcon = __raw_readl(S3C2410_CLKCON); struct clk *clkp; int ret; int ptr; clk_upll.enable = s3c2412_upll_enable; clk_usb_bus.parent = &clk_usbsrc; clk_usb_bus.rate = 0x0; s3c2412_clk_initparents(); for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { clkp = clks[ptr]; ret = s3c24xx_register_clock(clkp); if (ret < 0) { printk(KERN_ERR "Failed to register clock %s (%d)\n", clkp->name, ret); } } /* ensure usb bus clock is within correct rate of 48MHz */ if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) { printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n"); /* for the moment, let's use the UPLL, and see if we can * get 48MHz */ clk_set_parent(&clk_usysclk, &clk_upll); clk_set_parent(&clk_usbsrc, &clk_usysclk); clk_set_rate(&clk_usbsrc, 48*1000*1000); } printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on", print_mhz(clk_get_rate(&clk_upll)), print_mhz(clk_get_rate(&clk_usb_bus))); /* register clocks from clock array */ clkp = init_clocks; for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { /* ensure that we note the clock state */ clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; ret = s3c24xx_register_clock(clkp); if (ret < 0) { printk(KERN_ERR "Failed to register clock %s (%d)\n", clkp->name, ret); } } /* We must be careful disabling the clocks we are not intending to * be using at boot time, as subsystems such as the LCD which do * their own DMA requests to the bus can cause the system to lockup * if they where in the middle of requesting bus access. * * Disabling the LCD clock if the LCD is active is very dangerous, * and therefore the bootloader should be careful to not enable * the LCD clock if it is not needed. */ /* install (and disable) the clocks we do not need immediately */ clkp = init_clocks_disable; for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { ret = s3c24xx_register_clock(clkp); if (ret < 0) { printk(KERN_ERR "Failed to register clock %s (%d)\n", clkp->name, ret); } s3c2412_clkcon_enable(clkp, 0); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -