diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2006-06-21 09:42:43 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-06-22 15:34:38 -0400 |
commit | f3d9478b2ce468c3115b02ecae7e975990697f15 (patch) | |
tree | 8397671cbf251c54bf539016468164e08d0c45ee /sound/aoa/soundbus | |
parent | 41f0cd3a0c4c6547860cf3b1c2d7968008e6c071 (diff) |
[ALSA] snd-aoa: add snd-aoa
This large patch adds all of snd-aoa.
Consisting of many modules, it currently replaces snd-powermac
for all layout-id based machines and handles many more (for
example new powerbooks and powermacs with digital output that
previously couldn't be used at all).
It also has support for all layout-IDs that Apple has (judging
from their Info.plist file) but not all are tested.
The driver currently has 2 known regressions over snd-powermac:
* it doesn't handle powermac 7,2 and 7,3
* it doesn't have a DRC control on snapper-based machines
I will fix those during the 2.6.18 development cycle.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/aoa/soundbus')
-rw-r--r-- | sound/aoa/soundbus/Kconfig | 14 | ||||
-rw-r--r-- | sound/aoa/soundbus/Makefile | 3 | ||||
-rw-r--r-- | sound/aoa/soundbus/core.c | 250 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/Makefile | 2 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-control.c | 192 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-control.h | 37 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-core.c | 387 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-interface.h | 187 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | 1021 | ||||
-rw-r--r-- | sound/aoa/soundbus/i2sbus/i2sbus.h | 112 | ||||
-rw-r--r-- | sound/aoa/soundbus/soundbus.h | 202 | ||||
-rw-r--r-- | sound/aoa/soundbus/sysfs.c | 43 |
12 files changed, 2450 insertions, 0 deletions
diff --git a/sound/aoa/soundbus/Kconfig b/sound/aoa/soundbus/Kconfig new file mode 100644 index 000000000000..d532d27a9f54 --- /dev/null +++ b/sound/aoa/soundbus/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | config SND_AOA_SOUNDBUS | ||
2 | tristate "Apple Soundbus support" | ||
3 | depends on SOUND && SND_PCM && EXPERIMENTAL | ||
4 | ---help--- | ||
5 | This option enables the generic driver for the soundbus | ||
6 | support on Apple machines. | ||
7 | |||
8 | It is required for the sound bus implementations. | ||
9 | |||
10 | config SND_AOA_SOUNDBUS_I2S | ||
11 | tristate "I2S bus support" | ||
12 | depends on SND_AOA_SOUNDBUS && PCI | ||
13 | ---help--- | ||
14 | This option enables support for Apple I2S busses. | ||
diff --git a/sound/aoa/soundbus/Makefile b/sound/aoa/soundbus/Makefile new file mode 100644 index 000000000000..0e61f5aa06b5 --- /dev/null +++ b/sound/aoa/soundbus/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_SND_AOA_SOUNDBUS) += snd-aoa-soundbus.o | ||
2 | snd-aoa-soundbus-objs := core.o sysfs.o | ||
3 | obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += i2sbus/ | ||
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c new file mode 100644 index 000000000000..abe84a76c835 --- /dev/null +++ b/sound/aoa/soundbus/core.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * soundbus | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include "soundbus.h" | ||
11 | |||
12 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
13 | MODULE_LICENSE("GPL"); | ||
14 | MODULE_DESCRIPTION("Apple Soundbus"); | ||
15 | |||
16 | struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev) | ||
17 | { | ||
18 | struct device *tmp; | ||
19 | |||
20 | if (!dev) | ||
21 | return NULL; | ||
22 | tmp = get_device(&dev->ofdev.dev); | ||
23 | if (tmp) | ||
24 | return to_soundbus_device(tmp); | ||
25 | else | ||
26 | return NULL; | ||
27 | } | ||
28 | EXPORT_SYMBOL_GPL(soundbus_dev_get); | ||
29 | |||
30 | void soundbus_dev_put(struct soundbus_dev *dev) | ||
31 | { | ||
32 | if (dev) | ||
33 | put_device(&dev->ofdev.dev); | ||
34 | } | ||
35 | EXPORT_SYMBOL_GPL(soundbus_dev_put); | ||
36 | |||
37 | static int soundbus_probe(struct device *dev) | ||
38 | { | ||
39 | int error = -ENODEV; | ||
40 | struct soundbus_driver *drv; | ||
41 | struct soundbus_dev *soundbus_dev; | ||
42 | |||
43 | drv = to_soundbus_driver(dev->driver); | ||
44 | soundbus_dev = to_soundbus_device(dev); | ||
45 | |||
46 | if (!drv->probe) | ||
47 | return error; | ||
48 | |||
49 | soundbus_dev_get(soundbus_dev); | ||
50 | |||
51 | error = drv->probe(soundbus_dev); | ||
52 | if (error) | ||
53 | soundbus_dev_put(soundbus_dev); | ||
54 | |||
55 | return error; | ||
56 | } | ||
57 | |||
58 | |||
59 | static int soundbus_uevent(struct device *dev, char **envp, int num_envp, | ||
60 | char *buffer, int buffer_size) | ||
61 | { | ||
62 | struct soundbus_dev * soundbus_dev; | ||
63 | struct of_device * of; | ||
64 | char *scratch, *compat, *compat2; | ||
65 | int i = 0; | ||
66 | int length, cplen, cplen2, seen = 0; | ||
67 | |||
68 | if (!dev) | ||
69 | return -ENODEV; | ||
70 | |||
71 | soundbus_dev = to_soundbus_device(dev); | ||
72 | if (!soundbus_dev) | ||
73 | return -ENODEV; | ||
74 | |||
75 | of = &soundbus_dev->ofdev; | ||
76 | |||
77 | /* stuff we want to pass to /sbin/hotplug */ | ||
78 | envp[i++] = scratch = buffer; | ||
79 | length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name); | ||
80 | ++length; | ||
81 | buffer_size -= length; | ||
82 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
83 | return -ENOMEM; | ||
84 | scratch += length; | ||
85 | |||
86 | envp[i++] = scratch; | ||
87 | length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type); | ||
88 | ++length; | ||
89 | buffer_size -= length; | ||
90 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
91 | return -ENOMEM; | ||
92 | scratch += length; | ||
93 | |||
94 | /* Since the compatible field can contain pretty much anything | ||
95 | * it's not really legal to split it out with commas. We split it | ||
96 | * up using a number of environment variables instead. */ | ||
97 | |||
98 | compat = (char *) get_property(of->node, "compatible", &cplen); | ||
99 | compat2 = compat; | ||
100 | cplen2= cplen; | ||
101 | while (compat && cplen > 0) { | ||
102 | envp[i++] = scratch; | ||
103 | length = scnprintf (scratch, buffer_size, | ||
104 | "OF_COMPATIBLE_%d=%s", seen, compat); | ||
105 | ++length; | ||
106 | buffer_size -= length; | ||
107 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
108 | return -ENOMEM; | ||
109 | scratch += length; | ||
110 | length = strlen (compat) + 1; | ||
111 | compat += length; | ||
112 | cplen -= length; | ||
113 | seen++; | ||
114 | } | ||
115 | |||
116 | envp[i++] = scratch; | ||
117 | length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen); | ||
118 | ++length; | ||
119 | buffer_size -= length; | ||
120 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
121 | return -ENOMEM; | ||
122 | scratch += length; | ||
123 | |||
124 | envp[i++] = scratch; | ||
125 | length = scnprintf (scratch, buffer_size, "MODALIAS=%s", | ||
126 | soundbus_dev->modalias); | ||
127 | |||
128 | buffer_size -= length; | ||
129 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
130 | return -ENOMEM; | ||
131 | |||
132 | envp[i] = NULL; | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int soundbus_device_remove(struct device *dev) | ||
138 | { | ||
139 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
140 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
141 | |||
142 | if (dev->driver && drv->remove) | ||
143 | drv->remove(soundbus_dev); | ||
144 | soundbus_dev_put(soundbus_dev); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static void soundbus_device_shutdown(struct device *dev) | ||
150 | { | ||
151 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
152 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
153 | |||
154 | if (dev->driver && drv->shutdown) | ||
155 | drv->shutdown(soundbus_dev); | ||
156 | } | ||
157 | |||
158 | #ifdef CONFIG_PM | ||
159 | |||
160 | static int soundbus_device_suspend(struct device *dev, pm_message_t state) | ||
161 | { | ||
162 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
163 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
164 | |||
165 | if (dev->driver && drv->suspend) | ||
166 | return drv->suspend(soundbus_dev, state); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int soundbus_device_resume(struct device * dev) | ||
171 | { | ||
172 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
173 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
174 | |||
175 | if (dev->driver && drv->resume) | ||
176 | return drv->resume(soundbus_dev); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | #endif /* CONFIG_PM */ | ||
181 | |||
182 | extern struct device_attribute soundbus_dev_attrs[]; | ||
183 | |||
184 | static struct bus_type soundbus_bus_type = { | ||
185 | .name = "aoa-soundbus", | ||
186 | .probe = soundbus_probe, | ||
187 | .uevent = soundbus_uevent, | ||
188 | .remove = soundbus_device_remove, | ||
189 | .shutdown = soundbus_device_shutdown, | ||
190 | #ifdef CONFIG_PM | ||
191 | .suspend = soundbus_device_suspend, | ||
192 | .resume = soundbus_device_resume, | ||
193 | #endif | ||
194 | .dev_attrs = soundbus_dev_attrs, | ||
195 | }; | ||
196 | |||
197 | static int __init soundbus_init(void) | ||
198 | { | ||
199 | return bus_register(&soundbus_bus_type); | ||
200 | } | ||
201 | |||
202 | static void __exit soundbus_exit(void) | ||
203 | { | ||
204 | bus_unregister(&soundbus_bus_type); | ||
205 | } | ||
206 | |||
207 | int soundbus_add_one(struct soundbus_dev *dev) | ||
208 | { | ||
209 | static int devcount; | ||
210 | |||
211 | /* sanity checks */ | ||
212 | if (!dev->attach_codec || | ||
213 | !dev->ofdev.node || | ||
214 | dev->pcmname || | ||
215 | dev->pcmid != -1) { | ||
216 | printk(KERN_ERR "soundbus: adding device failed sanity check!\n"); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | snprintf(dev->ofdev.dev.bus_id, BUS_ID_SIZE, "soundbus:%x", ++devcount); | ||
221 | dev->ofdev.dev.bus = &soundbus_bus_type; | ||
222 | return of_device_register(&dev->ofdev); | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(soundbus_add_one); | ||
225 | |||
226 | void soundbus_remove_one(struct soundbus_dev *dev) | ||
227 | { | ||
228 | of_device_unregister(&dev->ofdev); | ||
229 | } | ||
230 | EXPORT_SYMBOL_GPL(soundbus_remove_one); | ||
231 | |||
232 | int soundbus_register_driver(struct soundbus_driver *drv) | ||
233 | { | ||
234 | /* initialize common driver fields */ | ||
235 | drv->driver.name = drv->name; | ||
236 | drv->driver.bus = &soundbus_bus_type; | ||
237 | |||
238 | /* register with core */ | ||
239 | return driver_register(&drv->driver); | ||
240 | } | ||
241 | EXPORT_SYMBOL_GPL(soundbus_register_driver); | ||
242 | |||
243 | void soundbus_unregister_driver(struct soundbus_driver *drv) | ||
244 | { | ||
245 | driver_unregister(&drv->driver); | ||
246 | } | ||
247 | EXPORT_SYMBOL_GPL(soundbus_unregister_driver); | ||
248 | |||
249 | module_init(soundbus_init); | ||
250 | module_exit(soundbus_exit); | ||
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile new file mode 100644 index 000000000000..e57a5cf65655 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o | ||
2 | snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/i2sbus-control.c new file mode 100644 index 000000000000..f50407952d3c --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * i2sbus driver -- bus control routines | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | |||
9 | #include <asm/io.h> | ||
10 | #include <linux/delay.h> | ||
11 | #include <asm/prom.h> | ||
12 | #include <asm/macio.h> | ||
13 | #include <asm/pmac_feature.h> | ||
14 | #include <asm/pmac_pfunc.h> | ||
15 | #include "i2sbus.h" | ||
16 | |||
17 | int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) | ||
18 | { | ||
19 | *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL); | ||
20 | if (!*c) | ||
21 | return -ENOMEM; | ||
22 | |||
23 | INIT_LIST_HEAD(&(*c)->list); | ||
24 | |||
25 | if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc)) | ||
26 | goto err; | ||
27 | /* we really should be using feature calls instead of mapping | ||
28 | * these registers. It's safe for now since no one else is | ||
29 | * touching them... */ | ||
30 | (*c)->controlregs = ioremap((*c)->rsrc.start, | ||
31 | sizeof(struct i2s_control_regs)); | ||
32 | if (!(*c)->controlregs) | ||
33 | goto err; | ||
34 | |||
35 | return 0; | ||
36 | err: | ||
37 | kfree(*c); | ||
38 | *c = NULL; | ||
39 | return -ENODEV; | ||
40 | } | ||
41 | |||
42 | void i2sbus_control_destroy(struct i2sbus_control *c) | ||
43 | { | ||
44 | iounmap(c->controlregs); | ||
45 | kfree(c); | ||
46 | } | ||
47 | |||
48 | /* this is serialised externally */ | ||
49 | int i2sbus_control_add_dev(struct i2sbus_control *c, | ||
50 | struct i2sbus_dev *i2sdev) | ||
51 | { | ||
52 | struct device_node *np; | ||
53 | |||
54 | np = i2sdev->sound.ofdev.node; | ||
55 | i2sdev->enable = pmf_find_function(np, "enable"); | ||
56 | i2sdev->cell_enable = pmf_find_function(np, "cell-enable"); | ||
57 | i2sdev->clock_enable = pmf_find_function(np, "clock-enable"); | ||
58 | i2sdev->cell_disable = pmf_find_function(np, "cell-disable"); | ||
59 | i2sdev->clock_disable = pmf_find_function(np, "clock-disable"); | ||
60 | |||
61 | /* if the bus number is not 0 or 1 we absolutely need to use | ||
62 | * the platform functions -- there's nothing in Darwin that | ||
63 | * would allow seeing a system behind what the FCRs are then, | ||
64 | * and I don't want to go parsing a bunch of platform functions | ||
65 | * by hand to try finding a system... */ | ||
66 | if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 && | ||
67 | (!i2sdev->enable || | ||
68 | !i2sdev->cell_enable || !i2sdev->clock_enable || | ||
69 | !i2sdev->cell_disable || !i2sdev->clock_disable)) { | ||
70 | pmf_put_function(i2sdev->enable); | ||
71 | pmf_put_function(i2sdev->cell_enable); | ||
72 | pmf_put_function(i2sdev->clock_enable); | ||
73 | pmf_put_function(i2sdev->cell_disable); | ||
74 | pmf_put_function(i2sdev->clock_disable); | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | |||
78 | list_add(&i2sdev->item, &c->list); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | void i2sbus_control_remove_dev(struct i2sbus_control *c, | ||
84 | struct i2sbus_dev *i2sdev) | ||
85 | { | ||
86 | /* this is serialised externally */ | ||
87 | list_del(&i2sdev->item); | ||
88 | if (list_empty(&c->list)) | ||
89 | i2sbus_control_destroy(c); | ||
90 | } | ||
91 | |||
92 | int i2sbus_control_enable(struct i2sbus_control *c, | ||
93 | struct i2sbus_dev *i2sdev) | ||
94 | { | ||
95 | struct pmf_args args = { .count = 0 }; | ||
96 | int cc; | ||
97 | |||
98 | if (i2sdev->enable) | ||
99 | return pmf_call_one(i2sdev->enable, &args); | ||
100 | |||
101 | switch (i2sdev->bus_number) { | ||
102 | case 0: | ||
103 | cc = in_le32(&c->controlregs->cell_control); | ||
104 | out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE); | ||
105 | break; | ||
106 | case 1: | ||
107 | cc = in_le32(&c->controlregs->cell_control); | ||
108 | out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE); | ||
109 | break; | ||
110 | default: | ||
111 | return -ENODEV; | ||
112 | } | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | int i2sbus_control_cell(struct i2sbus_control *c, | ||
117 | struct i2sbus_dev *i2sdev, | ||
118 | int enable) | ||
119 | { | ||
120 | struct pmf_args args = { .count = 0 }; | ||
121 | int cc; | ||
122 | |||
123 | switch (enable) { | ||
124 | case 0: | ||
125 | if (i2sdev->cell_disable) | ||
126 | return pmf_call_one(i2sdev->cell_disable, &args); | ||
127 | break; | ||
128 | case 1: | ||
129 | if (i2sdev->cell_enable) | ||
130 | return pmf_call_one(i2sdev->cell_enable, &args); | ||
131 | break; | ||
132 | default: | ||
133 | printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n"); | ||
134 | return -ENODEV; | ||
135 | } | ||
136 | switch (i2sdev->bus_number) { | ||
137 | case 0: | ||
138 | cc = in_le32(&c->controlregs->cell_control); | ||
139 | cc &= ~CTRL_CLOCK_CELL_0_ENABLE; | ||
140 | cc |= enable * CTRL_CLOCK_CELL_0_ENABLE; | ||
141 | out_le32(&c->controlregs->cell_control, cc); | ||
142 | break; | ||
143 | case 1: | ||
144 | cc = in_le32(&c->controlregs->cell_control); | ||
145 | cc &= ~CTRL_CLOCK_CELL_1_ENABLE; | ||
146 | cc |= enable * CTRL_CLOCK_CELL_1_ENABLE; | ||
147 | out_le32(&c->controlregs->cell_control, cc); | ||
148 | break; | ||
149 | default: | ||
150 | return -ENODEV; | ||
151 | } | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | int i2sbus_control_clock(struct i2sbus_control *c, | ||
156 | struct i2sbus_dev *i2sdev, | ||
157 | int enable) | ||
158 | { | ||
159 | struct pmf_args args = { .count = 0 }; | ||
160 | int cc; | ||
161 | |||
162 | switch (enable) { | ||
163 | case 0: | ||
164 | if (i2sdev->clock_disable) | ||
165 | return pmf_call_one(i2sdev->clock_disable, &args); | ||
166 | break; | ||
167 | case 1: | ||
168 | if (i2sdev->clock_enable) | ||
169 | return pmf_call_one(i2sdev->clock_enable, &args); | ||
170 | break; | ||
171 | default: | ||
172 | printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n"); | ||
173 | return -ENODEV; | ||
174 | } | ||
175 | switch (i2sdev->bus_number) { | ||
176 | case 0: | ||
177 | cc = in_le32(&c->controlregs->cell_control); | ||
178 | cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE; | ||
179 | cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE; | ||
180 | out_le32(&c->controlregs->cell_control, cc); | ||
181 | break; | ||
182 | case 1: | ||
183 | cc = in_le32(&c->controlregs->cell_control); | ||
184 | cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE; | ||
185 | cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE; | ||
186 | out_le32(&c->controlregs->cell_control, cc); | ||
187 | break; | ||
188 | default: | ||
189 | return -ENODEV; | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.h b/sound/aoa/soundbus/i2sbus/i2sbus-control.h new file mode 100644 index 000000000000..bb05550f730b --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * i2sbus driver -- bus register definitions | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | #ifndef __I2SBUS_CONTROLREGS_H | ||
9 | #define __I2SBUS_CONTROLREGS_H | ||
10 | |||
11 | /* i2s control registers, at least what we know about them */ | ||
12 | |||
13 | #define __PAD(m,n) u8 __pad##m[n] | ||
14 | #define _PAD(line, n) __PAD(line, n) | ||
15 | #define PAD(n) _PAD(__LINE__, (n)) | ||
16 | struct i2s_control_regs { | ||
17 | PAD(0x38); | ||
18 | __le32 fcr0; /* 0x38 (unknown) */ | ||
19 | __le32 cell_control; /* 0x3c (fcr1) */ | ||
20 | __le32 fcr2; /* 0x40 (unknown) */ | ||
21 | __le32 fcr3; /* 0x44 (fcr3) */ | ||
22 | __le32 clock_control; /* 0x48 (unknown) */ | ||
23 | PAD(4); | ||
24 | /* total size: 0x50 bytes */ | ||
25 | } __attribute__((__packed__)); | ||
26 | |||
27 | #define CTRL_CLOCK_CELL_0_ENABLE (1<<10) | ||
28 | #define CTRL_CLOCK_CLOCK_0_ENABLE (1<<12) | ||
29 | #define CTRL_CLOCK_SWRESET_0 (1<<11) | ||
30 | #define CTRL_CLOCK_INTF_0_ENABLE (1<<13) | ||
31 | |||
32 | #define CTRL_CLOCK_CELL_1_ENABLE (1<<17) | ||
33 | #define CTRL_CLOCK_CLOCK_1_ENABLE (1<<18) | ||
34 | #define CTRL_CLOCK_SWRESET_1 (1<<19) | ||
35 | #define CTRL_CLOCK_INTF_1_ENABLE (1<<20) | ||
36 | |||
37 | #endif /* __I2SBUS_CONTROLREGS_H */ | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c new file mode 100644 index 000000000000..f268dacdaa00 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * i2sbus driver | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <asm/macio.h> | ||
11 | #include <asm/dbdma.h> | ||
12 | #include <linux/pci.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <sound/driver.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include "../soundbus.h" | ||
18 | #include "i2sbus.h" | ||
19 | |||
20 | MODULE_LICENSE("GPL"); | ||
21 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
22 | MODULE_DESCRIPTION("Apple Soundbus: I2S support"); | ||
23 | /* for auto-loading, declare that we handle this weird | ||
24 | * string that macio puts into the relevant device */ | ||
25 | MODULE_ALIAS("of:Ni2sTi2sC"); | ||
26 | |||
27 | static struct of_device_id i2sbus_match[] = { | ||
28 | { .name = "i2s" }, | ||
29 | { } | ||
30 | }; | ||
31 | |||
32 | static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, | ||
33 | struct dbdma_command_mem *r, | ||
34 | int numcmds) | ||
35 | { | ||
36 | /* one more for rounding */ | ||
37 | r->size = (numcmds+1) * sizeof(struct dbdma_cmd); | ||
38 | /* We use the PCI APIs for now until the generic one gets fixed | ||
39 | * enough or until we get some macio-specific versions | ||
40 | */ | ||
41 | r->space = dma_alloc_coherent( | ||
42 | &macio_get_pci_dev(i2sdev->macio)->dev, | ||
43 | r->size, | ||
44 | &r->bus_addr, | ||
45 | GFP_KERNEL); | ||
46 | |||
47 | if (!r->space) return -ENOMEM; | ||
48 | |||
49 | memset(r->space, 0, r->size); | ||
50 | r->cmds = (void*)DBDMA_ALIGN(r->space); | ||
51 | r->bus_cmd_start = r->bus_addr + | ||
52 | (dma_addr_t)((char*)r->cmds - (char*)r->space); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, | ||
58 | struct dbdma_command_mem *r) | ||
59 | { | ||
60 | if (!r->space) return; | ||
61 | |||
62 | dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, | ||
63 | r->size, r->space, r->bus_addr); | ||
64 | } | ||
65 | |||
66 | static void i2sbus_release_dev(struct device *dev) | ||
67 | { | ||
68 | struct i2sbus_dev *i2sdev; | ||
69 | int i; | ||
70 | |||
71 | i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev); | ||
72 | |||
73 | if (i2sdev->intfregs) iounmap(i2sdev->intfregs); | ||
74 | if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); | ||
75 | if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); | ||
76 | for (i=0;i<3;i++) | ||
77 | if (i2sdev->allocated_resource[i]) | ||
78 | release_and_free_resource(i2sdev->allocated_resource[i]); | ||
79 | free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); | ||
80 | free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring); | ||
81 | for (i=0;i<3;i++) | ||
82 | free_irq(i2sdev->interrupts[i], i2sdev); | ||
83 | i2sbus_control_remove_dev(i2sdev->control, i2sdev); | ||
84 | mutex_destroy(&i2sdev->lock); | ||
85 | kfree(i2sdev); | ||
86 | } | ||
87 | |||
88 | static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs) | ||
89 | { | ||
90 | struct i2sbus_dev *dev = devid; | ||
91 | u32 intreg; | ||
92 | |||
93 | spin_lock(&dev->low_lock); | ||
94 | intreg = in_le32(&dev->intfregs->intr_ctl); | ||
95 | |||
96 | /* acknowledge interrupt reasons */ | ||
97 | out_le32(&dev->intfregs->intr_ctl, intreg); | ||
98 | |||
99 | spin_unlock(&dev->low_lock); | ||
100 | |||
101 | return IRQ_HANDLED; | ||
102 | } | ||
103 | |||
104 | static int force; | ||
105 | module_param(force, int, 0444); | ||
106 | MODULE_PARM_DESC(force, "Force loading i2sbus even when" | ||
107 | " no layout-id property is present"); | ||
108 | |||
109 | /* FIXME: look at device node refcounting */ | ||
110 | static int i2sbus_add_dev(struct macio_dev *macio, | ||
111 | struct i2sbus_control *control, | ||
112 | struct device_node *np) | ||
113 | { | ||
114 | struct i2sbus_dev *dev; | ||
115 | struct device_node *child = NULL, *sound = NULL; | ||
116 | int i; | ||
117 | static const char *rnames[] = { "i2sbus: %s (control)", | ||
118 | "i2sbus: %s (tx)", | ||
119 | "i2sbus: %s (rx)" }; | ||
120 | static irqreturn_t (*ints[])(int irq, void *devid, | ||
121 | struct pt_regs *regs) = { | ||
122 | i2sbus_bus_intr, | ||
123 | i2sbus_tx_intr, | ||
124 | i2sbus_rx_intr | ||
125 | }; | ||
126 | |||
127 | if (strlen(np->name) != 5) | ||
128 | return 0; | ||
129 | if (strncmp(np->name, "i2s-", 4)) | ||
130 | return 0; | ||
131 | |||
132 | if (np->n_intrs != 3) | ||
133 | return 0; | ||
134 | |||
135 | dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); | ||
136 | if (!dev) | ||
137 | return 0; | ||
138 | |||
139 | i = 0; | ||
140 | while ((child = of_get_next_child(np, child))) { | ||
141 | if (strcmp(child->name, "sound") == 0) { | ||
142 | i++; | ||
143 | sound = child; | ||
144 | } | ||
145 | } | ||
146 | if (i == 1) { | ||
147 | u32 *layout_id; | ||
148 | layout_id = (u32*) get_property(sound, "layout-id", NULL); | ||
149 | if (layout_id) { | ||
150 | snprintf(dev->sound.modalias, 32, | ||
151 | "sound-layout-%d", *layout_id); | ||
152 | force = 1; | ||
153 | } | ||
154 | } | ||
155 | /* for the time being, until we can handle non-layout-id | ||
156 | * things in some fabric, refuse to attach if there is no | ||
157 | * layout-id property or we haven't been forced to attach. | ||
158 | * When there are two i2s busses and only one has a layout-id, | ||
159 | * then this depends on the order, but that isn't important | ||
160 | * either as the second one in that case is just a modem. */ | ||
161 | if (!force) { | ||
162 | kfree(dev); | ||
163 | return -ENODEV; | ||
164 | } | ||
165 | |||
166 | mutex_init(&dev->lock); | ||
167 | spin_lock_init(&dev->low_lock); | ||
168 | dev->sound.ofdev.node = np; | ||
169 | dev->sound.ofdev.dma_mask = macio->ofdev.dma_mask; | ||
170 | dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.dma_mask; | ||
171 | dev->sound.ofdev.dev.parent = &macio->ofdev.dev; | ||
172 | dev->sound.ofdev.dev.release = i2sbus_release_dev; | ||
173 | dev->sound.attach_codec = i2sbus_attach_codec; | ||
174 | dev->sound.detach_codec = i2sbus_detach_codec; | ||
175 | dev->sound.pcmid = -1; | ||
176 | dev->macio = macio; | ||
177 | dev->control = control; | ||
178 | dev->bus_number = np->name[4] - 'a'; | ||
179 | INIT_LIST_HEAD(&dev->sound.codec_list); | ||
180 | |||
181 | for (i=0;i<3;i++) { | ||
182 | dev->interrupts[i] = -1; | ||
183 | snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name); | ||
184 | } | ||
185 | for (i=0;i<3;i++) { | ||
186 | if (request_irq(np->intrs[i].line, ints[i], 0, dev->rnames[i], dev)) | ||
187 | goto err; | ||
188 | dev->interrupts[i] = np->intrs[i].line; | ||
189 | } | ||
190 | |||
191 | for (i=0;i<3;i++) { | ||
192 | if (of_address_to_resource(np, i, &dev->resources[i])) | ||
193 | goto err; | ||
194 | /* if only we could use our resource dev->resources[i]... | ||
195 | * but request_resource doesn't know about parents and | ||
196 | * contained resources... */ | ||
197 | dev->allocated_resource[i] = | ||
198 | request_mem_region(dev->resources[i].start, | ||
199 | dev->resources[i].end - | ||
200 | dev->resources[i].start + 1, | ||
201 | dev->rnames[i]); | ||
202 | if (!dev->allocated_resource[i]) { | ||
203 | printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i); | ||
204 | goto err; | ||
205 | } | ||
206 | } | ||
207 | /* should do sanity checking here about length of them */ | ||
208 | dev->intfregs = ioremap(dev->resources[0].start, | ||
209 | dev->resources[0].end-dev->resources[0].start+1); | ||
210 | dev->out.dbdma = ioremap(dev->resources[1].start, | ||
211 | dev->resources[1].end-dev->resources[1].start+1); | ||
212 | dev->in.dbdma = ioremap(dev->resources[2].start, | ||
213 | dev->resources[2].end-dev->resources[2].start+1); | ||
214 | if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma) | ||
215 | goto err; | ||
216 | |||
217 | if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring, | ||
218 | MAX_DBDMA_COMMANDS)) | ||
219 | goto err; | ||
220 | if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring, | ||
221 | MAX_DBDMA_COMMANDS)) | ||
222 | goto err; | ||
223 | |||
224 | if (i2sbus_control_add_dev(dev->control, dev)) { | ||
225 | printk(KERN_ERR "i2sbus: control layer didn't like bus\n"); | ||
226 | goto err; | ||
227 | } | ||
228 | |||
229 | if (soundbus_add_one(&dev->sound)) { | ||
230 | printk(KERN_DEBUG "i2sbus: device registration error!\n"); | ||
231 | goto err; | ||
232 | } | ||
233 | |||
234 | /* enable this cell */ | ||
235 | i2sbus_control_cell(dev->control, dev, 1); | ||
236 | i2sbus_control_enable(dev->control, dev); | ||
237 | i2sbus_control_clock(dev->control, dev, 1); | ||
238 | |||
239 | return 1; | ||
240 | err: | ||
241 | for (i=0;i<3;i++) | ||
242 | if (dev->interrupts[i] != -1) | ||
243 | free_irq(dev->interrupts[i], dev); | ||
244 | free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring); | ||
245 | free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring); | ||
246 | if (dev->intfregs) iounmap(dev->intfregs); | ||
247 | if (dev->out.dbdma) iounmap(dev->out.dbdma); | ||
248 | if (dev->in.dbdma) iounmap(dev->in.dbdma); | ||
249 | for (i=0;i<3;i++) | ||
250 | if (dev->allocated_resource[i]) | ||
251 | release_and_free_resource(dev->allocated_resource[i]); | ||
252 | mutex_destroy(&dev->lock); | ||
253 | kfree(dev); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) | ||
258 | { | ||
259 | struct device_node *np = NULL; | ||
260 | int got = 0, err; | ||
261 | struct i2sbus_control *control = NULL; | ||
262 | |||
263 | err = i2sbus_control_init(dev, &control); | ||
264 | if (err) | ||
265 | return err; | ||
266 | if (!control) { | ||
267 | printk(KERN_ERR "i2sbus_control_init API breakage\n"); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | while ((np = of_get_next_child(dev->ofdev.node, np))) { | ||
272 | if (device_is_compatible(np, "i2sbus") || | ||
273 | device_is_compatible(np, "i2s-modem")) { | ||
274 | got += i2sbus_add_dev(dev, control, np); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | if (!got) { | ||
279 | /* found none, clean up */ | ||
280 | i2sbus_control_destroy(control); | ||
281 | return -ENODEV; | ||
282 | } | ||
283 | |||
284 | dev->ofdev.dev.driver_data = control; | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int i2sbus_remove(struct macio_dev* dev) | ||
290 | { | ||
291 | struct i2sbus_control *control = dev->ofdev.dev.driver_data; | ||
292 | struct i2sbus_dev *i2sdev, *tmp; | ||
293 | |||
294 | list_for_each_entry_safe(i2sdev, tmp, &control->list, item) | ||
295 | soundbus_remove_one(&i2sdev->sound); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | #ifdef CONFIG_PM | ||
301 | static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) | ||
302 | { | ||
303 | struct i2sbus_control *control = dev->ofdev.dev.driver_data; | ||
304 | struct codec_info_item *cii; | ||
305 | struct i2sbus_dev* i2sdev; | ||
306 | int err, ret = 0; | ||
307 | |||
308 | list_for_each_entry(i2sdev, &control->list, item) { | ||
309 | /* Notify Alsa */ | ||
310 | if (i2sdev->sound.pcm) { | ||
311 | /* Suspend PCM streams */ | ||
312 | snd_pcm_suspend_all(i2sdev->sound.pcm); | ||
313 | /* Probably useless as we handle | ||
314 | * power transitions ourselves */ | ||
315 | snd_power_change_state(i2sdev->sound.pcm->card, | ||
316 | SNDRV_CTL_POWER_D3hot); | ||
317 | } | ||
318 | /* Notify codecs */ | ||
319 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
320 | err = 0; | ||
321 | if (cii->codec->suspend) | ||
322 | err = cii->codec->suspend(cii, state); | ||
323 | if (err) | ||
324 | ret = err; | ||
325 | } | ||
326 | } | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int i2sbus_resume(struct macio_dev* dev) | ||
331 | { | ||
332 | struct i2sbus_control *control = dev->ofdev.dev.driver_data; | ||
333 | struct codec_info_item *cii; | ||
334 | struct i2sbus_dev* i2sdev; | ||
335 | int err, ret = 0; | ||
336 | |||
337 | list_for_each_entry(i2sdev, &control->list, item) { | ||
338 | /* Notify codecs so they can re-initialize */ | ||
339 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
340 | err = 0; | ||
341 | if (cii->codec->resume) | ||
342 | err = cii->codec->resume(cii); | ||
343 | if (err) | ||
344 | ret = err; | ||
345 | } | ||
346 | /* Notify Alsa */ | ||
347 | if (i2sdev->sound.pcm) { | ||
348 | /* Same comment as above, probably useless */ | ||
349 | snd_power_change_state(i2sdev->sound.pcm->card, | ||
350 | SNDRV_CTL_POWER_D0); | ||
351 | } | ||
352 | } | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | #endif /* CONFIG_PM */ | ||
357 | |||
358 | static int i2sbus_shutdown(struct macio_dev* dev) | ||
359 | { | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static struct macio_driver i2sbus_drv = { | ||
364 | .name = "soundbus-i2s", | ||
365 | .owner = THIS_MODULE, | ||
366 | .match_table = i2sbus_match, | ||
367 | .probe = i2sbus_probe, | ||
368 | .remove = i2sbus_remove, | ||
369 | #ifdef CONFIG_PM | ||
370 | .suspend = i2sbus_suspend, | ||
371 | .resume = i2sbus_resume, | ||
372 | #endif | ||
373 | .shutdown = i2sbus_shutdown, | ||
374 | }; | ||
375 | |||
376 | static int __init soundbus_i2sbus_init(void) | ||
377 | { | ||
378 | return macio_register_driver(&i2sbus_drv); | ||
379 | } | ||
380 | |||
381 | static void __exit soundbus_i2sbus_exit(void) | ||
382 | { | ||
383 | macio_unregister_driver(&i2sbus_drv); | ||
384 | } | ||
385 | |||
386 | module_init(soundbus_i2sbus_init); | ||
387 | module_exit(soundbus_i2sbus_exit); | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h new file mode 100644 index 000000000000..c6b5f5452d20 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * i2sbus driver -- interface register definitions | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | #ifndef __I2SBUS_INTERFACE_H | ||
9 | #define __I2SBUS_INTERFACE_H | ||
10 | |||
11 | /* i2s bus control registers, at least what we know about them */ | ||
12 | |||
13 | #define __PAD(m,n) u8 __pad##m[n] | ||
14 | #define _PAD(line, n) __PAD(line, n) | ||
15 | #define PAD(n) _PAD(__LINE__, (n)) | ||
16 | struct i2s_interface_regs { | ||
17 | __le32 intr_ctl; /* 0x00 */ | ||
18 | PAD(12); | ||
19 | __le32 serial_format; /* 0x10 */ | ||
20 | PAD(12); | ||
21 | __le32 codec_msg_out; /* 0x20 */ | ||
22 | PAD(12); | ||
23 | __le32 codec_msg_in; /* 0x30 */ | ||
24 | PAD(12); | ||
25 | __le32 frame_count; /* 0x40 */ | ||
26 | PAD(12); | ||
27 | __le32 frame_match; /* 0x50 */ | ||
28 | PAD(12); | ||
29 | __le32 data_word_sizes; /* 0x60 */ | ||
30 | PAD(12); | ||
31 | __le32 peak_level_sel; /* 0x70 */ | ||
32 | PAD(12); | ||
33 | __le32 peak_level_in0; /* 0x80 */ | ||
34 | PAD(12); | ||
35 | __le32 peak_level_in1; /* 0x90 */ | ||
36 | PAD(12); | ||
37 | /* total size: 0x100 bytes */ | ||
38 | } __attribute__((__packed__)); | ||
39 | |||
40 | /* interrupt register is just a bitfield with | ||
41 | * interrupt enable and pending bits */ | ||
42 | #define I2S_REG_INTR_CTL 0x00 | ||
43 | # define I2S_INT_FRAME_COUNT (1<<31) | ||
44 | # define I2S_PENDING_FRAME_COUNT (1<<30) | ||
45 | # define I2S_INT_MESSAGE_FLAG (1<<29) | ||
46 | # define I2S_PENDING_MESSAGE_FLAG (1<<28) | ||
47 | # define I2S_INT_NEW_PEAK (1<<27) | ||
48 | # define I2S_PENDING_NEW_PEAK (1<<26) | ||
49 | # define I2S_INT_CLOCKS_STOPPED (1<<25) | ||
50 | # define I2S_PENDING_CLOCKS_STOPPED (1<<24) | ||
51 | # define I2S_INT_EXTERNAL_SYNC_ERROR (1<<23) | ||
52 | # define I2S_PENDING_EXTERNAL_SYNC_ERROR (1<<22) | ||
53 | # define I2S_INT_EXTERNAL_SYNC_OK (1<<21) | ||
54 | # define I2S_PENDING_EXTERNAL_SYNC_OK (1<<20) | ||
55 | # define I2S_INT_NEW_SAMPLE_RATE (1<<19) | ||
56 | # define I2S_PENDING_NEW_SAMPLE_RATE (1<<18) | ||
57 | # define I2S_INT_STATUS_FLAG (1<<17) | ||
58 | # define I2S_PENDING_STATUS_FLAG (1<<16) | ||
59 | |||
60 | /* serial format register is more interesting :) | ||
61 | * It contains: | ||
62 | * - clock source | ||
63 | * - MClk divisor | ||
64 | * - SClk divisor | ||
65 | * - SClk master flag | ||
66 | * - serial format (sony, i2s 64x, i2s 32x, dav, silabs) | ||
67 | * - external sample frequency interrupt (don't understand) | ||
68 | * - external sample frequency | ||
69 | */ | ||
70 | #define I2S_REG_SERIAL_FORMAT 0x10 | ||
71 | /* clock source. You get either 18.432, 45.1584 or 49.1520 MHz */ | ||
72 | # define I2S_SF_CLOCK_SOURCE_SHIFT 30 | ||
73 | # define I2S_SF_CLOCK_SOURCE_MASK (3<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
74 | # define I2S_SF_CLOCK_SOURCE_18MHz (0<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
75 | # define I2S_SF_CLOCK_SOURCE_45MHz (1<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
76 | # define I2S_SF_CLOCK_SOURCE_49MHz (2<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
77 | /* also, let's define the exact clock speeds here, in Hz */ | ||
78 | #define I2S_CLOCK_SPEED_18MHz 18432000 | ||
79 | #define I2S_CLOCK_SPEED_45MHz 45158400 | ||
80 | #define I2S_CLOCK_SPEED_49MHz 49152000 | ||
81 | /* MClk is the clock that drives the codec, usually called its 'system clock'. | ||
82 | * It is derived by taking only every 'divisor' tick of the clock. | ||
83 | */ | ||
84 | # define I2S_SF_MCLKDIV_SHIFT 24 | ||
85 | # define I2S_SF_MCLKDIV_MASK (0x1F<<I2S_SF_MCLKDIV_SHIFT) | ||
86 | # define I2S_SF_MCLKDIV_1 (0x14<<I2S_SF_MCLKDIV_SHIFT) | ||
87 | # define I2S_SF_MCLKDIV_3 (0x13<<I2S_SF_MCLKDIV_SHIFT) | ||
88 | # define I2S_SF_MCLKDIV_5 (0x12<<I2S_SF_MCLKDIV_SHIFT) | ||
89 | # define I2S_SF_MCLKDIV_14 (0x0E<<I2S_SF_MCLKDIV_SHIFT) | ||
90 | # define I2S_SF_MCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_MCLKDIV_SHIFT)&I2S_SF_MCLKDIV_MASK) | ||
91 | static inline int i2s_sf_mclkdiv(int div, int *out) | ||
92 | { | ||
93 | int d; | ||
94 | |||
95 | switch(div) { | ||
96 | case 1: *out |= I2S_SF_MCLKDIV_1; return 0; | ||
97 | case 3: *out |= I2S_SF_MCLKDIV_3; return 0; | ||
98 | case 5: *out |= I2S_SF_MCLKDIV_5; return 0; | ||
99 | case 14: *out |= I2S_SF_MCLKDIV_14; return 0; | ||
100 | default: | ||
101 | if (div%2) return -1; | ||
102 | d = div/2-1; | ||
103 | if (d == 0x14 || d == 0x13 || d == 0x12 || d == 0x0E) | ||
104 | return -1; | ||
105 | *out |= I2S_SF_MCLKDIV_OTHER(div); | ||
106 | return 0; | ||
107 | } | ||
108 | } | ||
109 | /* SClk is the clock that drives the i2s wire bus. Note that it is | ||
110 | * derived from the MClk above by taking only every 'divisor' tick | ||
111 | * of MClk. | ||
112 | */ | ||
113 | # define I2S_SF_SCLKDIV_SHIFT 20 | ||
114 | # define I2S_SF_SCLKDIV_MASK (0xF<<I2S_SF_SCLKDIV_SHIFT) | ||
115 | # define I2S_SF_SCLKDIV_1 (8<<I2S_SF_SCLKDIV_SHIFT) | ||
116 | # define I2S_SF_SCLKDIV_3 (9<<I2S_SF_SCLKDIV_SHIFT) | ||
117 | # define I2S_SF_SCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_SCLKDIV_SHIFT)&I2S_SF_SCLKDIV_MASK) | ||
118 | static inline int i2s_sf_sclkdiv(int div, int *out) | ||
119 | { | ||
120 | int d; | ||
121 | |||
122 | switch(div) { | ||
123 | case 1: *out |= I2S_SF_SCLKDIV_1; return 0; | ||
124 | case 3: *out |= I2S_SF_SCLKDIV_3; return 0; | ||
125 | default: | ||
126 | if (div%2) return -1; | ||
127 | d = div/2-1; | ||
128 | if (d == 8 || d == 9) return -1; | ||
129 | *out |= I2S_SF_SCLKDIV_OTHER(div); | ||
130 | return 0; | ||
131 | } | ||
132 | } | ||
133 | # define I2S_SF_SCLK_MASTER (1<<19) | ||
134 | /* serial format is the way the data is put to the i2s wire bus */ | ||
135 | # define I2S_SF_SERIAL_FORMAT_SHIFT 16 | ||
136 | # define I2S_SF_SERIAL_FORMAT_MASK (7<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
137 | # define I2S_SF_SERIAL_FORMAT_SONY (0<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
138 | # define I2S_SF_SERIAL_FORMAT_I2S_64X (1<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
139 | # define I2S_SF_SERIAL_FORMAT_I2S_32X (2<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
140 | # define I2S_SF_SERIAL_FORMAT_I2S_DAV (4<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
141 | # define I2S_SF_SERIAL_FORMAT_I2S_SILABS (5<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
142 | /* unknown */ | ||
143 | # define I2S_SF_EXT_SAMPLE_FREQ_INT_SHIFT 12 | ||
144 | # define I2S_SF_EXT_SAMPLE_FREQ_INT_MASK (0xF<<I2S_SF_SAMPLE_FREQ_INT_SHIFT) | ||
145 | /* probably gives external frequency? */ | ||
146 | # define I2S_SF_EXT_SAMPLE_FREQ_MASK 0xFFF | ||
147 | |||
148 | /* used to send codec messages, but how isn't clear */ | ||
149 | #define I2S_REG_CODEC_MSG_OUT 0x20 | ||
150 | |||
151 | /* used to receive codec messages, but how isn't clear */ | ||
152 | #define I2S_REG_CODEC_MSG_IN 0x30 | ||
153 | |||
154 | /* frame count reg isn't clear to me yet, but probably useful */ | ||
155 | #define I2S_REG_FRAME_COUNT 0x40 | ||
156 | |||
157 | /* program to some value, and get interrupt if frame count reaches it */ | ||
158 | #define I2S_REG_FRAME_MATCH 0x50 | ||
159 | |||
160 | /* this register describes how the bus transfers data */ | ||
161 | #define I2S_REG_DATA_WORD_SIZES 0x60 | ||
162 | /* number of interleaved input channels */ | ||
163 | # define I2S_DWS_NUM_CHANNELS_IN_SHIFT 24 | ||
164 | # define I2S_DWS_NUM_CHANNELS_IN_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_IN_SHIFT) | ||
165 | /* word size of input data */ | ||
166 | # define I2S_DWS_DATA_IN_SIZE_SHIFT 16 | ||
167 | # define I2S_DWS_DATA_IN_16BIT (0<<I2S_DWS_DATA_IN_SIZE_SHIFT) | ||
168 | # define I2S_DWS_DATA_IN_24BIT (3<<I2S_DWS_DATA_IN_SIZE_SHIFT) | ||
169 | /* number of interleaved output channels */ | ||
170 | # define I2S_DWS_NUM_CHANNELS_OUT_SHIFT 8 | ||
171 | # define I2S_DWS_NUM_CHANNELS_OUT_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | ||
172 | /* word size of output data */ | ||
173 | # define I2S_DWS_DATA_OUT_SIZE_SHIFT 0 | ||
174 | # define I2S_DWS_DATA_OUT_16BIT (0<<I2S_DWS_DATA_OUT_SIZE_SHIFT) | ||
175 | # define I2S_DWS_DATA_OUT_24BIT (3<<I2S_DWS_DATA_OUT_SIZE_SHIFT) | ||
176 | |||
177 | |||
178 | /* unknown */ | ||
179 | #define I2S_REG_PEAK_LEVEL_SEL 0x70 | ||
180 | |||
181 | /* unknown */ | ||
182 | #define I2S_REG_PEAK_LEVEL_IN0 0x80 | ||
183 | |||
184 | /* unknown */ | ||
185 | #define I2S_REG_PEAK_LEVEL_IN1 0x90 | ||
186 | |||
187 | #endif /* __I2SBUS_INTERFACE_H */ | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c new file mode 100644 index 000000000000..3049015a04f1 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | * i2sbus driver -- pcm routines | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | |||
9 | #include <asm/io.h> | ||
10 | #include <linux/delay.h> | ||
11 | /* So apparently there's a reason for requiring driver.h | ||
12 | * to be included first, even if I don't know it... */ | ||
13 | #include <sound/driver.h> | ||
14 | #include <sound/core.h> | ||
15 | #include <asm/macio.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include "../soundbus.h" | ||
18 | #include "i2sbus.h" | ||
19 | |||
20 | static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in, | ||
21 | struct pcm_info **pi, struct pcm_info **other) | ||
22 | { | ||
23 | if (in) { | ||
24 | if (pi) | ||
25 | *pi = &i2sdev->in; | ||
26 | if (other) | ||
27 | *other = &i2sdev->out; | ||
28 | } else { | ||
29 | if (pi) | ||
30 | *pi = &i2sdev->out; | ||
31 | if (other) | ||
32 | *other = &i2sdev->in; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | static int clock_and_divisors(int mclk, int sclk, int rate, int *out) | ||
37 | { | ||
38 | /* sclk must be derived from mclk! */ | ||
39 | if (mclk % sclk) | ||
40 | return -1; | ||
41 | /* derive sclk register value */ | ||
42 | if (i2s_sf_sclkdiv(mclk / sclk, out)) | ||
43 | return -1; | ||
44 | |||
45 | if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) { | ||
46 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) { | ||
47 | *out |= I2S_SF_CLOCK_SOURCE_18MHz; | ||
48 | return 0; | ||
49 | } | ||
50 | } | ||
51 | if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) { | ||
52 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) { | ||
53 | *out |= I2S_SF_CLOCK_SOURCE_45MHz; | ||
54 | return 0; | ||
55 | } | ||
56 | } | ||
57 | if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) { | ||
58 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) { | ||
59 | *out |= I2S_SF_CLOCK_SOURCE_49MHz; | ||
60 | return 0; | ||
61 | } | ||
62 | } | ||
63 | return -1; | ||
64 | } | ||
65 | |||
66 | #define CHECK_RATE(rate) \ | ||
67 | do { if (rates & SNDRV_PCM_RATE_ ##rate) { \ | ||
68 | int dummy; \ | ||
69 | if (clock_and_divisors(sysclock_factor, \ | ||
70 | bus_factor, rate, &dummy)) \ | ||
71 | rates &= ~SNDRV_PCM_RATE_ ##rate; \ | ||
72 | } } while (0) | ||
73 | |||
74 | static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) | ||
75 | { | ||
76 | struct pcm_info *pi, *other; | ||
77 | struct soundbus_dev *sdev; | ||
78 | int masks_inited = 0, err; | ||
79 | struct codec_info_item *cii, *rev; | ||
80 | struct snd_pcm_hardware *hw; | ||
81 | u64 formats = 0; | ||
82 | unsigned int rates = 0; | ||
83 | struct transfer_info v; | ||
84 | int result = 0; | ||
85 | int bus_factor = 0, sysclock_factor = 0; | ||
86 | int found_this; | ||
87 | |||
88 | mutex_lock(&i2sdev->lock); | ||
89 | |||
90 | get_pcm_info(i2sdev, in, &pi, &other); | ||
91 | |||
92 | hw = &pi->substream->runtime->hw; | ||
93 | sdev = &i2sdev->sound; | ||
94 | |||
95 | if (pi->active) { | ||
96 | /* alsa messed up */ | ||
97 | result = -EBUSY; | ||
98 | goto out_unlock; | ||
99 | } | ||
100 | |||
101 | /* we now need to assign the hw */ | ||
102 | list_for_each_entry(cii, &sdev->codec_list, list) { | ||
103 | struct transfer_info *ti = cii->codec->transfers; | ||
104 | bus_factor = cii->codec->bus_factor; | ||
105 | sysclock_factor = cii->codec->sysclock_factor; | ||
106 | while (ti->formats && ti->rates) { | ||
107 | v = *ti; | ||
108 | if (ti->transfer_in == in | ||
109 | && cii->codec->usable(cii, ti, &v)) { | ||
110 | if (masks_inited) { | ||
111 | formats &= v.formats; | ||
112 | rates &= v.rates; | ||
113 | } else { | ||
114 | formats = v.formats; | ||
115 | rates = v.rates; | ||
116 | masks_inited = 1; | ||
117 | } | ||
118 | } | ||
119 | ti++; | ||
120 | } | ||
121 | } | ||
122 | if (!masks_inited || !bus_factor || !sysclock_factor) { | ||
123 | result = -ENODEV; | ||
124 | goto out_unlock; | ||
125 | } | ||
126 | /* bus dependent stuff */ | ||
127 | hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
128 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME; | ||
129 | |||
130 | CHECK_RATE(5512); | ||
131 | CHECK_RATE(8000); | ||
132 | CHECK_RATE(11025); | ||
133 | CHECK_RATE(16000); | ||
134 | CHECK_RATE(22050); | ||
135 | CHECK_RATE(32000); | ||
136 | CHECK_RATE(44100); | ||
137 | CHECK_RATE(48000); | ||
138 | CHECK_RATE(64000); | ||
139 | CHECK_RATE(88200); | ||
140 | CHECK_RATE(96000); | ||
141 | CHECK_RATE(176400); | ||
142 | CHECK_RATE(192000); | ||
143 | hw->rates = rates; | ||
144 | |||
145 | /* well. the codec might want 24 bits only, and we'll | ||
146 | * ever only transfer 24 bits, but they are top-aligned! | ||
147 | * So for alsa, we claim that we're doing full 32 bit | ||
148 | * while in reality we'll ignore the lower 8 bits of | ||
149 | * that when doing playback (they're transferred as 0 | ||
150 | * as far as I know, no codecs we have are 32-bit capable | ||
151 | * so I can't really test) and when doing recording we'll | ||
152 | * always have those lower 8 bits recorded as 0 */ | ||
153 | if (formats & SNDRV_PCM_FMTBIT_S24_BE) | ||
154 | formats |= SNDRV_PCM_FMTBIT_S32_BE; | ||
155 | if (formats & SNDRV_PCM_FMTBIT_U24_BE) | ||
156 | formats |= SNDRV_PCM_FMTBIT_U32_BE; | ||
157 | /* now mask off what we can support. I suppose we could | ||
158 | * also support S24_3LE and some similar formats, but I | ||
159 | * doubt there's a codec that would be able to use that, | ||
160 | * so we don't support it here. */ | ||
161 | hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE | | ||
162 | SNDRV_PCM_FMTBIT_U16_BE | | ||
163 | SNDRV_PCM_FMTBIT_S32_BE | | ||
164 | SNDRV_PCM_FMTBIT_U32_BE); | ||
165 | |||
166 | /* we need to set the highest and lowest rate possible. | ||
167 | * These are the highest and lowest rates alsa can | ||
168 | * support properly in its bitfield. | ||
169 | * Below, we'll use that to restrict to the rate | ||
170 | * currently in use (if any). */ | ||
171 | hw->rate_min = 5512; | ||
172 | hw->rate_max = 192000; | ||
173 | /* if the other stream is active, then we can only | ||
174 | * support what it is currently using. | ||
175 | * FIXME: I lied. This comment is wrong. We can support | ||
176 | * anything that works with the same serial format, ie. | ||
177 | * when recording 24 bit sound we can well play 16 bit | ||
178 | * sound at the same time iff using the same transfer mode. | ||
179 | */ | ||
180 | if (other->active) { | ||
181 | /* FIXME: is this guaranteed by the alsa api? */ | ||
182 | hw->formats &= (1ULL << i2sdev->format); | ||
183 | /* see above, restrict rates to the one we already have */ | ||
184 | hw->rate_min = i2sdev->rate; | ||
185 | hw->rate_max = i2sdev->rate; | ||
186 | } | ||
187 | |||
188 | hw->channels_min = 2; | ||
189 | hw->channels_max = 2; | ||
190 | /* these are somewhat arbitrary */ | ||
191 | hw->buffer_bytes_max = 131072; | ||
192 | hw->period_bytes_min = 256; | ||
193 | hw->period_bytes_max = 16384; | ||
194 | hw->periods_min = 3; | ||
195 | hw->periods_max = MAX_DBDMA_COMMANDS; | ||
196 | list_for_each_entry(cii, &sdev->codec_list, list) { | ||
197 | if (cii->codec->open) { | ||
198 | err = cii->codec->open(cii, pi->substream); | ||
199 | if (err) { | ||
200 | result = err; | ||
201 | /* unwind */ | ||
202 | found_this = 0; | ||
203 | list_for_each_entry_reverse(rev, | ||
204 | &sdev->codec_list, list) { | ||
205 | if (found_this && rev->codec->close) { | ||
206 | rev->codec->close(rev, | ||
207 | pi->substream); | ||
208 | } | ||
209 | if (rev == cii) | ||
210 | found_this = 1; | ||
211 | } | ||
212 | goto out_unlock; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | out_unlock: | ||
218 | mutex_unlock(&i2sdev->lock); | ||
219 | return result; | ||
220 | } | ||
221 | |||
222 | #undef CHECK_RATE | ||
223 | |||
224 | static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) | ||
225 | { | ||
226 | struct codec_info_item *cii; | ||
227 | struct pcm_info *pi; | ||
228 | int err = 0, tmp; | ||
229 | |||
230 | mutex_lock(&i2sdev->lock); | ||
231 | |||
232 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
233 | |||
234 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
235 | if (cii->codec->close) { | ||
236 | tmp = cii->codec->close(cii, pi->substream); | ||
237 | if (tmp) | ||
238 | err = tmp; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | pi->substream = NULL; | ||
243 | pi->active = 0; | ||
244 | mutex_unlock(&i2sdev->lock); | ||
245 | return err; | ||
246 | } | ||
247 | |||
248 | static int i2sbus_hw_params(struct snd_pcm_substream *substream, | ||
249 | struct snd_pcm_hw_params *params) | ||
250 | { | ||
251 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
252 | } | ||
253 | |||
254 | static int i2sbus_hw_free(struct snd_pcm_substream *substream) | ||
255 | { | ||
256 | snd_pcm_lib_free_pages(substream); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | ||
261 | { | ||
262 | /* whee. Hard work now. The user has selected a bitrate | ||
263 | * and bit format, so now we have to program our | ||
264 | * I2S controller appropriately. */ | ||
265 | struct snd_pcm_runtime *runtime; | ||
266 | struct dbdma_cmd *command; | ||
267 | int i, periodsize; | ||
268 | dma_addr_t offset; | ||
269 | struct bus_info bi; | ||
270 | struct codec_info_item *cii; | ||
271 | int sfr = 0; /* serial format register */ | ||
272 | int dws = 0; /* data word sizes reg */ | ||
273 | int input_16bit; | ||
274 | struct pcm_info *pi, *other; | ||
275 | int cnt; | ||
276 | int result = 0; | ||
277 | |||
278 | mutex_lock(&i2sdev->lock); | ||
279 | |||
280 | get_pcm_info(i2sdev, in, &pi, &other); | ||
281 | |||
282 | if (pi->dbdma_ring.running) { | ||
283 | result = -EBUSY; | ||
284 | goto out_unlock; | ||
285 | } | ||
286 | |||
287 | runtime = pi->substream->runtime; | ||
288 | pi->active = 1; | ||
289 | if (other->active && | ||
290 | ((i2sdev->format != runtime->format) | ||
291 | || (i2sdev->rate != runtime->rate))) { | ||
292 | result = -EINVAL; | ||
293 | goto out_unlock; | ||
294 | } | ||
295 | |||
296 | i2sdev->format = runtime->format; | ||
297 | i2sdev->rate = runtime->rate; | ||
298 | |||
299 | periodsize = snd_pcm_lib_period_bytes(pi->substream); | ||
300 | pi->current_period = 0; | ||
301 | |||
302 | /* generate dbdma command ring first */ | ||
303 | command = pi->dbdma_ring.cmds; | ||
304 | offset = runtime->dma_addr; | ||
305 | for (i = 0; i < pi->substream->runtime->periods; | ||
306 | i++, command++, offset += periodsize) { | ||
307 | memset(command, 0, sizeof(struct dbdma_cmd)); | ||
308 | command->command = | ||
309 | cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS); | ||
310 | command->phy_addr = cpu_to_le32(offset); | ||
311 | command->req_count = cpu_to_le16(periodsize); | ||
312 | command->xfer_status = cpu_to_le16(0); | ||
313 | } | ||
314 | /* last one branches back to first */ | ||
315 | command--; | ||
316 | command->command |= cpu_to_le16(BR_ALWAYS); | ||
317 | command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); | ||
318 | |||
319 | /* ok, let's set the serial format and stuff */ | ||
320 | switch (runtime->format) { | ||
321 | /* 16 bit formats */ | ||
322 | case SNDRV_PCM_FORMAT_S16_BE: | ||
323 | case SNDRV_PCM_FORMAT_U16_BE: | ||
324 | /* FIXME: if we add different bus factors we need to | ||
325 | * do more here!! */ | ||
326 | bi.bus_factor = 0; | ||
327 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
328 | bi.bus_factor = cii->codec->bus_factor; | ||
329 | break; | ||
330 | } | ||
331 | if (!bi.bus_factor) { | ||
332 | result = -ENODEV; | ||
333 | goto out_unlock; | ||
334 | } | ||
335 | input_16bit = 1; | ||
336 | break; | ||
337 | case SNDRV_PCM_FORMAT_S32_BE: | ||
338 | case SNDRV_PCM_FORMAT_U32_BE: | ||
339 | /* force 64x bus speed, otherwise the data cannot be | ||
340 | * transferred quickly enough! */ | ||
341 | bi.bus_factor = 64; | ||
342 | input_16bit = 0; | ||
343 | break; | ||
344 | default: | ||
345 | result = -EINVAL; | ||
346 | goto out_unlock; | ||
347 | } | ||
348 | /* we assume all sysclocks are the same! */ | ||
349 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
350 | bi.sysclock_factor = cii->codec->sysclock_factor; | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | if (clock_and_divisors(bi.sysclock_factor, | ||
355 | bi.bus_factor, | ||
356 | runtime->rate, | ||
357 | &sfr) < 0) { | ||
358 | result = -EINVAL; | ||
359 | goto out_unlock; | ||
360 | } | ||
361 | switch (bi.bus_factor) { | ||
362 | case 32: | ||
363 | sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X; | ||
364 | break; | ||
365 | case 64: | ||
366 | sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X; | ||
367 | break; | ||
368 | } | ||
369 | /* FIXME: THIS ASSUMES MASTER ALL THE TIME */ | ||
370 | sfr |= I2S_SF_SCLK_MASTER; | ||
371 | |||
372 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
373 | int err = 0; | ||
374 | if (cii->codec->prepare) | ||
375 | err = cii->codec->prepare(cii, &bi, pi->substream); | ||
376 | if (err) { | ||
377 | result = err; | ||
378 | goto out_unlock; | ||
379 | } | ||
380 | } | ||
381 | /* codecs are fine with it, so set our clocks */ | ||
382 | if (input_16bit) | ||
383 | dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | | ||
384 | (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | | ||
385 | I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT; | ||
386 | else | ||
387 | dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | | ||
388 | (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | | ||
389 | I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT; | ||
390 | |||
391 | /* early exit if already programmed correctly */ | ||
392 | /* not locking these is fine since we touch them only in this function */ | ||
393 | if (in_le32(&i2sdev->intfregs->serial_format) == sfr | ||
394 | && in_le32(&i2sdev->intfregs->data_word_sizes) == dws) | ||
395 | goto out_unlock; | ||
396 | |||
397 | /* let's notify the codecs about clocks going away. | ||
398 | * For now we only do mastering on the i2s cell... */ | ||
399 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
400 | if (cii->codec->switch_clock) | ||
401 | cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE); | ||
402 | |||
403 | i2sbus_control_enable(i2sdev->control, i2sdev); | ||
404 | i2sbus_control_cell(i2sdev->control, i2sdev, 1); | ||
405 | |||
406 | out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); | ||
407 | |||
408 | i2sbus_control_clock(i2sdev->control, i2sdev, 0); | ||
409 | |||
410 | msleep(1); | ||
411 | |||
412 | /* wait for clock stopped. This can apparently take a while... */ | ||
413 | cnt = 100; | ||
414 | while (cnt-- && | ||
415 | !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) { | ||
416 | msleep(5); | ||
417 | } | ||
418 | out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); | ||
419 | |||
420 | /* not locking these is fine since we touch them only in this function */ | ||
421 | out_le32(&i2sdev->intfregs->serial_format, sfr); | ||
422 | out_le32(&i2sdev->intfregs->data_word_sizes, dws); | ||
423 | |||
424 | i2sbus_control_enable(i2sdev->control, i2sdev); | ||
425 | i2sbus_control_cell(i2sdev->control, i2sdev, 1); | ||
426 | i2sbus_control_clock(i2sdev->control, i2sdev, 1); | ||
427 | msleep(1); | ||
428 | |||
429 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
430 | if (cii->codec->switch_clock) | ||
431 | cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE); | ||
432 | |||
433 | out_unlock: | ||
434 | mutex_unlock(&i2sdev->lock); | ||
435 | return result; | ||
436 | } | ||
437 | |||
438 | static struct dbdma_cmd STOP_CMD = { | ||
439 | .command = __constant_cpu_to_le16(DBDMA_STOP), | ||
440 | }; | ||
441 | |||
442 | static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) | ||
443 | { | ||
444 | struct codec_info_item *cii; | ||
445 | struct pcm_info *pi; | ||
446 | int timeout; | ||
447 | struct dbdma_cmd tmp; | ||
448 | int result = 0; | ||
449 | unsigned long flags; | ||
450 | |||
451 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
452 | |||
453 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
454 | |||
455 | switch (cmd) { | ||
456 | case SNDRV_PCM_TRIGGER_START: | ||
457 | case SNDRV_PCM_TRIGGER_RESUME: | ||
458 | if (pi->dbdma_ring.running) { | ||
459 | result = -EALREADY; | ||
460 | goto out_unlock; | ||
461 | } | ||
462 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
463 | if (cii->codec->start) | ||
464 | cii->codec->start(cii, pi->substream); | ||
465 | pi->dbdma_ring.running = 1; | ||
466 | |||
467 | /* reset dma engine */ | ||
468 | out_le32(&pi->dbdma->control, | ||
469 | 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); | ||
470 | timeout = 100; | ||
471 | while (in_le32(&pi->dbdma->status) & RUN && timeout--) | ||
472 | udelay(1); | ||
473 | if (timeout <= 0) { | ||
474 | printk(KERN_ERR | ||
475 | "i2sbus: error waiting for dma reset\n"); | ||
476 | result = -ENXIO; | ||
477 | goto out_unlock; | ||
478 | } | ||
479 | |||
480 | /* write dma command buffer address to the dbdma chip */ | ||
481 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | ||
482 | /* post PCI write */ | ||
483 | mb(); | ||
484 | (void)in_le32(&pi->dbdma->status); | ||
485 | |||
486 | /* change first command to STOP */ | ||
487 | tmp = *pi->dbdma_ring.cmds; | ||
488 | *pi->dbdma_ring.cmds = STOP_CMD; | ||
489 | |||
490 | /* set running state, remember that the first command is STOP */ | ||
491 | out_le32(&pi->dbdma->control, RUN | (RUN << 16)); | ||
492 | timeout = 100; | ||
493 | /* wait for STOP to be executed */ | ||
494 | while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--) | ||
495 | udelay(1); | ||
496 | if (timeout <= 0) { | ||
497 | printk(KERN_ERR "i2sbus: error waiting for dma stop\n"); | ||
498 | result = -ENXIO; | ||
499 | goto out_unlock; | ||
500 | } | ||
501 | /* again, write dma command buffer address to the dbdma chip, | ||
502 | * this time of the first real command */ | ||
503 | *pi->dbdma_ring.cmds = tmp; | ||
504 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | ||
505 | /* post write */ | ||
506 | mb(); | ||
507 | (void)in_le32(&pi->dbdma->status); | ||
508 | |||
509 | /* reset dma engine again */ | ||
510 | out_le32(&pi->dbdma->control, | ||
511 | 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); | ||
512 | timeout = 100; | ||
513 | while (in_le32(&pi->dbdma->status) & RUN && timeout--) | ||
514 | udelay(1); | ||
515 | if (timeout <= 0) { | ||
516 | printk(KERN_ERR | ||
517 | "i2sbus: error waiting for dma reset\n"); | ||
518 | result = -ENXIO; | ||
519 | goto out_unlock; | ||
520 | } | ||
521 | |||
522 | /* wake up the chip with the next descriptor */ | ||
523 | out_le32(&pi->dbdma->control, | ||
524 | (RUN | WAKE) | ((RUN | WAKE) << 16)); | ||
525 | /* get the frame count */ | ||
526 | pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); | ||
527 | |||
528 | /* off you go! */ | ||
529 | break; | ||
530 | case SNDRV_PCM_TRIGGER_STOP: | ||
531 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
532 | if (!pi->dbdma_ring.running) { | ||
533 | result = -EALREADY; | ||
534 | goto out_unlock; | ||
535 | } | ||
536 | |||
537 | /* turn off all relevant bits */ | ||
538 | out_le32(&pi->dbdma->control, | ||
539 | (RUN | WAKE | FLUSH | PAUSE) << 16); | ||
540 | { | ||
541 | /* FIXME: move to own function */ | ||
542 | int timeout = 5000; | ||
543 | while ((in_le32(&pi->dbdma->status) & RUN) | ||
544 | && --timeout > 0) | ||
545 | udelay(1); | ||
546 | if (!timeout) | ||
547 | printk(KERN_ERR | ||
548 | "i2sbus: timed out turning " | ||
549 | "off dbdma engine!\n"); | ||
550 | } | ||
551 | |||
552 | pi->dbdma_ring.running = 0; | ||
553 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
554 | if (cii->codec->stop) | ||
555 | cii->codec->stop(cii, pi->substream); | ||
556 | break; | ||
557 | default: | ||
558 | result = -EINVAL; | ||
559 | goto out_unlock; | ||
560 | } | ||
561 | |||
562 | out_unlock: | ||
563 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
564 | return result; | ||
565 | } | ||
566 | |||
567 | static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) | ||
568 | { | ||
569 | struct pcm_info *pi; | ||
570 | u32 fc; | ||
571 | |||
572 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
573 | |||
574 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
575 | fc = fc - pi->frame_count; | ||
576 | |||
577 | return (bytes_to_frames(pi->substream->runtime, | ||
578 | pi->current_period * | ||
579 | snd_pcm_lib_period_bytes(pi->substream)) | ||
580 | + fc) % pi->substream->runtime->buffer_size; | ||
581 | } | ||
582 | |||
583 | static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) | ||
584 | { | ||
585 | struct pcm_info *pi; | ||
586 | u32 fc; | ||
587 | u32 delta; | ||
588 | |||
589 | spin_lock(&i2sdev->low_lock); | ||
590 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
591 | |||
592 | if (!pi->dbdma_ring.running) { | ||
593 | /* there was still an interrupt pending | ||
594 | * while we stopped. or maybe another | ||
595 | * processor (not the one that was stopping | ||
596 | * the DMA engine) was spinning above | ||
597 | * waiting for the lock. */ | ||
598 | goto out_unlock; | ||
599 | } | ||
600 | |||
601 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
602 | /* a counter overflow does not change the calculation. */ | ||
603 | delta = fc - pi->frame_count; | ||
604 | |||
605 | /* update current_period */ | ||
606 | while (delta >= pi->substream->runtime->period_size) { | ||
607 | pi->current_period++; | ||
608 | delta = delta - pi->substream->runtime->period_size; | ||
609 | } | ||
610 | |||
611 | if (unlikely(delta)) { | ||
612 | /* Some interrupt came late, so check the dbdma. | ||
613 | * This special case exists to syncronize the frame_count with | ||
614 | * the dbdma transfer, but is hit every once in a while. */ | ||
615 | int period; | ||
616 | |||
617 | period = (in_le32(&pi->dbdma->cmdptr) | ||
618 | - pi->dbdma_ring.bus_cmd_start) | ||
619 | / sizeof(struct dbdma_cmd); | ||
620 | pi->current_period = pi->current_period | ||
621 | % pi->substream->runtime->periods; | ||
622 | |||
623 | while (pi->current_period != period) { | ||
624 | pi->current_period++; | ||
625 | pi->current_period %= pi->substream->runtime->periods; | ||
626 | /* Set delta to zero, as the frame_count value is too | ||
627 | * high (otherwise the code path will not be executed). | ||
628 | * This corrects the fact that the frame_count is too | ||
629 | * low at the beginning due to buffering. */ | ||
630 | delta = 0; | ||
631 | } | ||
632 | } | ||
633 | |||
634 | pi->frame_count = fc - delta; | ||
635 | pi->current_period %= pi->substream->runtime->periods; | ||
636 | |||
637 | spin_unlock(&i2sdev->low_lock); | ||
638 | /* may call _trigger again, hence needs to be unlocked */ | ||
639 | snd_pcm_period_elapsed(pi->substream); | ||
640 | return; | ||
641 | out_unlock: | ||
642 | spin_unlock(&i2sdev->low_lock); | ||
643 | } | ||
644 | |||
645 | irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs) | ||
646 | { | ||
647 | handle_interrupt((struct i2sbus_dev *)devid, 0); | ||
648 | return IRQ_HANDLED; | ||
649 | } | ||
650 | |||
651 | irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs) | ||
652 | { | ||
653 | handle_interrupt((struct i2sbus_dev *)devid, 1); | ||
654 | return IRQ_HANDLED; | ||
655 | } | ||
656 | |||
657 | static int i2sbus_playback_open(struct snd_pcm_substream *substream) | ||
658 | { | ||
659 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
660 | |||
661 | if (!i2sdev) | ||
662 | return -EINVAL; | ||
663 | i2sdev->out.substream = substream; | ||
664 | return i2sbus_pcm_open(i2sdev, 0); | ||
665 | } | ||
666 | |||
667 | static int i2sbus_playback_close(struct snd_pcm_substream *substream) | ||
668 | { | ||
669 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
670 | int err; | ||
671 | |||
672 | if (!i2sdev) | ||
673 | return -EINVAL; | ||
674 | if (i2sdev->out.substream != substream) | ||
675 | return -EINVAL; | ||
676 | err = i2sbus_pcm_close(i2sdev, 0); | ||
677 | if (!err) | ||
678 | i2sdev->out.substream = NULL; | ||
679 | return err; | ||
680 | } | ||
681 | |||
682 | static int i2sbus_playback_prepare(struct snd_pcm_substream *substream) | ||
683 | { | ||
684 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
685 | |||
686 | if (!i2sdev) | ||
687 | return -EINVAL; | ||
688 | if (i2sdev->out.substream != substream) | ||
689 | return -EINVAL; | ||
690 | return i2sbus_pcm_prepare(i2sdev, 0); | ||
691 | } | ||
692 | |||
693 | static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
694 | { | ||
695 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
696 | |||
697 | if (!i2sdev) | ||
698 | return -EINVAL; | ||
699 | if (i2sdev->out.substream != substream) | ||
700 | return -EINVAL; | ||
701 | return i2sbus_pcm_trigger(i2sdev, 0, cmd); | ||
702 | } | ||
703 | |||
704 | static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream | ||
705 | *substream) | ||
706 | { | ||
707 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
708 | |||
709 | if (!i2sdev) | ||
710 | return -EINVAL; | ||
711 | if (i2sdev->out.substream != substream) | ||
712 | return 0; | ||
713 | return i2sbus_pcm_pointer(i2sdev, 0); | ||
714 | } | ||
715 | |||
716 | static struct snd_pcm_ops i2sbus_playback_ops = { | ||
717 | .open = i2sbus_playback_open, | ||
718 | .close = i2sbus_playback_close, | ||
719 | .ioctl = snd_pcm_lib_ioctl, | ||
720 | .hw_params = i2sbus_hw_params, | ||
721 | .hw_free = i2sbus_hw_free, | ||
722 | .prepare = i2sbus_playback_prepare, | ||
723 | .trigger = i2sbus_playback_trigger, | ||
724 | .pointer = i2sbus_playback_pointer, | ||
725 | }; | ||
726 | |||
727 | static int i2sbus_record_open(struct snd_pcm_substream *substream) | ||
728 | { | ||
729 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
730 | |||
731 | if (!i2sdev) | ||
732 | return -EINVAL; | ||
733 | i2sdev->in.substream = substream; | ||
734 | return i2sbus_pcm_open(i2sdev, 1); | ||
735 | } | ||
736 | |||
737 | static int i2sbus_record_close(struct snd_pcm_substream *substream) | ||
738 | { | ||
739 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
740 | int err; | ||
741 | |||
742 | if (!i2sdev) | ||
743 | return -EINVAL; | ||
744 | if (i2sdev->in.substream != substream) | ||
745 | return -EINVAL; | ||
746 | err = i2sbus_pcm_close(i2sdev, 1); | ||
747 | if (!err) | ||
748 | i2sdev->in.substream = NULL; | ||
749 | return err; | ||
750 | } | ||
751 | |||
752 | static int i2sbus_record_prepare(struct snd_pcm_substream *substream) | ||
753 | { | ||
754 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
755 | |||
756 | if (!i2sdev) | ||
757 | return -EINVAL; | ||
758 | if (i2sdev->in.substream != substream) | ||
759 | return -EINVAL; | ||
760 | return i2sbus_pcm_prepare(i2sdev, 1); | ||
761 | } | ||
762 | |||
763 | static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd) | ||
764 | { | ||
765 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
766 | |||
767 | if (!i2sdev) | ||
768 | return -EINVAL; | ||
769 | if (i2sdev->in.substream != substream) | ||
770 | return -EINVAL; | ||
771 | return i2sbus_pcm_trigger(i2sdev, 1, cmd); | ||
772 | } | ||
773 | |||
774 | static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream | ||
775 | *substream) | ||
776 | { | ||
777 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
778 | |||
779 | if (!i2sdev) | ||
780 | return -EINVAL; | ||
781 | if (i2sdev->in.substream != substream) | ||
782 | return 0; | ||
783 | return i2sbus_pcm_pointer(i2sdev, 1); | ||
784 | } | ||
785 | |||
786 | static struct snd_pcm_ops i2sbus_record_ops = { | ||
787 | .open = i2sbus_record_open, | ||
788 | .close = i2sbus_record_close, | ||
789 | .ioctl = snd_pcm_lib_ioctl, | ||
790 | .hw_params = i2sbus_hw_params, | ||
791 | .hw_free = i2sbus_hw_free, | ||
792 | .prepare = i2sbus_record_prepare, | ||
793 | .trigger = i2sbus_record_trigger, | ||
794 | .pointer = i2sbus_record_pointer, | ||
795 | }; | ||
796 | |||
797 | static void i2sbus_private_free(struct snd_pcm *pcm) | ||
798 | { | ||
799 | struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm); | ||
800 | struct codec_info_item *p, *tmp; | ||
801 | |||
802 | i2sdev->sound.pcm = NULL; | ||
803 | i2sdev->out.created = 0; | ||
804 | i2sdev->in.created = 0; | ||
805 | list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) { | ||
806 | printk(KERN_ERR "i2sbus: a codec didn't unregister!\n"); | ||
807 | list_del(&p->list); | ||
808 | module_put(p->codec->owner); | ||
809 | kfree(p); | ||
810 | } | ||
811 | soundbus_dev_put(&i2sdev->sound); | ||
812 | module_put(THIS_MODULE); | ||
813 | } | ||
814 | |||
815 | /* FIXME: this function needs an error handling strategy with labels */ | ||
816 | int | ||
817 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | ||
818 | struct codec_info *ci, void *data) | ||
819 | { | ||
820 | int err, in = 0, out = 0; | ||
821 | struct transfer_info *tmp; | ||
822 | struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev); | ||
823 | struct codec_info_item *cii; | ||
824 | |||
825 | if (!dev->pcmname || dev->pcmid == -1) { | ||
826 | printk(KERN_ERR "i2sbus: pcm name and id must be set!\n"); | ||
827 | return -EINVAL; | ||
828 | } | ||
829 | |||
830 | list_for_each_entry(cii, &dev->codec_list, list) { | ||
831 | if (cii->codec_data == data) | ||
832 | return -EALREADY; | ||
833 | } | ||
834 | |||
835 | if (!ci->transfers || !ci->transfers->formats | ||
836 | || !ci->transfers->rates || !ci->usable) | ||
837 | return -EINVAL; | ||
838 | |||
839 | /* we currently code the i2s transfer on the clock, and support only | ||
840 | * 32 and 64 */ | ||
841 | if (ci->bus_factor != 32 && ci->bus_factor != 64) | ||
842 | return -EINVAL; | ||
843 | |||
844 | /* If you want to fix this, you need to keep track of what transport infos | ||
845 | * are to be used, which codecs they belong to, and then fix all the | ||
846 | * sysclock/busclock stuff above to depend on which is usable */ | ||
847 | list_for_each_entry(cii, &dev->codec_list, list) { | ||
848 | if (cii->codec->sysclock_factor != ci->sysclock_factor) { | ||
849 | printk(KERN_DEBUG | ||
850 | "cannot yet handle multiple different sysclocks!\n"); | ||
851 | return -EINVAL; | ||
852 | } | ||
853 | if (cii->codec->bus_factor != ci->bus_factor) { | ||
854 | printk(KERN_DEBUG | ||
855 | "cannot yet handle multiple different bus clocks!\n"); | ||
856 | return -EINVAL; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | tmp = ci->transfers; | ||
861 | while (tmp->formats && tmp->rates) { | ||
862 | if (tmp->transfer_in) | ||
863 | in = 1; | ||
864 | else | ||
865 | out = 1; | ||
866 | tmp++; | ||
867 | } | ||
868 | |||
869 | cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL); | ||
870 | if (!cii) { | ||
871 | printk(KERN_DEBUG "i2sbus: failed to allocate cii\n"); | ||
872 | return -ENOMEM; | ||
873 | } | ||
874 | |||
875 | /* use the private data to point to the codec info */ | ||
876 | cii->sdev = soundbus_dev_get(dev); | ||
877 | cii->codec = ci; | ||
878 | cii->codec_data = data; | ||
879 | |||
880 | if (!cii->sdev) { | ||
881 | printk(KERN_DEBUG | ||
882 | "i2sbus: failed to get soundbus dev reference\n"); | ||
883 | kfree(cii); | ||
884 | return -ENODEV; | ||
885 | } | ||
886 | |||
887 | if (!try_module_get(THIS_MODULE)) { | ||
888 | printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); | ||
889 | soundbus_dev_put(dev); | ||
890 | kfree(cii); | ||
891 | return -EBUSY; | ||
892 | } | ||
893 | |||
894 | if (!try_module_get(ci->owner)) { | ||
895 | printk(KERN_DEBUG | ||
896 | "i2sbus: failed to get module reference to codec owner!\n"); | ||
897 | module_put(THIS_MODULE); | ||
898 | soundbus_dev_put(dev); | ||
899 | kfree(cii); | ||
900 | return -EBUSY; | ||
901 | } | ||
902 | |||
903 | if (!dev->pcm) { | ||
904 | err = snd_pcm_new(card, | ||
905 | dev->pcmname, | ||
906 | dev->pcmid, | ||
907 | 0, | ||
908 | 0, | ||
909 | &dev->pcm); | ||
910 | if (err) { | ||
911 | printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); | ||
912 | kfree(cii); | ||
913 | module_put(ci->owner); | ||
914 | soundbus_dev_put(dev); | ||
915 | module_put(THIS_MODULE); | ||
916 | return err; | ||
917 | } | ||
918 | } | ||
919 | |||
920 | /* ALSA yet again sucks. | ||
921 | * If it is ever fixed, remove this line. See below. */ | ||
922 | out = in = 1; | ||
923 | |||
924 | if (!i2sdev->out.created && out) { | ||
925 | if (dev->pcm->card != card) { | ||
926 | /* eh? */ | ||
927 | printk(KERN_ERR | ||
928 | "Can't attach same bus to different cards!\n"); | ||
929 | module_put(ci->owner); | ||
930 | kfree(cii); | ||
931 | soundbus_dev_put(dev); | ||
932 | module_put(THIS_MODULE); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | if ((err = | ||
936 | snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) { | ||
937 | module_put(ci->owner); | ||
938 | kfree(cii); | ||
939 | soundbus_dev_put(dev); | ||
940 | module_put(THIS_MODULE); | ||
941 | return err; | ||
942 | } | ||
943 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
944 | &i2sbus_playback_ops); | ||
945 | i2sdev->out.created = 1; | ||
946 | } | ||
947 | |||
948 | if (!i2sdev->in.created && in) { | ||
949 | if (dev->pcm->card != card) { | ||
950 | printk(KERN_ERR | ||
951 | "Can't attach same bus to different cards!\n"); | ||
952 | module_put(ci->owner); | ||
953 | kfree(cii); | ||
954 | soundbus_dev_put(dev); | ||
955 | module_put(THIS_MODULE); | ||
956 | return -EINVAL; | ||
957 | } | ||
958 | if ((err = | ||
959 | snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) { | ||
960 | module_put(ci->owner); | ||
961 | kfree(cii); | ||
962 | soundbus_dev_put(dev); | ||
963 | module_put(THIS_MODULE); | ||
964 | return err; | ||
965 | } | ||
966 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
967 | &i2sbus_record_ops); | ||
968 | i2sdev->in.created = 1; | ||
969 | } | ||
970 | |||
971 | /* so we have to register the pcm after adding any substream | ||
972 | * to it because alsa doesn't create the devices for the | ||
973 | * substreams when we add them later. | ||
974 | * Therefore, force in and out on both busses (above) and | ||
975 | * register the pcm now instead of just after creating it. | ||
976 | */ | ||
977 | err = snd_device_register(card, dev->pcm); | ||
978 | if (err) { | ||
979 | printk(KERN_ERR "i2sbus: error registering new pcm\n"); | ||
980 | module_put(ci->owner); | ||
981 | kfree(cii); | ||
982 | soundbus_dev_put(dev); | ||
983 | module_put(THIS_MODULE); | ||
984 | return err; | ||
985 | } | ||
986 | /* no errors any more, so let's add this to our list */ | ||
987 | list_add(&cii->list, &dev->codec_list); | ||
988 | |||
989 | dev->pcm->private_data = i2sdev; | ||
990 | dev->pcm->private_free = i2sbus_private_free; | ||
991 | |||
992 | /* well, we really should support scatter/gather DMA */ | ||
993 | snd_pcm_lib_preallocate_pages_for_all( | ||
994 | dev->pcm, SNDRV_DMA_TYPE_DEV, | ||
995 | snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)), | ||
996 | 64 * 1024, 64 * 1024); | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) | ||
1002 | { | ||
1003 | struct codec_info_item *cii = NULL, *i; | ||
1004 | |||
1005 | list_for_each_entry(i, &dev->codec_list, list) { | ||
1006 | if (i->codec_data == data) { | ||
1007 | cii = i; | ||
1008 | break; | ||
1009 | } | ||
1010 | } | ||
1011 | if (cii) { | ||
1012 | list_del(&cii->list); | ||
1013 | module_put(cii->codec->owner); | ||
1014 | kfree(cii); | ||
1015 | } | ||
1016 | /* no more codecs, but still a pcm? */ | ||
1017 | if (list_empty(&dev->codec_list) && dev->pcm) { | ||
1018 | /* the actual cleanup is done by the callback above! */ | ||
1019 | snd_device_free(dev->pcm->card, dev->pcm); | ||
1020 | } | ||
1021 | } | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h new file mode 100644 index 000000000000..cfa5162e3b0f --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * i2sbus driver -- private definitions | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | #ifndef __I2SBUS_H | ||
9 | #define __I2SBUS_H | ||
10 | #include <asm/dbdma.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <sound/pcm.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/mutex.h> | ||
15 | #include <asm/prom.h> | ||
16 | #include "i2sbus-interface.h" | ||
17 | #include "i2sbus-control.h" | ||
18 | #include "../soundbus.h" | ||
19 | |||
20 | struct i2sbus_control { | ||
21 | volatile struct i2s_control_regs __iomem *controlregs; | ||
22 | struct resource rsrc; | ||
23 | struct list_head list; | ||
24 | }; | ||
25 | |||
26 | #define MAX_DBDMA_COMMANDS 32 | ||
27 | |||
28 | struct dbdma_command_mem { | ||
29 | dma_addr_t bus_addr; | ||
30 | dma_addr_t bus_cmd_start; | ||
31 | struct dbdma_cmd *cmds; | ||
32 | void *space; | ||
33 | int size; | ||
34 | u32 running:1; | ||
35 | }; | ||
36 | |||
37 | struct pcm_info { | ||
38 | u32 created:1, /* has this direction been created with alsa? */ | ||
39 | active:1; /* is this stream active? */ | ||
40 | /* runtime information */ | ||
41 | struct snd_pcm_substream *substream; | ||
42 | int current_period; | ||
43 | u32 frame_count; | ||
44 | struct dbdma_command_mem dbdma_ring; | ||
45 | volatile struct dbdma_regs __iomem *dbdma; | ||
46 | }; | ||
47 | |||
48 | struct i2sbus_dev { | ||
49 | struct soundbus_dev sound; | ||
50 | struct macio_dev *macio; | ||
51 | struct i2sbus_control *control; | ||
52 | volatile struct i2s_interface_regs __iomem *intfregs; | ||
53 | |||
54 | struct resource resources[3]; | ||
55 | struct resource *allocated_resource[3]; | ||
56 | int interrupts[3]; | ||
57 | char rnames[3][32]; | ||
58 | |||
59 | /* info about currently active substreams */ | ||
60 | struct pcm_info out, in; | ||
61 | snd_pcm_format_t format; | ||
62 | unsigned int rate; | ||
63 | |||
64 | /* list for a single controller */ | ||
65 | struct list_head item; | ||
66 | /* number of bus on controller */ | ||
67 | int bus_number; | ||
68 | /* for use by control layer */ | ||
69 | struct pmf_function *enable, | ||
70 | *cell_enable, | ||
71 | *cell_disable, | ||
72 | *clock_enable, | ||
73 | *clock_disable; | ||
74 | |||
75 | /* locks */ | ||
76 | /* spinlock for low-level interrupt locking */ | ||
77 | spinlock_t low_lock; | ||
78 | /* mutex for high-level consistency */ | ||
79 | struct mutex lock; | ||
80 | }; | ||
81 | |||
82 | #define soundbus_dev_to_i2sbus_dev(sdev) \ | ||
83 | container_of(sdev, struct i2sbus_dev, sound) | ||
84 | |||
85 | /* pcm specific functions */ | ||
86 | extern int | ||
87 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | ||
88 | struct codec_info *ci, void *data); | ||
89 | extern void | ||
90 | i2sbus_detach_codec(struct soundbus_dev *dev, void *data); | ||
91 | extern irqreturn_t | ||
92 | i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs); | ||
93 | extern irqreturn_t | ||
94 | i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs); | ||
95 | |||
96 | /* control specific functions */ | ||
97 | extern int i2sbus_control_init(struct macio_dev* dev, | ||
98 | struct i2sbus_control **c); | ||
99 | extern void i2sbus_control_destroy(struct i2sbus_control *c); | ||
100 | extern int i2sbus_control_add_dev(struct i2sbus_control *c, | ||
101 | struct i2sbus_dev *i2sdev); | ||
102 | extern void i2sbus_control_remove_dev(struct i2sbus_control *c, | ||
103 | struct i2sbus_dev *i2sdev); | ||
104 | extern int i2sbus_control_enable(struct i2sbus_control *c, | ||
105 | struct i2sbus_dev *i2sdev); | ||
106 | extern int i2sbus_control_cell(struct i2sbus_control *c, | ||
107 | struct i2sbus_dev *i2sdev, | ||
108 | int enable); | ||
109 | extern int i2sbus_control_clock(struct i2sbus_control *c, | ||
110 | struct i2sbus_dev *i2sdev, | ||
111 | int enable); | ||
112 | #endif /* __I2SBUS_H */ | ||
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h new file mode 100644 index 000000000000..5c27297835d7 --- /dev/null +++ b/sound/aoa/soundbus/soundbus.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * soundbus generic definitions | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | #ifndef __SOUNDBUS_H | ||
9 | #define __SOUNDBUS_H | ||
10 | |||
11 | #include <asm/of_device.h> | ||
12 | #include <sound/pcm.h> | ||
13 | #include <linux/list.h> | ||
14 | |||
15 | |||
16 | /* When switching from master to slave or the other way around, | ||
17 | * you don't want to have the codec chip acting as clock source | ||
18 | * while the bus still is. | ||
19 | * More importantly, while switch from slave to master, you need | ||
20 | * to turn off the chip's master function first, but then there's | ||
21 | * no clock for a while and other chips might reset, so we notify | ||
22 | * their drivers after having switched. | ||
23 | * The constants here are codec-point of view, so when we switch | ||
24 | * the soundbus to master we tell the codec we're going to switch | ||
25 | * and give it CLOCK_SWITCH_PREPARE_SLAVE! | ||
26 | */ | ||
27 | enum clock_switch { | ||
28 | CLOCK_SWITCH_PREPARE_SLAVE, | ||
29 | CLOCK_SWITCH_PREPARE_MASTER, | ||
30 | CLOCK_SWITCH_SLAVE, | ||
31 | CLOCK_SWITCH_MASTER, | ||
32 | CLOCK_SWITCH_NOTIFY, | ||
33 | }; | ||
34 | |||
35 | /* information on a transfer the codec can take */ | ||
36 | struct transfer_info { | ||
37 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ | ||
38 | unsigned int rates; /* SNDRV_PCM_RATE_* */ | ||
39 | /* flags */ | ||
40 | u32 transfer_in:1, /* input = 1, output = 0 */ | ||
41 | must_be_clock_source:1; | ||
42 | /* for codecs to distinguish among their TIs */ | ||
43 | int tag; | ||
44 | }; | ||
45 | |||
46 | struct codec_info_item { | ||
47 | struct codec_info *codec; | ||
48 | void *codec_data; | ||
49 | struct soundbus_dev *sdev; | ||
50 | /* internal, to be used by the soundbus provider */ | ||
51 | struct list_head list; | ||
52 | }; | ||
53 | |||
54 | /* for prepare, where the codecs need to know | ||
55 | * what we're going to drive the bus with */ | ||
56 | struct bus_info { | ||
57 | /* see below */ | ||
58 | int sysclock_factor; | ||
59 | int bus_factor; | ||
60 | }; | ||
61 | |||
62 | /* information on the codec itself, plus function pointers */ | ||
63 | struct codec_info { | ||
64 | /* the module this lives in */ | ||
65 | struct module *owner; | ||
66 | |||
67 | /* supported transfer possibilities, array terminated by | ||
68 | * formats or rates being 0. */ | ||
69 | struct transfer_info *transfers; | ||
70 | |||
71 | /* Master clock speed factor | ||
72 | * to be used (master clock speed = sysclock_factor * sampling freq) | ||
73 | * Unused if the soundbus provider has no such notion. | ||
74 | */ | ||
75 | int sysclock_factor; | ||
76 | |||
77 | /* Bus factor, bus clock speed = bus_factor * sampling freq) | ||
78 | * Unused if the soundbus provider has no such notion. | ||
79 | */ | ||
80 | int bus_factor; | ||
81 | |||
82 | /* operations */ | ||
83 | /* clock switching, see above */ | ||
84 | int (*switch_clock)(struct codec_info_item *cii, | ||
85 | enum clock_switch clock); | ||
86 | |||
87 | /* called for each transfer_info when the user | ||
88 | * opens the pcm device to determine what the | ||
89 | * hardware can support at this point in time. | ||
90 | * That can depend on other user-switchable controls. | ||
91 | * Return 1 if usable, 0 if not. | ||
92 | * out points to another instance of a transfer_info | ||
93 | * which is initialised to the values in *ti, and | ||
94 | * it's format and rate values can be modified by | ||
95 | * the callback if it is necessary to further restrict | ||
96 | * the formats that can be used at the moment, for | ||
97 | * example when one codec has multiple logical codec | ||
98 | * info structs for multiple inputs. | ||
99 | */ | ||
100 | int (*usable)(struct codec_info_item *cii, | ||
101 | struct transfer_info *ti, | ||
102 | struct transfer_info *out); | ||
103 | |||
104 | /* called when pcm stream is opened, probably not implemented | ||
105 | * most of the time since it isn't too useful */ | ||
106 | int (*open)(struct codec_info_item *cii, | ||
107 | struct snd_pcm_substream *substream); | ||
108 | |||
109 | /* called when the pcm stream is closed, at this point | ||
110 | * the user choices can all be unlocked (see below) */ | ||
111 | int (*close)(struct codec_info_item *cii, | ||
112 | struct snd_pcm_substream *substream); | ||
113 | |||
114 | /* if the codec must forbid some user choices because | ||
115 | * they are not valid with the substream/transfer info, | ||
116 | * it must do so here. Example: no digital output for | ||
117 | * incompatible framerate, say 8KHz, on Onyx. | ||
118 | * If the selected stuff in the substream is NOT | ||
119 | * compatible, you have to reject this call! */ | ||
120 | int (*prepare)(struct codec_info_item *cii, | ||
121 | struct bus_info *bi, | ||
122 | struct snd_pcm_substream *substream); | ||
123 | |||
124 | /* start() is called before data is pushed to the codec. | ||
125 | * Note that start() must be atomic! */ | ||
126 | int (*start)(struct codec_info_item *cii, | ||
127 | struct snd_pcm_substream *substream); | ||
128 | |||
129 | /* stop() is called after data is no longer pushed to the codec. | ||
130 | * Note that stop() must be atomic! */ | ||
131 | int (*stop)(struct codec_info_item *cii, | ||
132 | struct snd_pcm_substream *substream); | ||
133 | |||
134 | int (*suspend)(struct codec_info_item *cii, pm_message_t state); | ||
135 | int (*resume)(struct codec_info_item *cii); | ||
136 | }; | ||
137 | |||
138 | /* information on a soundbus device */ | ||
139 | struct soundbus_dev { | ||
140 | /* the bus it belongs to */ | ||
141 | struct list_head onbuslist; | ||
142 | |||
143 | /* the of device it represents */ | ||
144 | struct of_device ofdev; | ||
145 | |||
146 | /* what modules go by */ | ||
147 | char modalias[32]; | ||
148 | |||
149 | /* These fields must be before attach_codec can be called. | ||
150 | * They should be set by the owner of the alsa card object | ||
151 | * that is needed, and whoever sets them must make sure | ||
152 | * that they are unique within that alsa card object. */ | ||
153 | char *pcmname; | ||
154 | int pcmid; | ||
155 | |||
156 | /* this is assigned by the soundbus provider in attach_codec */ | ||
157 | struct snd_pcm *pcm; | ||
158 | |||
159 | /* operations */ | ||
160 | /* attach a codec to this soundbus, give the alsa | ||
161 | * card object the PCMs for this soundbus should be in. | ||
162 | * The 'data' pointer must be unique, it is used as the | ||
163 | * key for detach_codec(). */ | ||
164 | int (*attach_codec)(struct soundbus_dev *dev, struct snd_card *card, | ||
165 | struct codec_info *ci, void *data); | ||
166 | void (*detach_codec)(struct soundbus_dev *dev, void *data); | ||
167 | /* TODO: suspend/resume */ | ||
168 | |||
169 | /* private for the soundbus provider */ | ||
170 | struct list_head codec_list; | ||
171 | u32 have_out:1, have_in:1; | ||
172 | }; | ||
173 | #define to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev.dev) | ||
174 | #define of_to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev) | ||
175 | |||
176 | extern int soundbus_add_one(struct soundbus_dev *dev); | ||
177 | extern void soundbus_remove_one(struct soundbus_dev *dev); | ||
178 | |||
179 | extern struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev); | ||
180 | extern void soundbus_dev_put(struct soundbus_dev *dev); | ||
181 | |||
182 | struct soundbus_driver { | ||
183 | char *name; | ||
184 | struct module *owner; | ||
185 | |||
186 | /* we don't implement any matching at all */ | ||
187 | |||
188 | int (*probe)(struct soundbus_dev* dev); | ||
189 | int (*remove)(struct soundbus_dev* dev); | ||
190 | |||
191 | int (*suspend)(struct soundbus_dev* dev, pm_message_t state); | ||
192 | int (*resume)(struct soundbus_dev* dev); | ||
193 | int (*shutdown)(struct soundbus_dev* dev); | ||
194 | |||
195 | struct device_driver driver; | ||
196 | }; | ||
197 | #define to_soundbus_driver(drv) container_of(drv,struct soundbus_driver, driver) | ||
198 | |||
199 | extern int soundbus_register_driver(struct soundbus_driver *drv); | ||
200 | extern void soundbus_unregister_driver(struct soundbus_driver *drv); | ||
201 | |||
202 | #endif /* __SOUNDBUS_H */ | ||
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c new file mode 100644 index 000000000000..d31f8146952a --- /dev/null +++ b/sound/aoa/soundbus/sysfs.c | |||
@@ -0,0 +1,43 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/stat.h> | ||
4 | /* FIX UP */ | ||
5 | #include "soundbus.h" | ||
6 | |||
7 | #define soundbus_config_of_attr(field, format_string) \ | ||
8 | static ssize_t \ | ||
9 | field##_show (struct device *dev, struct device_attribute *attr, \ | ||
10 | char *buf) \ | ||
11 | { \ | ||
12 | struct soundbus_dev *mdev = to_soundbus_device (dev); \ | ||
13 | return sprintf (buf, format_string, mdev->ofdev.node->field); \ | ||
14 | } | ||
15 | |||
16 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | ||
17 | char *buf) | ||
18 | { | ||
19 | struct soundbus_dev *sdev = to_soundbus_device(dev); | ||
20 | struct of_device *of = &sdev->ofdev; | ||
21 | int length; | ||
22 | |||
23 | if (*sdev->modalias) { | ||
24 | strlcpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1); | ||
25 | strcat(buf, "\n"); | ||
26 | length = strlen(buf); | ||
27 | } else { | ||
28 | length = sprintf(buf, "of:N%sT%s\n", | ||
29 | of->node->name, of->node->type); | ||
30 | } | ||
31 | |||
32 | return length; | ||
33 | } | ||
34 | |||
35 | soundbus_config_of_attr (name, "%s\n"); | ||
36 | soundbus_config_of_attr (type, "%s\n"); | ||
37 | |||
38 | struct device_attribute soundbus_dev_attrs[] = { | ||
39 | __ATTR_RO(name), | ||
40 | __ATTR_RO(type), | ||
41 | __ATTR_RO(modalias), | ||
42 | __ATTR_NULL | ||
43 | }; | ||