| clock-fix1.patch
|
| Files affected:
|   arch/arm/mach-s3c2410/clock.c   |   98 	87 +	11 -	0 !
|   arch/arm/mach-s3c2410/clock.h   |   21 	20 +	1 -	0 !
|   arch/arm/mach-s3c2410/cpu.c     |   10 	10 +	0 -	0 !
|   arch/arm/mach-s3c2410/cpu.h     |    3 	3 +	0 -	0 !
|   arch/arm/mach-s3c2410/s3c2410.c |    6 	6 +	0 -	0 !
|   arch/arm/mach-s3c2410/s3c2440.c |   31 	31 +	0 -	0 !
|   6 files changed, 157 insertions(+), 12 deletions(-)
|
| Ben Dooks, Wed, 27 Oct 2004 16:25:45 +0100

--- linux-2.6.10-rc1-bk2-set2/arch/arm/mach-s3c2410/clock.c	2004-10-25 09:53:36.000000000 +0100
+++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/clock.c	2004-10-27 14:56:14.000000000 +0100
@@ -59,7 +59,7 @@
 
 /* old functions */
 
-void s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
+void inline s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
 {
 	unsigned long clkcon;
 	unsigned long flags;
@@ -72,11 +72,26 @@
 	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 s3c2410_clkcon_enable(struct clk *clk, int enable)
+{
+	s3c2410_clk_enable(clk->ctrlbit, enable);
+	return 0;
+}
 
 /* Clock API calls */
 
@@ -105,15 +120,16 @@
 
 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);
 }
 
 
@@ -131,8 +147,11 @@
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-	if (clk->parent != NULL)
-		return clk->parent->rate;
+	if (clk->rate != 0)
+		return clk->rate;
+	
+	while (clk->parent != NULL && clk->rate == 0)
+		clk = clk->parent;
 
 	return clk->rate;
 }
@@ -186,67 +205,105 @@
 	.ctrlbit       = 0
 };
 
+/* clocks that could be registered by external code */
+
+struct clk s3c24xx_dclk0 = {
+	.name		= "dclk0",
+};
+
+struct clk s3c24xx_dclk1 = {
+	.name		= "dclk1",
+};
+
+struct clk s3c24xx_clkout0 = {
+	.name		= "clkout1",
+};
+
+struct clk s3c24xx_clkout1 = {
+	.name		= "clkout1",
+};
+
+struct clk s3c24xx_uclk = {
+	.name		= "uclk",
+};
+
+
 /* clock definitions */
 
 static struct clk init_clocks[] = {
 	{ .name    = "nand",
 	  .parent  = &clk_h,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_NAND
 	},
 	{ .name    = "lcd",
 	  .parent  = &clk_h,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_LCDC
 	},
 	{ .name    = "usb-host",
 	  .parent  = &clk_h,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit =   S3C2410_CLKCON_USBH
 	},
 	{ .name    = "usb-device",
 	  .parent  = &clk_h,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_USBD
 	},
 	{ .name    = "timers",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_PWMT
 	},
 	{ .name    = "sdi",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_SDI
 	},
 	{ .name    = "uart0",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_UART0
 	},
 	{ .name    = "uart1",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_UART1
 	},
 	{ .name    = "uart2",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_UART2
 	},
 	{ .name    = "gpio",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_GPIO
 	},
 	{ .name    = "rtc",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_RTC
 	},
 	{ .name    = "adc",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_ADC
 	},
 	{ .name    = "i2c",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_IIC
 	},
 	{ .name    = "iis",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_IIS
 	},
 	{ .name    = "spi",
 	  .parent  = &clk_p,
+	  .enable  = s3c2410_clkcon_enable,
 	  .ctrlbit = S3C2410_CLKCON_SPI
 	},
 	{ .name    = "watchdog",
@@ -262,6 +319,9 @@
 	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);
@@ -273,7 +333,7 @@
 
 /* initalise all the clocks */
 
-static int __init s3c2410_init_clocks(void)
+int __init s3c2410_init_clocks(void)
 {
 	struct clk *clkp = init_clocks;
 	int ptr;
@@ -287,8 +347,25 @@
 	clk_p.rate = s3c24xx_pclk;
 	clk_f.rate = s3c24xx_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);
+	/* 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
+	 */
+
+	s3c2410_clk_enable(S3C2410_CLKCON_NAND, 0);
+	s3c2410_clk_enable(S3C2410_CLKCON_USBH, 0);
+	s3c2410_clk_enable(S3C2410_CLKCON_USBD, 0);
+	s3c2410_clk_enable(S3C2410_CLKCON_ADC, 0);
+	s3c2410_clk_enable(S3C2410_CLKCON_IIC, 0);
+	s3c2410_clk_enable(S3C2410_CLKCON_SPI, 0);
+
+	/* assume uart clocks are correctly setup */
 
 	/* register our clocks */
 
@@ -312,5 +389,4 @@
 	return 0;
 }
 
-arch_initcall(s3c2410_init_clocks);
 
--- linux-2.6.10-rc1-bk2-set2/arch/arm/mach-s3c2410/clock.h	2004-10-25 09:53:36.000000000 +0100
+++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/clock.h	2004-10-27 13:18:37.000000000 +0100
@@ -2,7 +2,7 @@
  * linux/arch/arm/mach-s3c2410/clock.h
  *
  * Copyright (c) 2004 Simtec Electronics
- * Written by Ben Dooks, <ben@simtec.co.uk>
+ *	Written by Ben Dooks, <ben@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,11 +17,30 @@
 	atomic_t              used;
 	unsigned long         rate;
 	unsigned long         ctrlbit;
+	int		    (*enable)(struct clk *, int enable);
 };
 
+/* other clocks which may be registered by board support */
+
+extern struct clk s3c24xx_dclk0;
+extern struct clk s3c24xx_dclk1;
+extern struct clk s3c24xx_clkout0;
+extern struct clk s3c24xx_clkout1;
+extern struct clk s3c24xx_uclk;
+
 /* processor clock settings, in Hz */
 
 extern unsigned long s3c24xx_xtal;
 extern unsigned long s3c24xx_pclk;
 extern unsigned long s3c24xx_hclk;
 extern unsigned long s3c24xx_fclk;
+
+/* exports for arch/arm/mach-s3c2410
+ *
+ * Please DO NOT use these outside of arch/arm/mach-s3c2410
+*/
+
+extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
+extern int s3c2410_register_clock(struct clk *clk);
+extern int s3c2410_init_clocks(void);
+
--- linux-2.6.10-rc1-bk2-set2/arch/arm/mach-s3c2410/cpu.c	2004-10-25 10:00:43.000000000 +0100
+++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/cpu.c	2004-10-27 13:32:28.000000000 +0100
@@ -38,6 +38,7 @@
 #include <asm/arch/regs-gpio.h>
 
 #include "cpu.h"
+#include "clock.h"
 #include "s3c2410.h"
 #include "s3c2440.h"
 
@@ -118,7 +119,16 @@
 
 void s3c24xx_set_board(struct s3c24xx_board *b)
 {
+	int i;
+
 	board = b;
+
+	if (b->clocks_count != 0) {
+		struct clk **ptr = b->clocks;;
+
+		for (i = b->clocks_count; i > 0; i--, ptr++)
+			s3c2410_register_clock(*ptr);
+	}
 }
 
 /* cpu information */
--- linux-2.6.10-rc1-bk2-set2/arch/arm/mach-s3c2410/cpu.h	2004-10-25 10:00:43.000000000 +0100
+++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/cpu.h	2004-10-27 13:21:01.000000000 +0100
@@ -49,6 +49,9 @@
 struct s3c24xx_board {
 	struct platform_device  **devices;
 	unsigned int              devices_count;
+
+	struct clk		**clocks;
+	unsigned int		  clocks_count;
 };
 
 extern void s3c24xx_set_board(struct s3c24xx_board *board);
--- linux-2.6.10-rc1-bk2-set2/arch/arm/mach-s3c2410/s3c2410.c	2004-10-25 10:00:43.000000000 +0100
+++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/s3c2410.c	2004-10-27 13:08:09.000000000 +0100
@@ -189,6 +189,12 @@
 	printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
 	       print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk),
 	       print_mhz(s3c24xx_pclk));
+
+	/* initialise the clocks here, to allow other things like the
+	 * console to use them 
+	 */
+
+	s3c2410_init_clocks();
 }
 
 int __init s3c2410_init(void)
--- linux-2.6.10-rc1-bk2-set2/arch/arm/mach-s3c2410/s3c2440.c	2004-10-25 10:00:43.000000000 +0100
+++ linux-2.6.10-rc1-bk2-set2-work1/arch/arm/mach-s3c2410/s3c2440.c	2004-10-27 14:17:19.000000000 +0100
@@ -120,6 +120,20 @@
 	&s3c_uart2
 };
 
+/* s3c2440 specific clock sources */
+
+static struct clk s3c2440_clk_cam = {
+	.name		= "camera",
+	.enable		= s3c2410_clkcon_enable,
+	.ctrlbit	= S3C2440_CLKCON_CAMERA
+};
+
+static struct clk s3c2440_clk_ac97 = {
+	.name		= "ac97",
+	.enable		= s3c2410_clkcon_enable,
+	.ctrlbit	= S3C2440_CLKCON_CAMERA
+};
+
 void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
 {
 	unsigned long clkdiv;
@@ -167,6 +181,23 @@
 	printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
 	       print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk),
 	       print_mhz(s3c24xx_pclk));
+
+	/* initialise the clocks here, to allow other things like the
+	 * console to use them, and to add new ones after the initialisation
+	 */
+
+	s3c2410_init_clocks();
+
+	/* add s3c2440 specific clocks */
+
+	s3c2440_clk_cam.parent = clk_get(NULL, "hclk");
+	s3c2440_clk_ac97.parent = clk_get(NULL, "pclk");
+
+	s3c2410_register_clock(&clk_ac97);
+	s3c2410_register_clock(&clk_cam);
+
+	clk_disable(&clk_ac97);
+	clk_disable(&clk_cam);
 }
 
 
