Xilinx: ARM: I2C: SI570: Driver updated for more error checking
[linux-2.6-xlnx.git] / drivers / video / xylon / xylonfb / xylonfb-pixclk.c
blob1a2f2aa5962e614128f2d393650a76ace78a4b2b
1 /*
2 * Xylon logiCVC frame buffer driver pixel clock generation
4 * Author: Xylon d.o.o.
5 * e-mail: davor.joja@logicbricks.com
7 * 2012 (c) Xylon d.o.o.
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
16 * This file implements HW dependent functionality for controlling pixel clock
17 * generation on various HW platforms.
21 #include <linux/fb.h>
24 #define HW_PIXEL_CLOCK_CHANGE_SUPPORTED 1
27 #if defined(CONFIG_FB_XYLON_TEST)
29 #define HW_PIXEL_CLOCK_CHANGE_SUPPORTED 0
30 int pixclk_set(struct fb_info *fbi)
32 printk(KERN_INFO
33 "Changing of pixel clock for %s on platform TEST not supported\n",
34 fbi->fix.id);
36 return -EPERM;
39 #elif defined(CONFIG_FB_XYLON_ZYNQ_PS_PIXCLK)
41 int pixclk_set(struct fb_info *fbi)
43 unsigned long pllclk, sysclk, pixclk;
44 unsigned long div, delta, delta_dec, delta_inc;
45 void *slcr_regs, *clk_regs, *rst_reg;
47 /* all clock values are in kHz */
48 pllclk = 1000000;
49 sysclk = 100000;
50 pixclk = PICOS2KHZ(fbi->var.pixclock);
52 slcr_regs = ioremap_nocache(0xF8000004, 8);
53 if (!slcr_regs) {
54 printk(KERN_ERR
55 "Error mapping SLCR\n");
56 return -EBUSY;
58 clk_regs = ioremap_nocache(0xF8000170, 32);
59 if (!clk_regs) {
60 printk(KERN_ERR
61 "Error setting xylonfb pixelclock\n");
62 iounmap(slcr_regs);
63 return -EBUSY;
65 rst_reg = ioremap_nocache(0xF8000240, 4);
66 if (!rst_reg) {
67 printk(KERN_ERR
68 "Error setting xylonfb pixelclock\n");
69 iounmap(clk_regs);
70 iounmap(slcr_regs);
71 return -EBUSY;
74 /* unlock register access */
75 writel(0xDF0D, (slcr_regs+4));
76 // /* calculate system clock divisor */
77 // div = pllclk / sysclk;
78 // /* prepare for register writting */
79 // div = (div + 0x1000) << 8;
80 // /* set system clock */
81 // writel(div, clk_regs);
82 /* calculate video clock divisor */
83 div = pllclk / pixclk;
84 delta = (pllclk / div) - pixclk;
85 if (delta != 0) {
86 delta_inc = pixclk - (pllclk / (div+1));
87 delta_dec = (pllclk / (div-1)) - pixclk;
88 if (delta < delta_inc) {
89 if (delta > delta_dec)
90 div--;
91 //else
92 // div = div;
93 } else {
94 if (delta > delta_dec) {
95 if (delta_inc > delta_dec)
96 div--;
97 else
98 div++;
99 } else {
100 div++;
104 /* prepare for register writting */
105 div = (div + 0x1000) << 8;
106 /* set video clock */
107 writel(div, (clk_regs+0x10));
108 // /* reset FPGA */
109 // writel(0, rst_reg);
110 // writel(0x1, rst_reg);
111 // writel(0, rst_reg);
112 /* lock register access */
113 writel(0x767B, slcr_regs);
115 iounmap(rst_reg);
116 iounmap(clk_regs);
117 iounmap(slcr_regs);
119 return 0;
122 #elif defined(CONFIG_FB_XYLON_ZC702_PIXCLK)
124 #include <linux/i2c/si570.h>
126 int pixclk_set(struct fb_info *fbi)
128 struct i2c_client *si570_client;
129 unsigned long pixclk;
131 pixclk = PICOS2KHZ(fbi->var.pixclock) * 1000;
133 si570_client = get_i2c_client_si570();
134 if (si570_client)
135 return set_frequency_si570(&si570_client->dev, pixclk);
136 else
137 return -EPERM;
140 #else
142 #if defined (HW_PIXEL_CLOCK_CHANGE_SUPPORTED)
143 #undef HW_PIXEL_CLOCK_CHANGE_SUPPORTED
144 #endif
145 #define HW_PIXEL_CLOCK_CHANGE_SUPPORTED 0
146 int pixclk_set(struct fb_info *fbi)
148 printk(KERN_INFO "Changing of pixel clock for %s not supported\n",
149 fbi->fix.id);
151 return -EPERM;
154 #endif
157 inline int pixclk_change(struct fb_info *fbi)
159 #if HW_PIXEL_CLOCK_CHANGE_SUPPORTED == 0
160 return 0;
161 #elif HW_PIXEL_CLOCK_CHANGE_SUPPORTED == 1
162 return 1;
163 #endif