93ef11a1dfc41229a09bc952491d2721d8431215
[openwrt/svn-archive/archive.git] / target / linux / ar7 / patches-2.6.32 / 160-vlynq_try_remote_first.patch
1 Index: linux-2.6.32.26/drivers/vlynq/vlynq.c
2 ===================================================================
3 --- linux-2.6.32.26.orig/drivers/vlynq/vlynq.c 2010-11-22 10:48:20.000000000 -0800
4 +++ linux-2.6.32.26/drivers/vlynq/vlynq.c 2010-11-28 02:56:51.972405343 -0800
5 @@ -103,6 +103,12 @@
6 }
7 #endif
8
9 +u32 __vlynq_rev_reg(struct vlynq_regs *regs)
10 +{
11 + return readl(&regs->revision);
12 +}
13 +EXPORT_SYMBOL(__vlynq_rev_reg);
14 +
15 /* Check the VLYNQ link status with a given device */
16 static int vlynq_linked(struct vlynq_device *dev)
17 {
18 @@ -117,20 +123,40 @@
19 return 0;
20 }
21
22 +static volatile int vlynq_delay_value_new = 0;
23 +
24 +static void vlynq_delay_wait(u32 count)
25 +{
26 + /* Code adopted from original vlynq driver */
27 + int i = 0;
28 + volatile int *ptr = &vlynq_delay_value_new;
29 + *ptr = 0;
30 +
31 + /* We are assuming that the each cycle takes about
32 + * 23 assembly instructions. */
33 + for(i = 0; i < (count + 23)/23; i++)
34 + *ptr = *ptr + 1;
35 +}
36 +
37 static void vlynq_reset(struct vlynq_device *dev)
38 {
39 + u32 rtm = readl(&dev->local->revision);
40 +
41 + rtm = rtm < 0x00010205 || readl(&dev->local->status) & 0x800 == 0 ?
42 + 0 : 0x600000;
43 +
44 writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET,
45 &dev->local->control);
46
47 /* Wait for the devices to finish resetting */
48 - msleep(5);
49 + vlynq_delay_wait(0xffffff);
50
51 /* Remove reset bit */
52 - writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
53 + writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET | rtm,
54 &dev->local->control);
55
56 /* Give some time for the devices to settle */
57 - msleep(5);
58 + vlynq_delay_wait(0xffffff);
59 }
60
61 static void vlynq_irq_unmask(unsigned int irq)
62 @@ -379,6 +405,61 @@
63 }
64 EXPORT_SYMBOL(vlynq_unregister_driver);
65
66 +enum vlynq_clk_src {
67 + vlynq_clk_external,
68 + vlynq_clk_local,
69 + vlynq_clk_remote,
70 + vlynq_clk_invalid,
71 +};
72 +
73 +static int __vlynq_set_clocks(struct vlynq_device *dev,
74 + enum vlynq_clk_src clk_dir,
75 + int lclk_div, int rclk_div)
76 +{
77 + u32 reg;
78 +
79 + if (clk_dir == vlynq_clk_invalid) {
80 + printk(KERN_ERR "%s: attempt to set invalid clocking\n",
81 + dev_name(&dev->dev));
82 + return -EINVAL;
83 + }
84 +
85 + reg = readl(&dev->local->control);
86 + if (readl(&dev->local->revision) < 0x00010205) {
87 + if (clk_dir & vlynq_clk_local)
88 + reg |= VLYNQ_CTRL_CLOCK_INT;
89 + else
90 + reg &= ~VLYNQ_CTRL_CLOCK_INT;
91 + }
92 + reg &= ~VLYNQ_CTRL_CLOCK_MASK;
93 + reg |= VLYNQ_CTRL_CLOCK_DIV(lclk_div);
94 + writel(reg, &dev->local->control);
95 +
96 + if (!vlynq_linked(dev))
97 + return -ENODEV;
98 +
99 + printk(KERN_INFO "%s: local VLYNQ protocol rev. is 0x%08x\n",
100 + dev_name(&dev->dev), readl(&dev->local->revision));
101 + printk(KERN_INFO "%s: remote VLYNQ protocol rev. is 0x%08x\n",
102 + dev_name(&dev->dev), readl(&dev->remote->revision));
103 +
104 + reg = readl(&dev->remote->control);
105 + if (readl(&dev->remote->revision) < 0x00010205) {
106 + if (clk_dir & vlynq_clk_remote)
107 + reg |= VLYNQ_CTRL_CLOCK_INT;
108 + else
109 + reg &= ~VLYNQ_CTRL_CLOCK_INT;
110 + }
111 + reg &= ~VLYNQ_CTRL_CLOCK_MASK;
112 + reg |= VLYNQ_CTRL_CLOCK_DIV(rclk_div);
113 + writel(reg, &dev->remote->control);
114 +
115 + if (!vlynq_linked(dev))
116 + return -ENODEV;
117 +
118 + return 0;
119 +}
120 +
121 /*
122 * A VLYNQ remote device can clock the VLYNQ bus master
123 * using a dedicated clock line. In that case, both the
124 @@ -392,29 +473,17 @@
125 int i;
126
127 vlynq_reset(dev);
128 - for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ?
129 - i <= vlynq_rdiv8 : i >= vlynq_rdiv2;
130 - dev->dev_id ? i++ : i--) {
131 + for (i = dev->dev_id ? 0 : 7; dev->dev_id ? i <= 7 : i >= 0;
132 + dev->dev_id ? i++ : i--) {
133
134 if (!vlynq_linked(dev))
135 break;
136
137 - writel((readl(&dev->remote->control) &
138 - ~VLYNQ_CTRL_CLOCK_MASK) |
139 - VLYNQ_CTRL_CLOCK_INT |
140 - VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
141 - &dev->remote->control);
142 - writel((readl(&dev->local->control)
143 - & ~(VLYNQ_CTRL_CLOCK_INT |
144 - VLYNQ_CTRL_CLOCK_MASK)) |
145 - VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
146 - &dev->local->control);
147 -
148 - if (vlynq_linked(dev)) {
149 - printk(KERN_DEBUG
150 - "%s: using remote clock divisor %d\n",
151 - dev_name(&dev->dev), i - vlynq_rdiv1 + 1);
152 - dev->divisor = i;
153 + if (!__vlynq_set_clocks(dev, vlynq_clk_remote, i, i)) {
154 + printk(KERN_INFO
155 + "%s: using remote clock divisor %d\n",
156 + dev_name(&dev->dev), i + 1);
157 + dev->divisor = i + vlynq_rdiv1;
158 return 0;
159 } else {
160 vlynq_reset(dev);
161 @@ -437,21 +506,14 @@
162
163 vlynq_reset(dev);
164
165 - for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ?
166 - i <= vlynq_ldiv8 : i >= vlynq_ldiv2;
167 - dev->dev_id ? i++ : i--) {
168 -
169 - writel((readl(&dev->local->control) &
170 - ~VLYNQ_CTRL_CLOCK_MASK) |
171 - VLYNQ_CTRL_CLOCK_INT |
172 - VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1),
173 - &dev->local->control);
174 -
175 - if (vlynq_linked(dev)) {
176 - printk(KERN_DEBUG
177 - "%s: using local clock divisor %d\n",
178 - dev_name(&dev->dev), i - vlynq_ldiv1 + 1);
179 - dev->divisor = i;
180 + for (i = dev->dev_id ? 0 : 7; dev->dev_id ? i <= 7 : i >= 0;
181 + dev->dev_id ? i++ : i--) {
182 +
183 + if (!__vlynq_set_clocks(dev, vlynq_clk_local, i, 0)) {
184 + printk(KERN_INFO
185 + "%s: using local clock divisor %d\n",
186 + dev_name(&dev->dev), i + 1);
187 + dev->divisor = i + vlynq_ldiv1;
188 return 0;
189 } else {
190 vlynq_reset(dev);
191 @@ -473,18 +535,10 @@
192 if (!vlynq_linked(dev))
193 return -ENODEV;
194
195 - writel((readl(&dev->remote->control) &
196 - ~VLYNQ_CTRL_CLOCK_INT),
197 - &dev->remote->control);
198 -
199 - writel((readl(&dev->local->control) &
200 - ~VLYNQ_CTRL_CLOCK_INT),
201 - &dev->local->control);
202 -
203 - if (vlynq_linked(dev)) {
204 - printk(KERN_DEBUG "%s: using external clock\n",
205 - dev_name(&dev->dev));
206 - dev->divisor = vlynq_div_external;
207 + if (!__vlynq_set_clocks(dev, vlynq_clk_external, 0, 0)) {
208 + printk(KERN_INFO "%s: using external clock\n",
209 + dev_name(&dev->dev));
210 + dev->divisor = vlynq_div_external;
211 return 0;
212 }
213
214 @@ -507,18 +561,9 @@
215 * generation negotiated by hardware.
216 * Check which device is generating clocks and perform setup
217 * accordingly */
218 - if (vlynq_linked(dev) && readl(&dev->remote->control) &
219 - VLYNQ_CTRL_CLOCK_INT) {
220 - if (!__vlynq_try_remote(dev) ||
221 - !__vlynq_try_local(dev) ||
222 - !__vlynq_try_external(dev))
223 - return 0;
224 - } else {
225 - if (!__vlynq_try_external(dev) ||
226 - !__vlynq_try_local(dev) ||
227 - !__vlynq_try_remote(dev))
228 - return 0;
229 - }
230 + if (!__vlynq_try_remote(dev) || !__vlynq_try_local(dev) ||
231 + !__vlynq_try_external(dev))
232 + return 0;
233 break;
234 case vlynq_ldiv1:
235 case vlynq_ldiv2:
236 @@ -528,15 +573,12 @@
237 case vlynq_ldiv6:
238 case vlynq_ldiv7:
239 case vlynq_ldiv8:
240 - writel(VLYNQ_CTRL_CLOCK_INT |
241 - VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
242 - vlynq_ldiv1), &dev->local->control);
243 - writel(0, &dev->remote->control);
244 - if (vlynq_linked(dev)) {
245 - printk(KERN_DEBUG
246 - "%s: using local clock divisor %d\n",
247 - dev_name(&dev->dev),
248 - dev->divisor - vlynq_ldiv1 + 1);
249 + if (!__vlynq_set_clocks(dev, vlynq_clk_local, dev->divisor -
250 + vlynq_ldiv1, 0)) {
251 + printk(KERN_INFO
252 + "%s: using local clock divisor %d\n",
253 + dev_name(&dev->dev),
254 + dev->divisor - vlynq_ldiv1 + 1);
255 return 0;
256 }
257 break;
258 @@ -548,15 +590,12 @@
259 case vlynq_rdiv6:
260 case vlynq_rdiv7:
261 case vlynq_rdiv8:
262 - writel(0, &dev->local->control);
263 - writel(VLYNQ_CTRL_CLOCK_INT |
264 - VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
265 - vlynq_rdiv1), &dev->remote->control);
266 - if (vlynq_linked(dev)) {
267 - printk(KERN_DEBUG
268 - "%s: using remote clock divisor %d\n",
269 - dev_name(&dev->dev),
270 - dev->divisor - vlynq_rdiv1 + 1);
271 + if (!__vlynq_set_clocks(dev, vlynq_clk_remote, 0,
272 + dev->divisor - vlynq_rdiv1)) {
273 + printk(KERN_INFO
274 + "%s: using remote clock divisor %d\n",
275 + dev_name(&dev->dev),
276 + dev->divisor - vlynq_rdiv1 + 1);
277 return 0;
278 }
279 break;
280 @@ -732,13 +771,12 @@
281 platform_set_drvdata(pdev, dev);
282
283 printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
284 - dev_name(&dev->dev), (void *)dev->regs_start, dev->irq,
285 - (void *)dev->mem_start);
286 + dev_name(&dev->dev), (void *)dev->regs_start,
287 + dev->irq, (void *)dev->mem_start);
288
289 dev->dev_id = 0;
290 dev->divisor = vlynq_div_auto;
291 - result = __vlynq_enable_device(dev);
292 - if (result == 0) {
293 + if (!__vlynq_enable_device(dev)) {
294 dev->dev_id = readl(&dev->remote->chip);
295 ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev);
296 }
297 Index: linux-2.6.32.26/include/linux/vlynq.h
298 ===================================================================
299 --- linux-2.6.32.26.orig/include/linux/vlynq.h 2010-11-22 10:48:20.000000000 -0800
300 +++ linux-2.6.32.26/include/linux/vlynq.h 2010-11-27 12:08:39.312438011 -0800
301 @@ -98,6 +98,7 @@
302
303 extern struct bus_type vlynq_bus_type;
304
305 +extern u32 __vlynq_rev_reg(struct vlynq_regs *regs);
306 extern int __vlynq_register_driver(struct vlynq_driver *driver,
307 struct module *owner);
308