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