aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-10 07:44:34 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-10 16:24:19 -0400
commit389ba79582b9bc2463b44ad60df62d709ebcdf97 (patch)
tree12a6c2d7ed1a80306c116237d5070dbe64d3a32a
parentf9d08de57b0beb6623a89d8a8f501040c5eadacb (diff)
[PATCH] aoa: i2sbus: fix for PowerMac7,2 and 7,3
This patch cleans up the resource handling in i2sbus and adds workarounds for the broken device trees on the PowerMac7,2 and 7,3. Some of this code will later move again when macio_asic is going to export all the sub-nodes too. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c112
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h6
2 files changed, 97 insertions, 21 deletions
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index 8227dbbc994f..23190aa6bc7b 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -7,13 +7,16 @@
7 */ 7 */
8 8
9#include <linux/module.h> 9#include <linux/module.h>
10#include <asm/macio.h>
11#include <asm/dbdma.h>
12#include <linux/pci.h> 10#include <linux/pci.h>
13#include <linux/interrupt.h> 11#include <linux/interrupt.h>
12#include <linux/dma-mapping.h>
13
14#include <sound/driver.h> 14#include <sound/driver.h>
15#include <sound/core.h> 15#include <sound/core.h>
16#include <linux/dma-mapping.h> 16
17#include <asm/macio.h>
18#include <asm/dbdma.h>
19
17#include "../soundbus.h" 20#include "../soundbus.h"
18#include "i2sbus.h" 21#include "i2sbus.h"
19 22
@@ -78,12 +81,12 @@ static void i2sbus_release_dev(struct device *dev)
78 if (i2sdev->intfregs) iounmap(i2sdev->intfregs); 81 if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
79 if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); 82 if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
80 if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); 83 if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
81 for (i=0;i<3;i++) 84 for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
82 if (i2sdev->allocated_resource[i]) 85 if (i2sdev->allocated_resource[i])
83 release_and_free_resource(i2sdev->allocated_resource[i]); 86 release_and_free_resource(i2sdev->allocated_resource[i]);
84 free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); 87 free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
85 free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring); 88 free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring);
86 for (i=0;i<3;i++) 89 for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
87 free_irq(i2sdev->interrupts[i], i2sdev); 90 free_irq(i2sdev->interrupts[i], i2sdev);
88 i2sbus_control_remove_dev(i2sdev->control, i2sdev); 91 i2sbus_control_remove_dev(i2sdev->control, i2sdev);
89 mutex_destroy(&i2sdev->lock); 92 mutex_destroy(&i2sdev->lock);
@@ -106,6 +109,50 @@ static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs)
106 return IRQ_HANDLED; 109 return IRQ_HANDLED;
107} 110}
108 111
112
113/*
114 * XXX FIXME: We test the layout_id's here to get the proper way of
115 * mapping in various registers, thanks to bugs in Apple device-trees.
116 * We could instead key off the machine model and the name of the i2s
117 * node (i2s-a). This we'll do when we move it all to macio_asic.c
118 * and have that export items for each sub-node too.
119 */
120static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
121 int layout, struct resource *res)
122{
123 struct device_node *parent;
124 int pindex, rc = -ENXIO;
125 u32 *reg;
126
127 /* Machines with layout 76 and 36 (K2 based) have a weird device
128 * tree what we need to special case.
129 * Normal machines just fetch the resource from the i2s-X node.
130 * Darwin further divides normal machines into old and new layouts
131 * with a subtely different code path but that doesn't seem necessary
132 * in practice, they just bloated it. In addition, even on our K2
133 * case the i2s-modem node, if we ever want to handle it, uses the
134 * normal layout
135 */
136 if (layout != 76 && layout != 36)
137 return of_address_to_resource(np, index, res);
138
139 parent = of_get_parent(np);
140 pindex = (index == aoa_resource_i2smmio) ? 0 : 1;
141 rc = of_address_to_resource(parent, pindex, res);
142 if (rc)
143 goto bail;
144 reg = (u32 *)get_property(np, "reg", NULL);
145 if (reg == NULL) {
146 rc = -ENXIO;
147 goto bail;
148 }
149 res->start += reg[index * 2];
150 res->end = res->start + reg[index * 2 + 1] - 1;
151 bail:
152 of_node_put(parent);
153 return rc;
154}
155
109/* FIXME: look at device node refcounting */ 156/* FIXME: look at device node refcounting */
110static int i2sbus_add_dev(struct macio_dev *macio, 157static int i2sbus_add_dev(struct macio_dev *macio,
111 struct i2sbus_control *control, 158 struct i2sbus_control *control,
@@ -113,7 +160,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
113{ 160{
114 struct i2sbus_dev *dev; 161 struct i2sbus_dev *dev;
115 struct device_node *child = NULL, *sound = NULL; 162 struct device_node *child = NULL, *sound = NULL;
116 int i; 163 struct resource *r;
164 int i, layout = 0, rlen;
117 static const char *rnames[] = { "i2sbus: %s (control)", 165 static const char *rnames[] = { "i2sbus: %s (control)",
118 "i2sbus: %s (tx)", 166 "i2sbus: %s (tx)",
119 "i2sbus: %s (rx)" }; 167 "i2sbus: %s (rx)" };
@@ -144,8 +192,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
144 u32 *layout_id; 192 u32 *layout_id;
145 layout_id = (u32*) get_property(sound, "layout-id", NULL); 193 layout_id = (u32*) get_property(sound, "layout-id", NULL);
146 if (layout_id) { 194 if (layout_id) {
195 layout = *layout_id;
147 snprintf(dev->sound.modalias, 32, 196 snprintf(dev->sound.modalias, 32,
148 "sound-layout-%d", *layout_id); 197 "sound-layout-%d", layout);
149 force = 1; 198 force = 1;
150 } 199 }
151 } 200 }
@@ -175,23 +224,32 @@ static int i2sbus_add_dev(struct macio_dev *macio,
175 dev->bus_number = np->name[4] - 'a'; 224 dev->bus_number = np->name[4] - 'a';
176 INIT_LIST_HEAD(&dev->sound.codec_list); 225 INIT_LIST_HEAD(&dev->sound.codec_list);
177 226
178 for (i=0;i<3;i++) { 227 for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
179 dev->interrupts[i] = -1; 228 dev->interrupts[i] = -1;
180 snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name); 229 snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
230 rnames[i], np->name);
181 } 231 }
182 for (i=0;i<3;i++) { 232 for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
183 int irq = irq_of_parse_and_map(np, i); 233 int irq = irq_of_parse_and_map(np, i);
184 if (request_irq(irq, ints[i], 0, dev->rnames[i], dev)) 234 if (request_irq(irq, ints[i], 0, dev->rnames[i], dev))
185 goto err; 235 goto err;
186 dev->interrupts[i] = irq; 236 dev->interrupts[i] = irq;
187 } 237 }
188 238
189 for (i=0;i<3;i++) { 239
190 if (of_address_to_resource(np, i, &dev->resources[i])) 240 /* Resource handling is problematic as some device-trees contain
241 * useless crap (ugh ugh ugh). We work around that here by calling
242 * specific functions for calculating the appropriate resources.
243 *
244 * This will all be moved to macio_asic.c at one point
245 */
246 for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
247 if (i2sbus_get_and_fixup_rsrc(np,i,layout,&dev->resources[i]))
191 goto err; 248 goto err;
192 /* if only we could use our resource dev->resources[i]... 249 /* If only we could use our resource dev->resources[i]...
193 * but request_resource doesn't know about parents and 250 * but request_resource doesn't know about parents and
194 * contained resources... */ 251 * contained resources...
252 */
195 dev->allocated_resource[i] = 253 dev->allocated_resource[i] =
196 request_mem_region(dev->resources[i].start, 254 request_mem_region(dev->resources[i].start,
197 dev->resources[i].end - 255 dev->resources[i].end -
@@ -202,13 +260,25 @@ static int i2sbus_add_dev(struct macio_dev *macio,
202 goto err; 260 goto err;
203 } 261 }
204 } 262 }
205 /* should do sanity checking here about length of them */ 263
206 dev->intfregs = ioremap(dev->resources[0].start, 264 r = &dev->resources[aoa_resource_i2smmio];
207 dev->resources[0].end-dev->resources[0].start+1); 265 rlen = r->end - r->start + 1;
208 dev->out.dbdma = ioremap(dev->resources[1].start, 266 if (rlen < sizeof(struct i2s_interface_regs))
209 dev->resources[1].end-dev->resources[1].start+1); 267 goto err;
210 dev->in.dbdma = ioremap(dev->resources[2].start, 268 dev->intfregs = ioremap(r->start, rlen);
211 dev->resources[2].end-dev->resources[2].start+1); 269
270 r = &dev->resources[aoa_resource_txdbdma];
271 rlen = r->end - r->start + 1;
272 if (rlen < sizeof(struct dbdma_regs))
273 goto err;
274 dev->out.dbdma = ioremap(r->start, rlen);
275
276 r = &dev->resources[aoa_resource_rxdbdma];
277 rlen = r->end - r->start + 1;
278 if (rlen < sizeof(struct dbdma_regs))
279 goto err;
280 dev->in.dbdma = ioremap(r->start, rlen);
281
212 if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma) 282 if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma)
213 goto err; 283 goto err;
214 284
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index cfa5162e3b0f..d32f8a9724d7 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -45,6 +45,12 @@ struct pcm_info {
45 volatile struct dbdma_regs __iomem *dbdma; 45 volatile struct dbdma_regs __iomem *dbdma;
46}; 46};
47 47
48enum {
49 aoa_resource_i2smmio = 0,
50 aoa_resource_txdbdma,
51 aoa_resource_rxdbdma,
52};
53
48struct i2sbus_dev { 54struct i2sbus_dev {
49 struct soundbus_dev sound; 55 struct soundbus_dev sound;
50 struct macio_dev *macio; 56 struct macio_dev *macio;