aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;