[PATCH 2/5] fbdev: sa1100fb: make use of device clock
Use per-device clock (instead of calling cpufreq_get(0), which can return 0 if no cpu frequency driver is selected) to program timings. Signed-off-by: Dmitry Eremin-Solenikov dbarysh...@gmail.com --- drivers/video/sa1100fb.c | 24 +--- drivers/video/sa1100fb.h | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index de76da0..05d1b37 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -178,6 +178,7 @@ #include linux/dma-mapping.h #include linux/mutex.h #include linux/io.h +#include linux/clk.h #include video/sa1100fb.h @@ -413,9 +414,9 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var-transp.offset); #ifdef CONFIG_CPU_FREQ - dev_dbg(fbi-dev, dma period = %d ps, clock = %d kHz\n, + dev_dbg(fbi-dev, dma period = %d ps, clock = %ld kHz\n, sa1100fb_display_dma_period(var), - cpufreq_get(smp_processor_id())); + clk_get_rate(fbi-clk) / 1000); #endif return 0; @@ -586,9 +587,10 @@ static struct fb_ops sa1100fb_ops = { * Calculate the PCD value from the clock rate (in picoseconds). * We take account of the PPCR clock setting. */ -static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock) +static inline unsigned int get_pcd(struct sa1100fb_info *fbi, + unsigned int pixclock) { - unsigned int pcd = cpuclock / 100; + unsigned int pcd = clk_get_rate(fbi-clk) / 100 / 1000; pcd *= pixclock; pcd /= 1000; @@ -667,7 +669,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ LCCR2_BegFrmDel(var-upper_margin) + LCCR2_EndFrmDel(var-lower_margin); - pcd = get_pcd(var-pixclock, cpufreq_get(0)); + pcd = get_pcd(fbi, var-pixclock); new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi-inf-lccr3 | (var-sync FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | (var-sync FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); @@ -1003,7 +1005,6 @@ sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) { struct sa1100fb_info *fbi = TO_INF(nb, freq_transition); - struct cpufreq_freqs *f = data; u_int pcd; switch (val) { @@ -1012,7 +1013,7 @@ sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val, break; case CPUFREQ_POSTCHANGE: - pcd = get_pcd(fbi-fb.var.pixclock, f-new); + pcd = get_pcd(fbi, fbi-fb.var.pixclock); fbi-reg_lccr3 = (fbi-reg_lccr3 ~0xff) | LCCR3_PixClkDiv(pcd); set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); break; @@ -1219,6 +1220,13 @@ static int sa1100fb_probe(struct platform_device *pdev) if (!fbi) goto failed; + fbi-clk = clk_get(pdev-dev, NULL); + if (IS_ERR(fbi-clk)) { + ret = PTR_ERR(fbi-clk); + fbi-clk = NULL; + goto failed; + } + fbi-base = ioremap(res-start, resource_size(res)); if (!fbi-base) goto failed; @@ -1271,6 +1279,8 @@ static int sa1100fb_probe(struct platform_device *pdev) failed: if (fbi) iounmap(fbi-base); + if (fbi-clk) + clk_put(fbi-clk); kfree(fbi); release_mem_region(res-start, resource_size(res)); return ret; diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h index fc5d429..0139d13 100644 --- a/drivers/video/sa1100fb.h +++ b/drivers/video/sa1100fb.h @@ -68,6 +68,7 @@ struct sa1100fb_info { #endif const struct sa1100fb_mach_info *inf; + struct clk *clk; }; #define TO_INF(ptr,member) container_of(ptr,struct sa1100fb_info,member) -- 1.8.4.2 ___ Linux PCMCIA reimplementation list http://lists.infradead.org/mailman/listinfo/linux-pcmcia
[PATCH 3/5] pcmcia: sa1100: make use of device clock
Use per-device clock (instead of calling cpufreq_get(0), which can return 0 if no cpu frequency driver is selected) to program timings. Signed-off-by: Dmitry Eremin-Solenikov dbarysh...@gmail.com --- drivers/pcmcia/sa1100_generic.c | 1 + drivers/pcmcia/sa11xx_base.c| 14 -- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index ff8a027..d2ab060 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -93,6 +93,7 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) for (i = 0; i sinfo-nskt; i++) soc_pcmcia_remove_one(sinfo-skt[i]); + clk_put(sinfo-clk); kfree(sinfo); return 0; } diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 6eecd7c..aef0e69 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -38,6 +38,7 @@ #include linux/spinlock.h #include linux/io.h #include linux/slab.h +#include linux/clk.h #include mach/hardware.h #include asm/irq.h @@ -138,14 +139,15 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, static int sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt) { - return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); + unsigned long clk = clk_get_rate(skt-clk); + return sa1100_pcmcia_set_mecr(skt, clk / 1000); } static int sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf) { struct soc_pcmcia_timing timing; - unsigned int clock = cpufreq_get(0); + unsigned int clock = clk_get_rate(skt-clk); unsigned long mecr = MECR; char *p = buf; @@ -221,6 +223,11 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo; struct soc_pcmcia_socket *skt; int i, ret = 0; + struct clk *clk; + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) + return -ENODEV; sa11xx_drv_pcmcia_ops(ops); @@ -229,12 +236,14 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, return -ENOMEM; sinfo-nskt = nr; + sinfo-clk = clk; /* Initialize processor specific parameters */ for (i = 0; i nr; i++) { skt = sinfo-skt[i]; skt-nr = first + i; + skt-clk = clk; soc_pcmcia_init_one(skt, ops, dev); ret = sa11xx_drv_pcmcia_add_one(skt); @@ -245,6 +254,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, if (ret) { while (--i = 0) soc_pcmcia_remove_one(sinfo-skt[i]); + clk_put(clk); kfree(sinfo); } else { dev_set_drvdata(dev, sinfo); -- 1.8.4.2 ___ Linux PCMCIA reimplementation list http://lists.infradead.org/mailman/listinfo/linux-pcmcia
[PATCH 5/5] pcmcia: sa1111: make use of device clock
Use per-device clock (instead of calling cpufreq_get(0), which can return 0 if no cpu frequency driver is selected) to program timings. Signed-off-by: Dmitry Eremin-Solenikov dbarysh...@gmail.com --- drivers/pcmcia/sa_generic.c | 4 1 file changed, 4 insertions(+) diff --git a/drivers/pcmcia/sa_generic.c b/drivers/pcmcia/sa_generic.c index 65b02c3..c5988be 100644 --- a/drivers/pcmcia/sa_generic.c +++ b/drivers/pcmcia/sa_generic.c @@ -145,6 +145,9 @@ int sa_pcmcia_add(struct sa_dev *dev, struct pcmcia_low_level *ops, return -ENOMEM; s-soc.nr = ops-first + i; + s-soc.clk = clk_get(dev-dev, NULL); + if (IS_ERR(s-soc.clk)) + return -ENODEV; soc_pcmcia_init_one(s-soc, ops, dev-dev); s-dev = dev; if (s-soc.nr) { @@ -220,6 +223,7 @@ static int pcmcia_remove(struct sa_dev *dev) for (; s; s = next) { next = s-next; soc_pcmcia_remove_one(s-soc); + clk_put(s-soc.clk); kfree(s); } -- 1.8.4.2 ___ Linux PCMCIA reimplementation list http://lists.infradead.org/mailman/listinfo/linux-pcmcia
[PATCH 4/5] arm: sa1100: add a clock alias for sa1111 pcmcia device
Signed-off-by: Dmitry Eremin-Solenikov dbarysh...@gmail.com --- arch/arm/mach-sa1100/clock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c index abf1dc1..cd4762d 100644 --- a/arch/arm/mach-sa1100/clock.c +++ b/arch/arm/mach-sa1100/clock.c @@ -124,6 +124,7 @@ static struct clk_lookup sa11xx_clkregs[] = { CLKDEV_INIT(sa1100-rtc, NULL, NULL), CLKDEV_INIT(sa11x0-fb, NULL, clk_cpu), CLKDEV_INIT(sa11x0-pcmcia, NULL, clk_cpu), + CLKDEV_INIT(1600, NULL, clk_cpu), /* sa pcmcia */ }; static int __init sa11xx_clk_init(void) -- 1.8.4.2 ___ Linux PCMCIA reimplementation list http://lists.infradead.org/mailman/listinfo/linux-pcmcia
[PATCH 1/5] arm: sa1100: add cpu clock
Both SA1100 framebuffer and PCMCIA drivers require knowledge of cpu frequency to correctly program timings. Currently they receive timing information by calling cpufreq_get(0). However if cpu frequency driver is not enabled (e.g. due to unsupported DRAM chip/board on sa1110) cpufreq_get(0) returns 0, causing incorrect timings to be programmed. Add cpu clock returning cpu frequency, to be used by sa11x0 fb and pcmcia drivers. Signed-off-by: Dmitry Eremin-Solenikov dbarysh...@gmail.com --- arch/arm/mach-sa1100/clock.c | 34 ++ 1 file changed, 34 insertions(+) diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c index 172ebd0..abf1dc1 100644 --- a/arch/arm/mach-sa1100/clock.c +++ b/arch/arm/mach-sa1100/clock.c @@ -15,10 +15,12 @@ #include linux/clkdev.h #include mach/hardware.h +#include mach/generic.h struct clkops { void(*enable)(struct clk *); void(*disable)(struct clk *); + unsigned long (*get_rate)(struct clk *); }; struct clk { @@ -51,6 +53,19 @@ static void clk_gpio27_disable(struct clk *clk) GAFR = ~GPIO_32_768kHz; } +static void clk_cpu_enable(struct clk *clk) +{ +} + +static void clk_cpu_disable(struct clk *clk) +{ +} + +static unsigned long clk_cpu_get_rate(struct clk *clk) +{ + return sa11x0_getspeed(0) * 1000; +} + int clk_enable(struct clk *clk) { unsigned long flags; @@ -80,16 +95,35 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk clk-ops clk-ops-get_rate) + return clk-ops-get_rate(clk); + else + return 0; +} +EXPORT_SYMBOL(clk_get_rate); + const struct clkops clk_gpio27_ops = { .enable = clk_gpio27_enable, .disable= clk_gpio27_disable, }; +const struct clkops clk_cpu_ops = { + .enable = clk_cpu_enable, + .disable= clk_cpu_disable, + .get_rate = clk_cpu_get_rate, +}; + static DEFINE_CLK(gpio27, clk_gpio27_ops); +static DEFINE_CLK(cpu, clk_cpu_ops); + static struct clk_lookup sa11xx_clkregs[] = { CLKDEV_INIT(sa.0, NULL, clk_gpio27), CLKDEV_INIT(sa1100-rtc, NULL, NULL), + CLKDEV_INIT(sa11x0-fb, NULL, clk_cpu), + CLKDEV_INIT(sa11x0-pcmcia, NULL, clk_cpu), }; static int __init sa11xx_clk_init(void) -- 1.8.4.2 ___ Linux PCMCIA reimplementation list http://lists.infradead.org/mailman/listinfo/linux-pcmcia