diff options
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-core.c | 112 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus.h | 6 |
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 | */ | ||
120 | static 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 */ |
110 | static int i2sbus_add_dev(struct macio_dev *macio, | 157 | static 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 | ||
48 | enum { | ||
49 | aoa_resource_i2smmio = 0, | ||
50 | aoa_resource_txdbdma, | ||
51 | aoa_resource_rxdbdma, | ||
52 | }; | ||
53 | |||
48 | struct i2sbus_dev { | 54 | struct i2sbus_dev { |
49 | struct soundbus_dev sound; | 55 | struct soundbus_dev sound; |
50 | struct macio_dev *macio; | 56 | struct macio_dev *macio; |