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