diff options
| -rw-r--r-- | arch/arm/mach-pxa/clock.c | 79 | ||||
| -rw-r--r-- | arch/arm/mach-pxa/clock.h | 43 | ||||
| -rw-r--r-- | arch/arm/mach-pxa/pxa25x.c | 38 | ||||
| -rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 45 |
4 files changed, 176 insertions, 29 deletions
diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c index 34a31caa6f9d..83ef5ecaf432 100644 --- a/arch/arm/mach-pxa/clock.c +++ b/arch/arm/mach-pxa/clock.c | |||
| @@ -9,19 +9,15 @@ | |||
| 9 | #include <linux/string.h> | 9 | #include <linux/string.h> |
| 10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
| 11 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/delay.h> | ||
| 12 | 14 | ||
| 13 | #include <asm/arch/pxa-regs.h> | 15 | #include <asm/arch/pxa-regs.h> |
| 14 | #include <asm/hardware.h> | 16 | #include <asm/hardware.h> |
| 15 | 17 | ||
| 16 | struct clk { | 18 | #include "devices.h" |
| 17 | struct list_head node; | 19 | #include "generic.h" |
| 18 | unsigned long rate; | 20 | #include "clock.h" |
| 19 | struct module *owner; | ||
| 20 | const char *name; | ||
| 21 | unsigned int enabled; | ||
| 22 | void (*enable)(void); | ||
| 23 | void (*disable)(void); | ||
| 24 | }; | ||
| 25 | 21 | ||
| 26 | static LIST_HEAD(clocks); | 22 | static LIST_HEAD(clocks); |
| 27 | static DEFINE_MUTEX(clocks_mutex); | 23 | static DEFINE_MUTEX(clocks_mutex); |
| @@ -33,7 +29,8 @@ struct clk *clk_get(struct device *dev, const char *id) | |||
| 33 | 29 | ||
| 34 | mutex_lock(&clocks_mutex); | 30 | mutex_lock(&clocks_mutex); |
| 35 | list_for_each_entry(p, &clocks, node) { | 31 | list_for_each_entry(p, &clocks, node) { |
| 36 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | 32 | if (strcmp(id, p->name) == 0 && |
| 33 | (p->dev == NULL || p->dev == dev)) { | ||
| 37 | clk = p; | 34 | clk = p; |
| 38 | break; | 35 | break; |
| 39 | } | 36 | } |
| @@ -46,7 +43,6 @@ EXPORT_SYMBOL(clk_get); | |||
| 46 | 43 | ||
| 47 | void clk_put(struct clk *clk) | 44 | void clk_put(struct clk *clk) |
| 48 | { | 45 | { |
| 49 | module_put(clk->owner); | ||
| 50 | } | 46 | } |
| 51 | EXPORT_SYMBOL(clk_put); | 47 | EXPORT_SYMBOL(clk_put); |
| 52 | 48 | ||
| @@ -56,8 +52,12 @@ int clk_enable(struct clk *clk) | |||
| 56 | 52 | ||
| 57 | spin_lock_irqsave(&clocks_lock, flags); | 53 | spin_lock_irqsave(&clocks_lock, flags); |
| 58 | if (clk->enabled++ == 0) | 54 | if (clk->enabled++ == 0) |
| 59 | clk->enable(); | 55 | clk->ops->enable(clk); |
| 60 | spin_unlock_irqrestore(&clocks_lock, flags); | 56 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 57 | |||
| 58 | if (clk->delay) | ||
| 59 | udelay(clk->delay); | ||
| 60 | |||
| 61 | return 0; | 61 | return 0; |
| 62 | } | 62 | } |
| 63 | EXPORT_SYMBOL(clk_enable); | 63 | EXPORT_SYMBOL(clk_enable); |
| @@ -70,54 +70,75 @@ void clk_disable(struct clk *clk) | |||
| 70 | 70 | ||
| 71 | spin_lock_irqsave(&clocks_lock, flags); | 71 | spin_lock_irqsave(&clocks_lock, flags); |
| 72 | if (--clk->enabled == 0) | 72 | if (--clk->enabled == 0) |
| 73 | clk->disable(); | 73 | clk->ops->disable(clk); |
| 74 | spin_unlock_irqrestore(&clocks_lock, flags); | 74 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 75 | } | 75 | } |
| 76 | EXPORT_SYMBOL(clk_disable); | 76 | EXPORT_SYMBOL(clk_disable); |
| 77 | 77 | ||
| 78 | unsigned long clk_get_rate(struct clk *clk) | 78 | unsigned long clk_get_rate(struct clk *clk) |
| 79 | { | 79 | { |
| 80 | return clk->rate; | 80 | unsigned long rate; |
| 81 | |||
| 82 | rate = clk->rate; | ||
| 83 | if (clk->ops->getrate) | ||
| 84 | rate = clk->ops->getrate(clk); | ||
| 85 | |||
| 86 | return rate; | ||
| 81 | } | 87 | } |
| 82 | EXPORT_SYMBOL(clk_get_rate); | 88 | EXPORT_SYMBOL(clk_get_rate); |
| 83 | 89 | ||
| 84 | 90 | ||
| 85 | static void clk_gpio27_enable(void) | 91 | static void clk_gpio27_enable(struct clk *clk) |
| 86 | { | 92 | { |
| 87 | pxa_gpio_mode(GPIO11_3_6MHz_MD); | 93 | pxa_gpio_mode(GPIO11_3_6MHz_MD); |
| 88 | } | 94 | } |
| 89 | 95 | ||
| 90 | static void clk_gpio27_disable(void) | 96 | static void clk_gpio27_disable(struct clk *clk) |
| 91 | { | 97 | { |
| 92 | } | 98 | } |
| 93 | 99 | ||
| 94 | static struct clk clk_gpio27 = { | 100 | static const struct clkops clk_gpio27_ops = { |
| 95 | .name = "GPIO27_CLK", | ||
| 96 | .rate = 3686400, | ||
| 97 | .enable = clk_gpio27_enable, | 101 | .enable = clk_gpio27_enable, |
| 98 | .disable = clk_gpio27_disable, | 102 | .disable = clk_gpio27_disable, |
| 99 | }; | 103 | }; |
| 100 | 104 | ||
| 101 | int clk_register(struct clk *clk) | 105 | |
| 106 | void clk_cken_enable(struct clk *clk) | ||
| 102 | { | 107 | { |
| 103 | mutex_lock(&clocks_mutex); | 108 | CKEN |= 1 << clk->cken; |
| 104 | list_add(&clk->node, &clocks); | ||
| 105 | mutex_unlock(&clocks_mutex); | ||
| 106 | return 0; | ||
| 107 | } | 109 | } |
| 108 | EXPORT_SYMBOL(clk_register); | ||
| 109 | 110 | ||
| 110 | void clk_unregister(struct clk *clk) | 111 | void clk_cken_disable(struct clk *clk) |
| 111 | { | 112 | { |
| 113 | CKEN &= ~(1 << clk->cken); | ||
| 114 | } | ||
| 115 | |||
| 116 | const struct clkops clk_cken_ops = { | ||
| 117 | .enable = clk_cken_enable, | ||
| 118 | .disable = clk_cken_disable, | ||
| 119 | }; | ||
| 120 | |||
| 121 | static struct clk common_clks[] = { | ||
| 122 | { | ||
| 123 | .name = "GPIO27_CLK", | ||
| 124 | .ops = &clk_gpio27_ops, | ||
| 125 | .rate = 3686400, | ||
| 126 | }, | ||
| 127 | }; | ||
| 128 | |||
| 129 | void clks_register(struct clk *clks, size_t num) | ||
| 130 | { | ||
| 131 | int i; | ||
| 132 | |||
| 112 | mutex_lock(&clocks_mutex); | 133 | mutex_lock(&clocks_mutex); |
| 113 | list_del(&clk->node); | 134 | for (i = 0; i < num; i++) |
| 135 | list_add(&clks[i].node, &clocks); | ||
| 114 | mutex_unlock(&clocks_mutex); | 136 | mutex_unlock(&clocks_mutex); |
| 115 | } | 137 | } |
| 116 | EXPORT_SYMBOL(clk_unregister); | ||
| 117 | 138 | ||
| 118 | static int __init clk_init(void) | 139 | static int __init clk_init(void) |
| 119 | { | 140 | { |
| 120 | clk_register(&clk_gpio27); | 141 | clks_register(common_clks, ARRAY_SIZE(common_clks)); |
| 121 | return 0; | 142 | return 0; |
| 122 | } | 143 | } |
| 123 | arch_initcall(clk_init); | 144 | arch_initcall(clk_init); |
diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h new file mode 100644 index 000000000000..bc6b77e1592e --- /dev/null +++ b/arch/arm/mach-pxa/clock.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | struct clk; | ||
| 2 | |||
| 3 | struct clkops { | ||
| 4 | void (*enable)(struct clk *); | ||
| 5 | void (*disable)(struct clk *); | ||
| 6 | unsigned long (*getrate)(struct clk *); | ||
| 7 | }; | ||
| 8 | |||
| 9 | struct clk { | ||
| 10 | struct list_head node; | ||
| 11 | const char *name; | ||
| 12 | struct device *dev; | ||
| 13 | const struct clkops *ops; | ||
| 14 | unsigned long rate; | ||
| 15 | unsigned int cken; | ||
| 16 | unsigned int delay; | ||
| 17 | unsigned int enabled; | ||
| 18 | }; | ||
| 19 | |||
| 20 | #define INIT_CKEN(_name, _cken, _rate, _delay, _dev) \ | ||
| 21 | { \ | ||
| 22 | .name = _name, \ | ||
| 23 | .dev = _dev, \ | ||
| 24 | .ops = &clk_cken_ops, \ | ||
| 25 | .rate = _rate, \ | ||
| 26 | .cken = CKEN_##_cken, \ | ||
| 27 | .delay = _delay, \ | ||
| 28 | } | ||
| 29 | |||
| 30 | #define INIT_CK(_name, _cken, _ops, _dev) \ | ||
| 31 | { \ | ||
| 32 | .name = _name, \ | ||
| 33 | .dev = _dev, \ | ||
| 34 | .ops = _ops, \ | ||
| 35 | .cken = CKEN_##_cken, \ | ||
| 36 | } | ||
| 37 | |||
| 38 | extern const struct clkops clk_cken_ops; | ||
| 39 | |||
| 40 | void clk_cken_enable(struct clk *clk); | ||
| 41 | void clk_cken_disable(struct clk *clk); | ||
| 42 | |||
| 43 | void clks_register(struct clk *clks, size_t num); | ||
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index bcf3f0a78463..62a770121bfa 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | #include "generic.h" | 31 | #include "generic.h" |
| 32 | #include "devices.h" | 32 | #include "devices.h" |
| 33 | #include "clock.h" | ||
| 33 | 34 | ||
| 34 | /* | 35 | /* |
| 35 | * Various clock factors driven by the CCCR register. | 36 | * Various clock factors driven by the CCCR register. |
| @@ -94,6 +95,41 @@ unsigned int pxa25x_get_memclk_frequency_10khz(void) | |||
| 94 | return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; | 95 | return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 98 | static unsigned long clk_pxa25x_lcd_getrate(struct clk *clk) | ||
| 99 | { | ||
| 100 | return pxa25x_get_memclk_frequency_10khz() * 10000; | ||
| 101 | } | ||
| 102 | |||
| 103 | static const struct clkops clk_pxa25x_lcd_ops = { | ||
| 104 | .enable = clk_cken_enable, | ||
| 105 | .disable = clk_cken_disable, | ||
| 106 | .getrate = clk_pxa25x_lcd_getrate, | ||
| 107 | }; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * 3.6864MHz -> OST, GPIO, SSP, PWM, PLLs (95.842MHz, 147.456MHz) | ||
| 111 | * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz | ||
| 112 | * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly) | ||
| 113 | */ | ||
| 114 | static struct clk pxa25x_clks[] = { | ||
| 115 | INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev), | ||
| 116 | INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev), | ||
| 117 | INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev), | ||
| 118 | INIT_CKEN("UARTCLK", STUART, 14745600, 1, &pxa_device_stuart.dev), | ||
| 119 | INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev), | ||
| 120 | INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev), | ||
| 121 | INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev), | ||
| 122 | INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev), | ||
| 123 | /* | ||
| 124 | INIT_CKEN("PWMCLK", PWM0, 3686400, 0, NULL), | ||
| 125 | INIT_CKEN("PWMCLK", PWM0, 3686400, 0, NULL), | ||
| 126 | INIT_CKEN("SSPCLK", SSP, 3686400, 0, NULL), | ||
| 127 | INIT_CKEN("I2SCLK", I2S, 14745600, 0, NULL), | ||
| 128 | INIT_CKEN("NSSPCLK", NSSP, 3686400, 0, NULL), | ||
| 129 | INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL), | ||
| 130 | */ | ||
| 131 | }; | ||
| 132 | |||
| 97 | #ifdef CONFIG_PM | 133 | #ifdef CONFIG_PM |
| 98 | 134 | ||
| 99 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x | 135 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x |
| @@ -215,6 +251,8 @@ static int __init pxa25x_init(void) | |||
| 215 | int ret = 0; | 251 | int ret = 0; |
| 216 | 252 | ||
| 217 | if (cpu_is_pxa21x() || cpu_is_pxa25x()) { | 253 | if (cpu_is_pxa21x() || cpu_is_pxa25x()) { |
| 254 | clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks)); | ||
| 255 | |||
| 218 | if ((ret = pxa_init_dma(16))) | 256 | if ((ret = pxa_init_dma(16))) |
| 219 | return ret; | 257 | return ret; |
| 220 | #ifdef CONFIG_PM | 258 | #ifdef CONFIG_PM |
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 3710981b72d8..433644edf791 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | #include "generic.h" | 28 | #include "generic.h" |
| 29 | #include "devices.h" | 29 | #include "devices.h" |
| 30 | #include "clock.h" | ||
| 30 | 31 | ||
| 31 | /* Crystal clock: 13MHz */ | 32 | /* Crystal clock: 13MHz */ |
| 32 | #define BASE_CLK 13000000 | 33 | #define BASE_CLK 13000000 |
| @@ -120,6 +121,48 @@ unsigned int pxa27x_get_lcdclk_frequency_10khz(void) | |||
| 120 | return (K / 10000); | 121 | return (K / 10000); |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 124 | static unsigned long clk_pxa27x_lcd_getrate(struct clk *clk) | ||
| 125 | { | ||
| 126 | return pxa27x_get_lcdclk_frequency_10khz() * 10000; | ||
| 127 | } | ||
| 128 | |||
| 129 | static const struct clkops clk_pxa27x_lcd_ops = { | ||
| 130 | .enable = clk_cken_enable, | ||
| 131 | .disable = clk_cken_disable, | ||
| 132 | .getrate = clk_pxa27x_lcd_getrate, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static struct clk pxa27x_clks[] = { | ||
| 136 | INIT_CK("LCDCLK", LCD, &clk_pxa27x_lcd_ops, &pxa_device_fb.dev), | ||
| 137 | INIT_CK("CAMCLK", CAMERA, &clk_pxa27x_lcd_ops, NULL), | ||
| 138 | |||
| 139 | INIT_CKEN("UARTCLK", STUART, 14857000, 1, &pxa_device_stuart.dev), | ||
| 140 | INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev), | ||
| 141 | INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev), | ||
| 142 | |||
| 143 | INIT_CKEN("I2SCLK", I2S, 14682000, 0, &pxa_device_i2s.dev), | ||
| 144 | INIT_CKEN("I2CCLK", I2C, 32842000, 0, &pxa_device_i2c.dev), | ||
| 145 | INIT_CKEN("UDCCLK", USB, 48000000, 5, &pxa_device_udc.dev), | ||
| 146 | INIT_CKEN("MMCCLK", MMC, 19500000, 0, &pxa_device_mci.dev), | ||
| 147 | INIT_CKEN("FICPCLK", FICP, 48000000, 0, &pxa_device_ficp.dev), | ||
| 148 | |||
| 149 | INIT_CKEN("USBCLK", USB, 48000000, 0, &pxa27x_device_ohci.dev), | ||
| 150 | INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev), | ||
| 151 | INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL), | ||
| 152 | |||
| 153 | /* | ||
| 154 | INIT_CKEN("PWMCLK", PWM0, 13000000, 0, NULL), | ||
| 155 | INIT_CKEN("SSPCLK", SSP1, 13000000, 0, NULL), | ||
| 156 | INIT_CKEN("SSPCLK", SSP2, 13000000, 0, NULL), | ||
| 157 | INIT_CKEN("SSPCLK", SSP3, 13000000, 0, NULL), | ||
| 158 | INIT_CKEN("MSLCLK", MSL, 48000000, 0, NULL), | ||
| 159 | INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL), | ||
| 160 | INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL), | ||
| 161 | INIT_CKEN("IMCLK", IM, 0, 0, NULL), | ||
| 162 | INIT_CKEN("MEMCLK", MEMC, 0, 0, NULL), | ||
| 163 | */ | ||
| 164 | }; | ||
| 165 | |||
| 123 | #ifdef CONFIG_PM | 166 | #ifdef CONFIG_PM |
| 124 | 167 | ||
| 125 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x | 168 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x |
| @@ -343,6 +386,8 @@ static int __init pxa27x_init(void) | |||
| 343 | { | 386 | { |
| 344 | int ret = 0; | 387 | int ret = 0; |
| 345 | if (cpu_is_pxa27x()) { | 388 | if (cpu_is_pxa27x()) { |
| 389 | clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks)); | ||
| 390 | |||
| 346 | if ((ret = pxa_init_dma(32))) | 391 | if ((ret = pxa_init_dma(32))) |
| 347 | return ret; | 392 | return ret; |
| 348 | #ifdef CONFIG_PM | 393 | #ifdef CONFIG_PM |
