Root/target/linux/ar7/patches-3.3/160-vlynq_try_remote_first.patch

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

Archive Download this file



interactive