X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-s3c2410%2Fclock.c;h=f6d7470fe531aa2bb34745409bded44904e9cc7a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=a12ade71b25aa453901ca7be709d1f73081ffed7;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index a12ade71b..f6d7470fe 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,12 @@ #include "clock.h" +/* clock information */ + +unsigned long s3c24xx_xtal = 12*1000*1000; /* default 12MHz */ +unsigned long s3c24xx_fclk; +unsigned long s3c24xx_hclk; +unsigned long s3c24xx_pclk; static LIST_HEAD(clocks); static DECLARE_MUTEX(clocks_sem); @@ -53,7 +60,7 @@ static DECLARE_MUTEX(clocks_sem); /* old functions */ -void s3c2410_clk_enable(unsigned int clocks, unsigned int enable) +void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable) { unsigned long clkcon; unsigned long flags; @@ -66,11 +73,26 @@ void s3c2410_clk_enable(unsigned int clocks, unsigned int enable) if (enable) clkcon |= clocks; + /* ensure none of the special function bits set */ + clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); + __raw_writel(clkcon, S3C2410_CLKCON); local_irq_restore(flags); } +/* enable and disable calls for use with the clk struct */ + +static int clk_null_enable(struct clk *clk, int enable) +{ + return 0; +} + +int s3c24xx_clkcon_enable(struct clk *clk, int enable) +{ + s3c24xx_clk_enable(clk->ctrlbit, enable); + return 0; +} /* Clock API calls */ @@ -78,17 +100,35 @@ struct clk *clk_get(struct device *dev, const char *id) { struct clk *p; struct clk *clk = ERR_PTR(-ENOENT); + int idno; + + idno = (dev == NULL) ? -1 : to_platform_device(dev)->id; down(&clocks_sem); + list_for_each_entry(p, &clocks, list) { - if (strcmp(id, p->name) == 0 && + if (p->id == idno && + strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } - up(&clocks_sem); + /* check for the case where a device was supplied, but the + * clock that was being searched for is not device specific */ + + if (IS_ERR(clk)) { + list_for_each_entry(p, &clocks, list) { + if (p->id == -1 && strcmp(id, p->name) == 0 && + try_module_get(p->owner)) { + clk = p; + break; + } + } + } + + up(&clocks_sem); return clk; } @@ -99,15 +139,16 @@ void clk_put(struct clk *clk) int clk_enable(struct clk *clk) { - if (clk->ctrlbit != 0) - s3c2410_clk_enable(clk->ctrlbit, 1); + if (IS_ERR(clk)) + return -EINVAL; - return 0; + return (clk->enable)(clk, 1); } void clk_disable(struct clk *clk) { - s3c2410_clk_enable(clk->ctrlbit, 0); + if (!IS_ERR(clk)) + (clk->enable)(clk, 0); } @@ -125,8 +166,14 @@ void clk_unuse(struct clk *clk) unsigned long clk_get_rate(struct clk *clk) { - if (clk->parent != NULL) - return clk->parent->rate; + if (IS_ERR(clk)) + return 0; + + if (clk->rate != 0) + return clk->rate; + + while (clk->parent != NULL && clk->rate == 0) + clk = clk->parent; return clk->rate; } @@ -160,90 +207,151 @@ EXPORT_SYMBOL(clk_get_parent); /* base clocks */ static struct clk clk_f = { - .name = "fclk", - .rate = 0, - .parent = NULL, - .ctrlbit = 0 + .name = "fclk", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, }; static struct clk clk_h = { - .name = "hclk", - .rate = 0, - .parent = NULL, - .ctrlbit = 0 + .name = "hclk", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, }; static struct clk clk_p = { - .name = "pclk", - .rate = 0, - .parent = NULL, - .ctrlbit = 0 + .name = "pclk", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, }; +/* clocks that could be registered by external code */ + +struct clk s3c24xx_dclk0 = { + .name = "dclk0", + .id = -1, +}; + +struct clk s3c24xx_dclk1 = { + .name = "dclk1", + .id = -1, +}; + +struct clk s3c24xx_clkout0 = { + .name = "clkout0", + .id = -1, +}; + +struct clk s3c24xx_clkout1 = { + .name = "clkout1", + .id = -1, +}; + +struct clk s3c24xx_uclk = { + .name = "uclk", + .id = -1, +}; + + /* clock definitions */ static struct clk init_clocks[] = { { .name = "nand", + .id = -1, .parent = &clk_h, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_NAND }, { .name = "lcd", + .id = -1, .parent = &clk_h, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_LCDC }, { .name = "usb-host", + .id = -1, .parent = &clk_h, - .ctrlbit = S3C2410_CLKCON_USBH + .enable = s3c24xx_clkcon_enable, + .ctrlbit = S3C2410_CLKCON_USBH }, { .name = "usb-device", + .id = -1, .parent = &clk_h, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_USBD }, { .name = "timers", .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_PWMT }, { .name = "sdi", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_SDI }, - { .name = "uart0", + { .name = "uart", + .id = 0, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART0 }, - { .name = "uart1", + { .name = "uart", + .id = 1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART1 }, - { .name = "uart2", + { .name = "uart", + .id = 2, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_UART2 }, { .name = "gpio", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_GPIO }, { .name = "rtc", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_RTC }, { .name = "adc", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_ADC }, { .name = "i2c", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_IIC }, { .name = "iis", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_IIS }, { .name = "spi", + .id = -1, .parent = &clk_p, + .enable = s3c24xx_clkcon_enable, .ctrlbit = S3C2410_CLKCON_SPI }, { .name = "watchdog", + .id = -1, .parent = &clk_p, .ctrlbit = 0 } @@ -251,11 +359,14 @@ static struct clk init_clocks[] = { /* initialise the clock system */ -int s3c2410_register_clock(struct clk *clk) +int s3c24xx_register_clock(struct clk *clk) { clk->owner = THIS_MODULE; atomic_set(&clk->used, 0); + if (clk->enable == NULL) + clk->enable = clk_null_enable; + /* add to the list of available clocks */ down(&clocks_sem); @@ -267,7 +378,7 @@ int s3c2410_register_clock(struct clk *clk) /* initalise all the clocks */ -static int __init s3c2410_init_clocks(void) +int __init s3c24xx_setup_clocks(void) { struct clk *clkp = init_clocks; int ptr; @@ -277,26 +388,43 @@ static int __init s3c2410_init_clocks(void) /* initialise the main system clocks */ - clk_h.rate = s3c2410_hclk; - clk_p.rate = s3c2410_pclk; - clk_f.rate = s3c2410_fclk; - - /* set the enabled clocks to a minimal (known) state */ - __raw_writel(S3C2410_CLKCON_PWMT | S3C2410_CLKCON_UART0 | S3C2410_CLKCON_UART1 | S3C2410_CLKCON_UART2 | S3C2410_CLKCON_GPIO | S3C2410_CLKCON_RTC, S3C2410_CLKCON); + clk_h.rate = s3c24xx_hclk; + clk_p.rate = s3c24xx_pclk; + clk_f.rate = s3c24xx_fclk; + + /* it looks like just setting the register here is not good + * enough, and causes the odd hang at initial boot time, so + * do all of them indivdually. + * + * I think 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. + * + * and of course, this looks neater + */ + + s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0); + s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0); + s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0); + s3c24xx_clk_enable(S3C2410_CLKCON_ADC, 0); + s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0); + s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0); + + /* assume uart clocks are correctly setup */ /* register our clocks */ - if (s3c2410_register_clock(&clk_f) < 0) + if (s3c24xx_register_clock(&clk_f) < 0) printk(KERN_ERR "failed to register cpu fclk\n"); - if (s3c2410_register_clock(&clk_h) < 0) + if (s3c24xx_register_clock(&clk_h) < 0) printk(KERN_ERR "failed to register cpu hclk\n"); - if (s3c2410_register_clock(&clk_p) < 0) + if (s3c24xx_register_clock(&clk_p) < 0) printk(KERN_ERR "failed to register cpu pclk\n"); for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { - ret = s3c2410_register_clock(clkp); + ret = s3c24xx_register_clock(clkp); if (ret < 0) { printk(KERN_ERR "Failed to register clock %s (%d)\n", clkp->name, ret); @@ -306,5 +434,4 @@ static int __init s3c2410_init_clocks(void) return 0; } -arch_initcall(s3c2410_init_clocks);