summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/sound/aoa/soundbus/i2sbus')
-rw-r--r--ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile2
-rw-r--r--ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c194
-rw-r--r--ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c464
-rw-r--r--ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h126
-rw-r--r--ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h187
-rw-r--r--ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c1064
6 files changed, 0 insertions, 2037 deletions
diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile
deleted file mode 100644
index 1b949b2a..00000000
--- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o
-snd-aoa-i2sbus-objs := core.o pcm.o control.o
diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c
deleted file mode 100644
index 4dc9b49c..00000000
--- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/control.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * i2sbus driver -- bus control routines
- *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- *
- * GPL v2, can be found in COPYING.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/macio.h>
-#include <asm/pmac_feature.h>
-#include <asm/pmac_pfunc.h>
-#include <asm/keylargo.h>
-
-#include "i2sbus.h"
-
-int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c)
-{
- *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL);
- if (!*c)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&(*c)->list);
-
- (*c)->macio = dev->bus->chip;
- return 0;
-}
-
-void i2sbus_control_destroy(struct i2sbus_control *c)
-{
- kfree(c);
-}
-
-/* this is serialised externally */
-int i2sbus_control_add_dev(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev)
-{
- struct device_node *np;
-
- np = i2sdev->sound.ofdev.dev.of_node;
- i2sdev->enable = pmf_find_function(np, "enable");
- i2sdev->cell_enable = pmf_find_function(np, "cell-enable");
- i2sdev->clock_enable = pmf_find_function(np, "clock-enable");
- i2sdev->cell_disable = pmf_find_function(np, "cell-disable");
- i2sdev->clock_disable = pmf_find_function(np, "clock-disable");
-
- /* if the bus number is not 0 or 1 we absolutely need to use
- * the platform functions -- there's nothing in Darwin that
- * would allow seeing a system behind what the FCRs are then,
- * and I don't want to go parsing a bunch of platform functions
- * by hand to try finding a system... */
- if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 &&
- (!i2sdev->enable ||
- !i2sdev->cell_enable || !i2sdev->clock_enable ||
- !i2sdev->cell_disable || !i2sdev->clock_disable)) {
- pmf_put_function(i2sdev->enable);
- pmf_put_function(i2sdev->cell_enable);
- pmf_put_function(i2sdev->clock_enable);
- pmf_put_function(i2sdev->cell_disable);
- pmf_put_function(i2sdev->clock_disable);
- return -ENODEV;
- }
-
- list_add(&i2sdev->item, &c->list);
-
- return 0;
-}
-
-void i2sbus_control_remove_dev(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev)
-{
- /* this is serialised externally */
- list_del(&i2sdev->item);
- if (list_empty(&c->list))
- i2sbus_control_destroy(c);
-}
-
-int i2sbus_control_enable(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev)
-{
- struct pmf_args args = { .count = 0 };
- struct macio_chip *macio = c->macio;
-
- if (i2sdev->enable)
- return pmf_call_one(i2sdev->enable, &args);
-
- if (macio == NULL || macio->base == NULL)
- return -ENODEV;
-
- switch (i2sdev->bus_number) {
- case 0:
- /* these need to be locked or done through
- * newly created feature calls! */
- MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE);
- break;
- case 1:
- MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_ENABLE);
- break;
- default:
- return -ENODEV;
- }
- return 0;
-}
-
-int i2sbus_control_cell(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev,
- int enable)
-{
- struct pmf_args args = { .count = 0 };
- struct macio_chip *macio = c->macio;
-
- switch (enable) {
- case 0:
- if (i2sdev->cell_disable)
- return pmf_call_one(i2sdev->cell_disable, &args);
- break;
- case 1:
- if (i2sdev->cell_enable)
- return pmf_call_one(i2sdev->cell_enable, &args);
- break;
- default:
- printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n");
- return -ENODEV;
- }
-
- if (macio == NULL || macio->base == NULL)
- return -ENODEV;
-
- switch (i2sdev->bus_number) {
- case 0:
- if (enable)
- MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE);
- else
- MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE);
- break;
- case 1:
- if (enable)
- MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE);
- else
- MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE);
- break;
- default:
- return -ENODEV;
- }
- return 0;
-}
-
-int i2sbus_control_clock(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev,
- int enable)
-{
- struct pmf_args args = { .count = 0 };
- struct macio_chip *macio = c->macio;
-
- switch (enable) {
- case 0:
- if (i2sdev->clock_disable)
- return pmf_call_one(i2sdev->clock_disable, &args);
- break;
- case 1:
- if (i2sdev->clock_enable)
- return pmf_call_one(i2sdev->clock_enable, &args);
- break;
- default:
- printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n");
- return -ENODEV;
- }
-
- if (macio == NULL || macio->base == NULL)
- return -ENODEV;
-
- switch (i2sdev->bus_number) {
- case 0:
- if (enable)
- MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
- else
- MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
- break;
- case 1:
- if (enable)
- MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT);
- else
- MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT);
- break;
- default:
- return -ENODEV;
- }
- return 0;
-}
diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c
deleted file mode 100644
index 01065833..00000000
--- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/core.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * i2sbus driver
- *
- * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
- *
- * GPL v2, can be found in COPYING.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-
-#include <asm/macio.h>
-#include <asm/dbdma.h>
-
-#include "../soundbus.h"
-#include "i2sbus.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
-MODULE_DESCRIPTION("Apple Soundbus: I2S support");
-
-static int force;
-module_param(force, int, 0444);
-MODULE_PARM_DESC(force, "Force loading i2sbus even when"
- " no layout-id property is present");
-
-static struct of_device_id i2sbus_match[] = {
- { .name = "i2s" },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, i2sbus_match);
-
-static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
- struct dbdma_command_mem *r,
- int numcmds)
-{
- /* one more for rounding, one for branch back, one for stop command */
- r->size = (numcmds + 3) * sizeof(struct dbdma_cmd);
- /* We use the PCI APIs for now until the generic one gets fixed
- * enough or until we get some macio-specific versions
- */
- r->space = dma_alloc_coherent(
- &macio_get_pci_dev(i2sdev->macio)->dev,
- r->size,
- &r->bus_addr,
- GFP_KERNEL);
-
- if (!r->space) return -ENOMEM;
-
- memset(r->space, 0, r->size);
- r->cmds = (void*)DBDMA_ALIGN(r->space);
- r->bus_cmd_start = r->bus_addr +
- (dma_addr_t)((char*)r->cmds - (char*)r->space);
-
- return 0;
-}
-
-static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev,
- struct dbdma_command_mem *r)
-{
- if (!r->space) return;
-
- dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev,
- r->size, r->space, r->bus_addr);
-}
-
-static void i2sbus_release_dev(struct device *dev)
-{
- struct i2sbus_dev *i2sdev;
- int i;
-
- i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
-
- if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
- if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
- if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
- for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
- if (i2sdev->allocated_resource[i])
- release_and_free_resource(i2sdev->allocated_resource[i]);
- free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
- free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring);
- for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
- free_irq(i2sdev->interrupts[i], i2sdev);
- i2sbus_control_remove_dev(i2sdev->control, i2sdev);
- mutex_destroy(&i2sdev->lock);
- kfree(i2sdev);
-}
-
-static irqreturn_t i2sbus_bus_intr(int irq, void *devid)
-{
- struct i2sbus_dev *dev = devid;
- u32 intreg;
-
- spin_lock(&dev->low_lock);
- intreg = in_le32(&dev->intfregs->intr_ctl);
-
- /* acknowledge interrupt reasons */
- out_le32(&dev->intfregs->intr_ctl, intreg);
-
- spin_unlock(&dev->low_lock);
-
- return IRQ_HANDLED;
-}
-
-
-/*
- * XXX FIXME: We test the layout_id's here to get the proper way of
- * mapping in various registers, thanks to bugs in Apple device-trees.
- * We could instead key off the machine model and the name of the i2s
- * node (i2s-a). This we'll do when we move it all to macio_asic.c
- * and have that export items for each sub-node too.
- */
-static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
- int layout, struct resource *res)
-{
- struct device_node *parent;
- int pindex, rc = -ENXIO;
- const u32 *reg;
-
- /* Machines with layout 76 and 36 (K2 based) have a weird device
- * tree what we need to special case.
- * Normal machines just fetch the resource from the i2s-X node.
- * Darwin further divides normal machines into old and new layouts
- * with a subtely different code path but that doesn't seem necessary
- * in practice, they just bloated it. In addition, even on our K2
- * case the i2s-modem node, if we ever want to handle it, uses the
- * normal layout
- */
- if (layout != 76 && layout != 36)
- return of_address_to_resource(np, index, res);
-
- parent = of_get_parent(np);
- pindex = (index == aoa_resource_i2smmio) ? 0 : 1;
- rc = of_address_to_resource(parent, pindex, res);
- if (rc)
- goto bail;
- reg = of_get_property(np, "reg", NULL);
- if (reg == NULL) {
- rc = -ENXIO;
- goto bail;
- }
- res->start += reg[index * 2];
- res->end = res->start + reg[index * 2 + 1] - 1;
- bail:
- of_node_put(parent);
- return rc;
-}
-
-/* FIXME: look at device node refcounting */
-static int i2sbus_add_dev(struct macio_dev *macio,
- struct i2sbus_control *control,
- struct device_node *np)
-{
- struct i2sbus_dev *dev;
- struct device_node *child = NULL, *sound = NULL;
- struct resource *r;
- int i, layout = 0, rlen, ok = force;
- static const char *rnames[] = { "i2sbus: %s (control)",
- "i2sbus: %s (tx)",
- "i2sbus: %s (rx)" };
- static irq_handler_t ints[] = {
- i2sbus_bus_intr,
- i2sbus_tx_intr,
- i2sbus_rx_intr
- };
-
- if (strlen(np->name) != 5)
- return 0;
- if (strncmp(np->name, "i2s-", 4))
- return 0;
-
- dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
- if (!dev)
- return 0;
-
- i = 0;
- while ((child = of_get_next_child(np, child))) {
- if (strcmp(child->name, "sound") == 0) {
- i++;
- sound = child;
- }
- }
- if (i == 1) {
- const u32 *id = of_get_property(sound, "layout-id", NULL);
-
- if (id) {
- layout = *id;
- snprintf(dev->sound.modalias, 32,
- "sound-layout-%d", layout);
- ok = 1;
- } else {
- id = of_get_property(sound, "device-id", NULL);
- /*
- * We probably cannot handle all device-id machines,
- * so restrict to those we do handle for now.
- */
- if (id && (*id == 22 || *id == 14 || *id == 35)) {
- snprintf(dev->sound.modalias, 32,
- "aoa-device-id-%d", *id);
- ok = 1;
- layout = -1;
- }
- }
- }
- /* for the time being, until we can handle non-layout-id
- * things in some fabric, refuse to attach if there is no
- * layout-id property or we haven't been forced to attach.
- * When there are two i2s busses and only one has a layout-id,
- * then this depends on the order, but that isn't important
- * either as the second one in that case is just a modem. */
- if (!ok) {
- kfree(dev);
- return -ENODEV;
- }
-
- mutex_init(&dev->lock);
- spin_lock_init(&dev->low_lock);
- dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask;
- dev->sound.ofdev.dev.of_node = np;
- dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask;
- dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
- dev->sound.ofdev.dev.release = i2sbus_release_dev;
- dev->sound.attach_codec = i2sbus_attach_codec;
- dev->sound.detach_codec = i2sbus_detach_codec;
- dev->sound.pcmid = -1;
- dev->macio = macio;
- dev->control = control;
- dev->bus_number = np->name[4] - 'a';
- INIT_LIST_HEAD(&dev->sound.codec_list);
-
- for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
- dev->interrupts[i] = -1;
- snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
- rnames[i], np->name);
- }
- for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
- int irq = irq_of_parse_and_map(np, i);
- if (request_irq(irq, ints[i], 0, dev->rnames[i], dev))
- goto err;
- dev->interrupts[i] = irq;
- }
-
-
- /* Resource handling is problematic as some device-trees contain
- * useless crap (ugh ugh ugh). We work around that here by calling
- * specific functions for calculating the appropriate resources.
- *
- * This will all be moved to macio_asic.c at one point
- */
- for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
- if (i2sbus_get_and_fixup_rsrc(np,i,layout,&dev->resources[i]))
- goto err;
- /* If only we could use our resource dev->resources[i]...
- * but request_resource doesn't know about parents and
- * contained resources...
- */
- dev->allocated_resource[i] =
- request_mem_region(dev->resources[i].start,
- resource_size(&dev->resources[i]),
- dev->rnames[i]);
- if (!dev->allocated_resource[i]) {
- printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i);
- goto err;
- }
- }
-
- r = &dev->resources[aoa_resource_i2smmio];
- rlen = resource_size(r);
- if (rlen < sizeof(struct i2s_interface_regs))
- goto err;
- dev->intfregs = ioremap(r->start, rlen);
-
- r = &dev->resources[aoa_resource_txdbdma];
- rlen = resource_size(r);
- if (rlen < sizeof(struct dbdma_regs))
- goto err;
- dev->out.dbdma = ioremap(r->start, rlen);
-
- r = &dev->resources[aoa_resource_rxdbdma];
- rlen = resource_size(r);
- if (rlen < sizeof(struct dbdma_regs))
- goto err;
- dev->in.dbdma = ioremap(r->start, rlen);
-
- if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma)
- goto err;
-
- if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring,
- MAX_DBDMA_COMMANDS))
- goto err;
- if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring,
- MAX_DBDMA_COMMANDS))
- goto err;
-
- if (i2sbus_control_add_dev(dev->control, dev)) {
- printk(KERN_ERR "i2sbus: control layer didn't like bus\n");
- goto err;
- }
-
- if (soundbus_add_one(&dev->sound)) {
- printk(KERN_DEBUG "i2sbus: device registration error!\n");
- goto err;
- }
-
- /* enable this cell */
- i2sbus_control_cell(dev->control, dev, 1);
- i2sbus_control_enable(dev->control, dev);
- i2sbus_control_clock(dev->control, dev, 1);
-
- return 1;
- err:
- for (i=0;i<3;i++)
- if (dev->interrupts[i] != -1)
- free_irq(dev->interrupts[i], dev);
- free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
- free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
- if (dev->intfregs) iounmap(dev->intfregs);
- if (dev->out.dbdma) iounmap(dev->out.dbdma);
- if (dev->in.dbdma) iounmap(dev->in.dbdma);
- for (i=0;i<3;i++)
- if (dev->allocated_resource[i])
- release_and_free_resource(dev->allocated_resource[i]);
- mutex_destroy(&dev->lock);
- kfree(dev);
- return 0;
-}
-
-static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
-{
- struct device_node *np = NULL;
- int got = 0, err;
- struct i2sbus_control *control = NULL;
-
- err = i2sbus_control_init(dev, &control);
- if (err)
- return err;
- if (!control) {
- printk(KERN_ERR "i2sbus_control_init API breakage\n");
- return -ENODEV;
- }
-
- while ((np = of_get_next_child(dev->ofdev.dev.of_node, np))) {
- if (of_device_is_compatible(np, "i2sbus") ||
- of_device_is_compatible(np, "i2s-modem")) {
- got += i2sbus_add_dev(dev, control, np);
- }
- }
-
- if (!got) {
- /* found none, clean up */
- i2sbus_control_destroy(control);
- return -ENODEV;
- }
-
- dev_set_drvdata(&dev->ofdev.dev, control);
-
- return 0;
-}
-
-static int i2sbus_remove(struct macio_dev* dev)
-{
- struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
- struct i2sbus_dev *i2sdev, *tmp;
-
- list_for_each_entry_safe(i2sdev, tmp, &control->list, item)
- soundbus_remove_one(&i2sdev->sound);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
-{
- struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
- struct codec_info_item *cii;
- struct i2sbus_dev* i2sdev;
- int err, ret = 0;
-
- list_for_each_entry(i2sdev, &control->list, item) {
- /* Notify Alsa */
- if (i2sdev->sound.pcm) {
- /* Suspend PCM streams */
- snd_pcm_suspend_all(i2sdev->sound.pcm);
- }
-
- /* Notify codecs */
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- err = 0;
- if (cii->codec->suspend)
- err = cii->codec->suspend(cii, state);
- if (err)
- ret = err;
- }
-
- /* wait until streams are stopped */
- i2sbus_wait_for_stop_both(i2sdev);
- }
-
- return ret;
-}
-
-static int i2sbus_resume(struct macio_dev* dev)
-{
- struct i2sbus_control *control = dev_get_drvdata(&dev->ofdev.dev);
- struct codec_info_item *cii;
- struct i2sbus_dev* i2sdev;
- int err, ret = 0;
-
- list_for_each_entry(i2sdev, &control->list, item) {
- /* reset i2s bus format etc. */
- i2sbus_pcm_prepare_both(i2sdev);
-
- /* Notify codecs so they can re-initialize */
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- err = 0;
- if (cii->codec->resume)
- err = cii->codec->resume(cii);
- if (err)
- ret = err;
- }
- }
-
- return ret;
-}
-#endif /* CONFIG_PM */
-
-static int i2sbus_shutdown(struct macio_dev* dev)
-{
- return 0;
-}
-
-static struct macio_driver i2sbus_drv = {
- .driver = {
- .name = "soundbus-i2s",
- .owner = THIS_MODULE,
- .of_match_table = i2sbus_match,
- },
- .probe = i2sbus_probe,
- .remove = i2sbus_remove,
-#ifdef CONFIG_PM
- .suspend = i2sbus_suspend,
- .resume = i2sbus_resume,
-#endif
- .shutdown = i2sbus_shutdown,
-};
-
-static int __init soundbus_i2sbus_init(void)
-{
- return macio_register_driver(&i2sbus_drv);
-}
-
-static void __exit soundbus_i2sbus_exit(void)
-{
- macio_unregister_driver(&i2sbus_drv);
-}
-
-module_init(soundbus_i2sbus_init);
-module_exit(soundbus_i2sbus_exit);
diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h
deleted file mode 100644
index befefd99..00000000
--- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * i2sbus driver -- private definitions
- *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- *
- * GPL v2, can be found in COPYING.
- */
-#ifndef __I2SBUS_H
-#define __I2SBUS_H
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-
-#include <sound/pcm.h>
-
-#include <asm/prom.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-
-#include "interface.h"
-#include "../soundbus.h"
-
-struct i2sbus_control {
- struct list_head list;
- struct macio_chip *macio;
-};
-
-#define MAX_DBDMA_COMMANDS 32
-
-struct dbdma_command_mem {
- dma_addr_t bus_addr;
- dma_addr_t bus_cmd_start;
- struct dbdma_cmd *cmds;
- void *space;
- int size;
- u32 running:1;
- u32 stopping:1;
-};
-
-struct pcm_info {
- u32 created:1, /* has this direction been created with alsa? */
- active:1; /* is this stream active? */
- /* runtime information */
- struct snd_pcm_substream *substream;
- int current_period;
- u32 frame_count;
- struct dbdma_command_mem dbdma_ring;
- volatile struct dbdma_regs __iomem *dbdma;
- struct completion *stop_completion;
-};
-
-enum {
- aoa_resource_i2smmio = 0,
- aoa_resource_txdbdma,
- aoa_resource_rxdbdma,
-};
-
-struct i2sbus_dev {
- struct soundbus_dev sound;
- struct macio_dev *macio;
- struct i2sbus_control *control;
- volatile struct i2s_interface_regs __iomem *intfregs;
-
- struct resource resources[3];
- struct resource *allocated_resource[3];
- int interrupts[3];
- char rnames[3][32];
-
- /* info about currently active substreams */
- struct pcm_info out, in;
- snd_pcm_format_t format;
- unsigned int rate;
-
- /* list for a single controller */
- struct list_head item;
- /* number of bus on controller */
- int bus_number;
- /* for use by control layer */
- struct pmf_function *enable,
- *cell_enable,
- *cell_disable,
- *clock_enable,
- *clock_disable;
-
- /* locks */
- /* spinlock for low-level interrupt locking */
- spinlock_t low_lock;
- /* mutex for high-level consistency */
- struct mutex lock;
-};
-
-#define soundbus_dev_to_i2sbus_dev(sdev) \
- container_of(sdev, struct i2sbus_dev, sound)
-
-/* pcm specific functions */
-extern int
-i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
- struct codec_info *ci, void *data);
-extern void
-i2sbus_detach_codec(struct soundbus_dev *dev, void *data);
-extern irqreturn_t
-i2sbus_tx_intr(int irq, void *devid);
-extern irqreturn_t
-i2sbus_rx_intr(int irq, void *devid);
-
-extern void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev);
-extern void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev);
-
-/* control specific functions */
-extern int i2sbus_control_init(struct macio_dev* dev,
- struct i2sbus_control **c);
-extern void i2sbus_control_destroy(struct i2sbus_control *c);
-extern int i2sbus_control_add_dev(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev);
-extern void i2sbus_control_remove_dev(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev);
-extern int i2sbus_control_enable(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev);
-extern int i2sbus_control_cell(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev,
- int enable);
-extern int i2sbus_control_clock(struct i2sbus_control *c,
- struct i2sbus_dev *i2sdev,
- int enable);
-#endif /* __I2SBUS_H */
diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h
deleted file mode 100644
index c6b5f545..00000000
--- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/interface.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * i2sbus driver -- interface register definitions
- *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- *
- * GPL v2, can be found in COPYING.
- */
-#ifndef __I2SBUS_INTERFACE_H
-#define __I2SBUS_INTERFACE_H
-
-/* i2s bus control registers, at least what we know about them */
-
-#define __PAD(m,n) u8 __pad##m[n]
-#define _PAD(line, n) __PAD(line, n)
-#define PAD(n) _PAD(__LINE__, (n))
-struct i2s_interface_regs {
- __le32 intr_ctl; /* 0x00 */
- PAD(12);
- __le32 serial_format; /* 0x10 */
- PAD(12);
- __le32 codec_msg_out; /* 0x20 */
- PAD(12);
- __le32 codec_msg_in; /* 0x30 */
- PAD(12);
- __le32 frame_count; /* 0x40 */
- PAD(12);
- __le32 frame_match; /* 0x50 */
- PAD(12);
- __le32 data_word_sizes; /* 0x60 */
- PAD(12);
- __le32 peak_level_sel; /* 0x70 */
- PAD(12);
- __le32 peak_level_in0; /* 0x80 */
- PAD(12);
- __le32 peak_level_in1; /* 0x90 */
- PAD(12);
- /* total size: 0x100 bytes */
-} __attribute__((__packed__));
-
-/* interrupt register is just a bitfield with
- * interrupt enable and pending bits */
-#define I2S_REG_INTR_CTL 0x00
-# define I2S_INT_FRAME_COUNT (1<<31)
-# define I2S_PENDING_FRAME_COUNT (1<<30)
-# define I2S_INT_MESSAGE_FLAG (1<<29)
-# define I2S_PENDING_MESSAGE_FLAG (1<<28)
-# define I2S_INT_NEW_PEAK (1<<27)
-# define I2S_PENDING_NEW_PEAK (1<<26)
-# define I2S_INT_CLOCKS_STOPPED (1<<25)
-# define I2S_PENDING_CLOCKS_STOPPED (1<<24)
-# define I2S_INT_EXTERNAL_SYNC_ERROR (1<<23)
-# define I2S_PENDING_EXTERNAL_SYNC_ERROR (1<<22)
-# define I2S_INT_EXTERNAL_SYNC_OK (1<<21)
-# define I2S_PENDING_EXTERNAL_SYNC_OK (1<<20)
-# define I2S_INT_NEW_SAMPLE_RATE (1<<19)
-# define I2S_PENDING_NEW_SAMPLE_RATE (1<<18)
-# define I2S_INT_STATUS_FLAG (1<<17)
-# define I2S_PENDING_STATUS_FLAG (1<<16)
-
-/* serial format register is more interesting :)
- * It contains:
- * - clock source
- * - MClk divisor
- * - SClk divisor
- * - SClk master flag
- * - serial format (sony, i2s 64x, i2s 32x, dav, silabs)
- * - external sample frequency interrupt (don't understand)
- * - external sample frequency
- */
-#define I2S_REG_SERIAL_FORMAT 0x10
-/* clock source. You get either 18.432, 45.1584 or 49.1520 MHz */
-# define I2S_SF_CLOCK_SOURCE_SHIFT 30
-# define I2S_SF_CLOCK_SOURCE_MASK (3<<I2S_SF_CLOCK_SOURCE_SHIFT)
-# define I2S_SF_CLOCK_SOURCE_18MHz (0<<I2S_SF_CLOCK_SOURCE_SHIFT)
-# define I2S_SF_CLOCK_SOURCE_45MHz (1<<I2S_SF_CLOCK_SOURCE_SHIFT)
-# define I2S_SF_CLOCK_SOURCE_49MHz (2<<I2S_SF_CLOCK_SOURCE_SHIFT)
-/* also, let's define the exact clock speeds here, in Hz */
-#define I2S_CLOCK_SPEED_18MHz 18432000
-#define I2S_CLOCK_SPEED_45MHz 45158400
-#define I2S_CLOCK_SPEED_49MHz 49152000
-/* MClk is the clock that drives the codec, usually called its 'system clock'.
- * It is derived by taking only every 'divisor' tick of the clock.
- */
-# define I2S_SF_MCLKDIV_SHIFT 24
-# define I2S_SF_MCLKDIV_MASK (0x1F<<I2S_SF_MCLKDIV_SHIFT)
-# define I2S_SF_MCLKDIV_1 (0x14<<I2S_SF_MCLKDIV_SHIFT)
-# define I2S_SF_MCLKDIV_3 (0x13<<I2S_SF_MCLKDIV_SHIFT)
-# define I2S_SF_MCLKDIV_5 (0x12<<I2S_SF_MCLKDIV_SHIFT)
-# define I2S_SF_MCLKDIV_14 (0x0E<<I2S_SF_MCLKDIV_SHIFT)
-# define I2S_SF_MCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_MCLKDIV_SHIFT)&I2S_SF_MCLKDIV_MASK)
-static inline int i2s_sf_mclkdiv(int div, int *out)
-{
- int d;
-
- switch(div) {
- case 1: *out |= I2S_SF_MCLKDIV_1; return 0;
- case 3: *out |= I2S_SF_MCLKDIV_3; return 0;
- case 5: *out |= I2S_SF_MCLKDIV_5; return 0;
- case 14: *out |= I2S_SF_MCLKDIV_14; return 0;
- default:
- if (div%2) return -1;
- d = div/2-1;
- if (d == 0x14 || d == 0x13 || d == 0x12 || d == 0x0E)
- return -1;
- *out |= I2S_SF_MCLKDIV_OTHER(div);
- return 0;
- }
-}
-/* SClk is the clock that drives the i2s wire bus. Note that it is
- * derived from the MClk above by taking only every 'divisor' tick
- * of MClk.
- */
-# define I2S_SF_SCLKDIV_SHIFT 20
-# define I2S_SF_SCLKDIV_MASK (0xF<<I2S_SF_SCLKDIV_SHIFT)
-# define I2S_SF_SCLKDIV_1 (8<<I2S_SF_SCLKDIV_SHIFT)
-# define I2S_SF_SCLKDIV_3 (9<<I2S_SF_SCLKDIV_SHIFT)
-# define I2S_SF_SCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_SCLKDIV_SHIFT)&I2S_SF_SCLKDIV_MASK)
-static inline int i2s_sf_sclkdiv(int div, int *out)
-{
- int d;
-
- switch(div) {
- case 1: *out |= I2S_SF_SCLKDIV_1; return 0;
- case 3: *out |= I2S_SF_SCLKDIV_3; return 0;
- default:
- if (div%2) return -1;
- d = div/2-1;
- if (d == 8 || d == 9) return -1;
- *out |= I2S_SF_SCLKDIV_OTHER(div);
- return 0;
- }
-}
-# define I2S_SF_SCLK_MASTER (1<<19)
-/* serial format is the way the data is put to the i2s wire bus */
-# define I2S_SF_SERIAL_FORMAT_SHIFT 16
-# define I2S_SF_SERIAL_FORMAT_MASK (7<<I2S_SF_SERIAL_FORMAT_SHIFT)
-# define I2S_SF_SERIAL_FORMAT_SONY (0<<I2S_SF_SERIAL_FORMAT_SHIFT)
-# define I2S_SF_SERIAL_FORMAT_I2S_64X (1<<I2S_SF_SERIAL_FORMAT_SHIFT)
-# define I2S_SF_SERIAL_FORMAT_I2S_32X (2<<I2S_SF_SERIAL_FORMAT_SHIFT)
-# define I2S_SF_SERIAL_FORMAT_I2S_DAV (4<<I2S_SF_SERIAL_FORMAT_SHIFT)
-# define I2S_SF_SERIAL_FORMAT_I2S_SILABS (5<<I2S_SF_SERIAL_FORMAT_SHIFT)
-/* unknown */
-# define I2S_SF_EXT_SAMPLE_FREQ_INT_SHIFT 12
-# define I2S_SF_EXT_SAMPLE_FREQ_INT_MASK (0xF<<I2S_SF_SAMPLE_FREQ_INT_SHIFT)
-/* probably gives external frequency? */
-# define I2S_SF_EXT_SAMPLE_FREQ_MASK 0xFFF
-
-/* used to send codec messages, but how isn't clear */
-#define I2S_REG_CODEC_MSG_OUT 0x20
-
-/* used to receive codec messages, but how isn't clear */
-#define I2S_REG_CODEC_MSG_IN 0x30
-
-/* frame count reg isn't clear to me yet, but probably useful */
-#define I2S_REG_FRAME_COUNT 0x40
-
-/* program to some value, and get interrupt if frame count reaches it */
-#define I2S_REG_FRAME_MATCH 0x50
-
-/* this register describes how the bus transfers data */
-#define I2S_REG_DATA_WORD_SIZES 0x60
-/* number of interleaved input channels */
-# define I2S_DWS_NUM_CHANNELS_IN_SHIFT 24
-# define I2S_DWS_NUM_CHANNELS_IN_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_IN_SHIFT)
-/* word size of input data */
-# define I2S_DWS_DATA_IN_SIZE_SHIFT 16
-# define I2S_DWS_DATA_IN_16BIT (0<<I2S_DWS_DATA_IN_SIZE_SHIFT)
-# define I2S_DWS_DATA_IN_24BIT (3<<I2S_DWS_DATA_IN_SIZE_SHIFT)
-/* number of interleaved output channels */
-# define I2S_DWS_NUM_CHANNELS_OUT_SHIFT 8
-# define I2S_DWS_NUM_CHANNELS_OUT_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_OUT_SHIFT)
-/* word size of output data */
-# define I2S_DWS_DATA_OUT_SIZE_SHIFT 0
-# define I2S_DWS_DATA_OUT_16BIT (0<<I2S_DWS_DATA_OUT_SIZE_SHIFT)
-# define I2S_DWS_DATA_OUT_24BIT (3<<I2S_DWS_DATA_OUT_SIZE_SHIFT)
-
-
-/* unknown */
-#define I2S_REG_PEAK_LEVEL_SEL 0x70
-
-/* unknown */
-#define I2S_REG_PEAK_LEVEL_IN0 0x80
-
-/* unknown */
-#define I2S_REG_PEAK_LEVEL_IN1 0x90
-
-#endif /* __I2SBUS_INTERFACE_H */
diff --git a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c b/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c
deleted file mode 100644
index 19491ed9..00000000
--- a/ANDROID_3.4.5/sound/aoa/soundbus/i2sbus/pcm.c
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * i2sbus driver -- pcm routines
- *
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
- *
- * GPL v2, can be found in COPYING.
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <asm/macio.h>
-#include <linux/pci.h>
-#include <linux/module.h>
-#include "../soundbus.h"
-#include "i2sbus.h"
-
-static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in,
- struct pcm_info **pi, struct pcm_info **other)
-{
- if (in) {
- if (pi)
- *pi = &i2sdev->in;
- if (other)
- *other = &i2sdev->out;
- } else {
- if (pi)
- *pi = &i2sdev->out;
- if (other)
- *other = &i2sdev->in;
- }
-}
-
-static int clock_and_divisors(int mclk, int sclk, int rate, int *out)
-{
- /* sclk must be derived from mclk! */
- if (mclk % sclk)
- return -1;
- /* derive sclk register value */
- if (i2s_sf_sclkdiv(mclk / sclk, out))
- return -1;
-
- if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) {
- if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) {
- *out |= I2S_SF_CLOCK_SOURCE_18MHz;
- return 0;
- }
- }
- if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) {
- if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) {
- *out |= I2S_SF_CLOCK_SOURCE_45MHz;
- return 0;
- }
- }
- if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) {
- if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) {
- *out |= I2S_SF_CLOCK_SOURCE_49MHz;
- return 0;
- }
- }
- return -1;
-}
-
-#define CHECK_RATE(rate) \
- do { if (rates & SNDRV_PCM_RATE_ ##rate) { \
- int dummy; \
- if (clock_and_divisors(sysclock_factor, \
- bus_factor, rate, &dummy)) \
- rates &= ~SNDRV_PCM_RATE_ ##rate; \
- } } while (0)
-
-static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
-{
- struct pcm_info *pi, *other;
- struct soundbus_dev *sdev;
- int masks_inited = 0, err;
- struct codec_info_item *cii, *rev;
- struct snd_pcm_hardware *hw;
- u64 formats = 0;
- unsigned int rates = 0;
- struct transfer_info v;
- int result = 0;
- int bus_factor = 0, sysclock_factor = 0;
- int found_this;
-
- mutex_lock(&i2sdev->lock);
-
- get_pcm_info(i2sdev, in, &pi, &other);
-
- hw = &pi->substream->runtime->hw;
- sdev = &i2sdev->sound;
-
- if (pi->active) {
- /* alsa messed up */
- result = -EBUSY;
- goto out_unlock;
- }
-
- /* we now need to assign the hw */
- list_for_each_entry(cii, &sdev->codec_list, list) {
- struct transfer_info *ti = cii->codec->transfers;
- bus_factor = cii->codec->bus_factor;
- sysclock_factor = cii->codec->sysclock_factor;
- while (ti->formats && ti->rates) {
- v = *ti;
- if (ti->transfer_in == in
- && cii->codec->usable(cii, ti, &v)) {
- if (masks_inited) {
- formats &= v.formats;
- rates &= v.rates;
- } else {
- formats = v.formats;
- rates = v.rates;
- masks_inited = 1;
- }
- }
- ti++;
- }
- }
- if (!masks_inited || !bus_factor || !sysclock_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
- /* bus dependent stuff */
- hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_JOINT_DUPLEX;
-
- CHECK_RATE(5512);
- CHECK_RATE(8000);
- CHECK_RATE(11025);
- CHECK_RATE(16000);
- CHECK_RATE(22050);
- CHECK_RATE(32000);
- CHECK_RATE(44100);
- CHECK_RATE(48000);
- CHECK_RATE(64000);
- CHECK_RATE(88200);
- CHECK_RATE(96000);
- CHECK_RATE(176400);
- CHECK_RATE(192000);
- hw->rates = rates;
-
- /* well. the codec might want 24 bits only, and we'll
- * ever only transfer 24 bits, but they are top-aligned!
- * So for alsa, we claim that we're doing full 32 bit
- * while in reality we'll ignore the lower 8 bits of
- * that when doing playback (they're transferred as 0
- * as far as I know, no codecs we have are 32-bit capable
- * so I can't really test) and when doing recording we'll
- * always have those lower 8 bits recorded as 0 */
- if (formats & SNDRV_PCM_FMTBIT_S24_BE)
- formats |= SNDRV_PCM_FMTBIT_S32_BE;
- if (formats & SNDRV_PCM_FMTBIT_U24_BE)
- formats |= SNDRV_PCM_FMTBIT_U32_BE;
- /* now mask off what we can support. I suppose we could
- * also support S24_3LE and some similar formats, but I
- * doubt there's a codec that would be able to use that,
- * so we don't support it here. */
- hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE |
- SNDRV_PCM_FMTBIT_U16_BE |
- SNDRV_PCM_FMTBIT_S32_BE |
- SNDRV_PCM_FMTBIT_U32_BE);
-
- /* we need to set the highest and lowest rate possible.
- * These are the highest and lowest rates alsa can
- * support properly in its bitfield.
- * Below, we'll use that to restrict to the rate
- * currently in use (if any). */
- hw->rate_min = 5512;
- hw->rate_max = 192000;
- /* if the other stream is active, then we can only
- * support what it is currently using.
- * FIXME: I lied. This comment is wrong. We can support
- * anything that works with the same serial format, ie.
- * when recording 24 bit sound we can well play 16 bit
- * sound at the same time iff using the same transfer mode.
- */
- if (other->active) {
- /* FIXME: is this guaranteed by the alsa api? */
- hw->formats &= (1ULL << i2sdev->format);
- /* see above, restrict rates to the one we already have */
- hw->rate_min = i2sdev->rate;
- hw->rate_max = i2sdev->rate;
- }
-
- hw->channels_min = 2;
- hw->channels_max = 2;
- /* these are somewhat arbitrary */
- hw->buffer_bytes_max = 131072;
- hw->period_bytes_min = 256;
- hw->period_bytes_max = 16384;
- hw->periods_min = 3;
- hw->periods_max = MAX_DBDMA_COMMANDS;
- err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0) {
- result = err;
- goto out_unlock;
- }
- list_for_each_entry(cii, &sdev->codec_list, list) {
- if (cii->codec->open) {
- err = cii->codec->open(cii, pi->substream);
- if (err) {
- result = err;
- /* unwind */
- found_this = 0;
- list_for_each_entry_reverse(rev,
- &sdev->codec_list, list) {
- if (found_this && rev->codec->close) {
- rev->codec->close(rev,
- pi->substream);
- }
- if (rev == cii)
- found_this = 1;
- }
- goto out_unlock;
- }
- }
- }
-
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
-}
-
-#undef CHECK_RATE
-
-static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in)
-{
- struct codec_info_item *cii;
- struct pcm_info *pi;
- int err = 0, tmp;
-
- mutex_lock(&i2sdev->lock);
-
- get_pcm_info(i2sdev, in, &pi, NULL);
-
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- if (cii->codec->close) {
- tmp = cii->codec->close(cii, pi->substream);
- if (tmp)
- err = tmp;
- }
- }
-
- pi->substream = NULL;
- pi->active = 0;
- mutex_unlock(&i2sdev->lock);
- return err;
-}
-
-static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev,
- struct pcm_info *pi)
-{
- unsigned long flags;
- struct completion done;
- long timeout;
-
- spin_lock_irqsave(&i2sdev->low_lock, flags);
- if (pi->dbdma_ring.stopping) {
- init_completion(&done);
- pi->stop_completion = &done;
- spin_unlock_irqrestore(&i2sdev->low_lock, flags);
- timeout = wait_for_completion_timeout(&done, HZ);
- spin_lock_irqsave(&i2sdev->low_lock, flags);
- pi->stop_completion = NULL;
- if (timeout == 0) {
- /* timeout expired, stop dbdma forcefully */
- printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n");
- /* make sure RUN, PAUSE and S0 bits are cleared */
- out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
- pi->dbdma_ring.stopping = 0;
- timeout = 10;
- while (in_le32(&pi->dbdma->status) & ACTIVE) {
- if (--timeout <= 0)
- break;
- udelay(1);
- }
- }
- }
- spin_unlock_irqrestore(&i2sdev->low_lock, flags);
-}
-
-#ifdef CONFIG_PM
-void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
-{
- struct pcm_info *pi;
-
- get_pcm_info(i2sdev, 0, &pi, NULL);
- i2sbus_wait_for_stop(i2sdev, pi);
- get_pcm_info(i2sdev, 1, &pi, NULL);
- i2sbus_wait_for_stop(i2sdev, pi);
-}
-#endif
-
-static int i2sbus_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-}
-
-static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
- struct pcm_info *pi;
-
- get_pcm_info(i2sdev, in, &pi, NULL);
- if (pi->dbdma_ring.stopping)
- i2sbus_wait_for_stop(i2sdev, pi);
- snd_pcm_lib_free_pages(substream);
- return 0;
-}
-
-static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
-{
- return i2sbus_hw_free(substream, 0);
-}
-
-static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
-{
- return i2sbus_hw_free(substream, 1);
-}
-
-static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
-{
- /* whee. Hard work now. The user has selected a bitrate
- * and bit format, so now we have to program our
- * I2S controller appropriately. */
- struct snd_pcm_runtime *runtime;
- struct dbdma_cmd *command;
- int i, periodsize, nperiods;
- dma_addr_t offset;
- struct bus_info bi;
- struct codec_info_item *cii;
- int sfr = 0; /* serial format register */
- int dws = 0; /* data word sizes reg */
- int input_16bit;
- struct pcm_info *pi, *other;
- int cnt;
- int result = 0;
- unsigned int cmd, stopaddr;
-
- mutex_lock(&i2sdev->lock);
-
- get_pcm_info(i2sdev, in, &pi, &other);
-
- if (pi->dbdma_ring.running) {
- result = -EBUSY;
- goto out_unlock;
- }
- if (pi->dbdma_ring.stopping)
- i2sbus_wait_for_stop(i2sdev, pi);
-
- if (!pi->substream || !pi->substream->runtime) {
- result = -EINVAL;
- goto out_unlock;
- }
-
- runtime = pi->substream->runtime;
- pi->active = 1;
- if (other->active &&
- ((i2sdev->format != runtime->format)
- || (i2sdev->rate != runtime->rate))) {
- result = -EINVAL;
- goto out_unlock;
- }
-
- i2sdev->format = runtime->format;
- i2sdev->rate = runtime->rate;
-
- periodsize = snd_pcm_lib_period_bytes(pi->substream);
- nperiods = pi->substream->runtime->periods;
- pi->current_period = 0;
-
- /* generate dbdma command ring first */
- command = pi->dbdma_ring.cmds;
- memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd));
-
- /* commands to DMA to/from the ring */
- /*
- * For input, we need to do a graceful stop; if we abort
- * the DMA, we end up with leftover bytes that corrupt
- * the next recording. To do this we set the S0 status
- * bit and wait for the DMA controller to stop. Each
- * command has a branch condition to
- * make it branch to a stop command if S0 is set.
- * On input we also need to wait for the S7 bit to be
- * set before turning off the DMA controller.
- * In fact we do the graceful stop for output as well.
- */
- offset = runtime->dma_addr;
- cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS;
- stopaddr = pi->dbdma_ring.bus_cmd_start +
- (nperiods + 1) * sizeof(struct dbdma_cmd);
- for (i = 0; i < nperiods; i++, command++, offset += periodsize) {
- command->command = cpu_to_le16(cmd);
- command->cmd_dep = cpu_to_le32(stopaddr);
- command->phy_addr = cpu_to_le32(offset);
- command->req_count = cpu_to_le16(periodsize);
- }
-
- /* branch back to beginning of ring */
- command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS);
- command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start);
- command++;
-
- /* set stop command */
- command->command = cpu_to_le16(DBDMA_STOP);
-
- /* ok, let's set the serial format and stuff */
- switch (runtime->format) {
- /* 16 bit formats */
- case SNDRV_PCM_FORMAT_S16_BE:
- case SNDRV_PCM_FORMAT_U16_BE:
- /* FIXME: if we add different bus factors we need to
- * do more here!! */
- bi.bus_factor = 0;
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- bi.bus_factor = cii->codec->bus_factor;
- break;
- }
- if (!bi.bus_factor) {
- result = -ENODEV;
- goto out_unlock;
- }
- input_16bit = 1;
- break;
- case SNDRV_PCM_FORMAT_S32_BE:
- case SNDRV_PCM_FORMAT_U32_BE:
- /* force 64x bus speed, otherwise the data cannot be
- * transferred quickly enough! */
- bi.bus_factor = 64;
- input_16bit = 0;
- break;
- default:
- result = -EINVAL;
- goto out_unlock;
- }
- /* we assume all sysclocks are the same! */
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- bi.sysclock_factor = cii->codec->sysclock_factor;
- break;
- }
-
- if (clock_and_divisors(bi.sysclock_factor,
- bi.bus_factor,
- runtime->rate,
- &sfr) < 0) {
- result = -EINVAL;
- goto out_unlock;
- }
- switch (bi.bus_factor) {
- case 32:
- sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X;
- break;
- case 64:
- sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X;
- break;
- }
- /* FIXME: THIS ASSUMES MASTER ALL THE TIME */
- sfr |= I2S_SF_SCLK_MASTER;
-
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
- int err = 0;
- if (cii->codec->prepare)
- err = cii->codec->prepare(cii, &bi, pi->substream);
- if (err) {
- result = err;
- goto out_unlock;
- }
- }
- /* codecs are fine with it, so set our clocks */
- if (input_16bit)
- dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) |
- (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) |
- I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT;
- else
- dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) |
- (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) |
- I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT;
-
- /* early exit if already programmed correctly */
- /* not locking these is fine since we touch them only in this function */
- if (in_le32(&i2sdev->intfregs->serial_format) == sfr
- && in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
- goto out_unlock;
-
- /* let's notify the codecs about clocks going away.
- * For now we only do mastering on the i2s cell... */
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
- if (cii->codec->switch_clock)
- cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE);
-
- i2sbus_control_enable(i2sdev->control, i2sdev);
- i2sbus_control_cell(i2sdev->control, i2sdev, 1);
-
- out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED);
-
- i2sbus_control_clock(i2sdev->control, i2sdev, 0);
-
- msleep(1);
-
- /* wait for clock stopped. This can apparently take a while... */
- cnt = 100;
- while (cnt-- &&
- !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) {
- msleep(5);
- }
- out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED);
-
- /* not locking these is fine since we touch them only in this function */
- out_le32(&i2sdev->intfregs->serial_format, sfr);
- out_le32(&i2sdev->intfregs->data_word_sizes, dws);
-
- i2sbus_control_enable(i2sdev->control, i2sdev);
- i2sbus_control_cell(i2sdev->control, i2sdev, 1);
- i2sbus_control_clock(i2sdev->control, i2sdev, 1);
- msleep(1);
-
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
- if (cii->codec->switch_clock)
- cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
-
- out_unlock:
- mutex_unlock(&i2sdev->lock);
- return result;
-}
-
-#ifdef CONFIG_PM
-void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev)
-{
- i2sbus_pcm_prepare(i2sdev, 0);
- i2sbus_pcm_prepare(i2sdev, 1);
-}
-#endif
-
-static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd)
-{
- struct codec_info_item *cii;
- struct pcm_info *pi;
- int result = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&i2sdev->low_lock, flags);
-
- get_pcm_info(i2sdev, in, &pi, NULL);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- if (pi->dbdma_ring.running) {
- result = -EALREADY;
- goto out_unlock;
- }
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
- if (cii->codec->start)
- cii->codec->start(cii, pi->substream);
- pi->dbdma_ring.running = 1;
-
- if (pi->dbdma_ring.stopping) {
- /* Clear the S0 bit, then see if we stopped yet */
- out_le32(&pi->dbdma->control, 1 << 16);
- if (in_le32(&pi->dbdma->status) & ACTIVE) {
- /* possible race here? */
- udelay(10);
- if (in_le32(&pi->dbdma->status) & ACTIVE) {
- pi->dbdma_ring.stopping = 0;
- goto out_unlock; /* keep running */
- }
- }
- }
-
- /* make sure RUN, PAUSE and S0 bits are cleared */
- out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
-
- /* set branch condition select register */
- out_le32(&pi->dbdma->br_sel, (1 << 16) | 1);
-
- /* write dma command buffer address to the dbdma chip */
- out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start);
-
- /* initialize the frame count and current period */
- pi->current_period = 0;
- pi->frame_count = in_le32(&i2sdev->intfregs->frame_count);
-
- /* set the DMA controller running */
- out_le32(&pi->dbdma->control, (RUN << 16) | RUN);
-
- /* off you go! */
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- if (!pi->dbdma_ring.running) {
- result = -EALREADY;
- goto out_unlock;
- }
- pi->dbdma_ring.running = 0;
-
- /* Set the S0 bit to make the DMA branch to the stop cmd */
- out_le32(&pi->dbdma->control, (1 << 16) | 1);
- pi->dbdma_ring.stopping = 1;
-
- list_for_each_entry(cii, &i2sdev->sound.codec_list, list)
- if (cii->codec->stop)
- cii->codec->stop(cii, pi->substream);
- break;
- default:
- result = -EINVAL;
- goto out_unlock;
- }
-
- out_unlock:
- spin_unlock_irqrestore(&i2sdev->low_lock, flags);
- return result;
-}
-
-static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in)
-{
- struct pcm_info *pi;
- u32 fc;
-
- get_pcm_info(i2sdev, in, &pi, NULL);
-
- fc = in_le32(&i2sdev->intfregs->frame_count);
- fc = fc - pi->frame_count;
-
- if (fc >= pi->substream->runtime->buffer_size)
- fc %= pi->substream->runtime->buffer_size;
- return fc;
-}
-
-static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
-{
- struct pcm_info *pi;
- u32 fc, nframes;
- u32 status;
- int timeout, i;
- int dma_stopped = 0;
- struct snd_pcm_runtime *runtime;
-
- spin_lock(&i2sdev->low_lock);
- get_pcm_info(i2sdev, in, &pi, NULL);
- if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping)
- goto out_unlock;
-
- i = pi->current_period;
- runtime = pi->substream->runtime;
- while (pi->dbdma_ring.cmds[i].xfer_status) {
- if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT)
- /*
- * BT is the branch taken bit. If it took a branch
- * it is because we set the S0 bit to make it
- * branch to the stop command.
- */
- dma_stopped = 1;
- pi->dbdma_ring.cmds[i].xfer_status = 0;
-
- if (++i >= runtime->periods) {
- i = 0;
- pi->frame_count += runtime->buffer_size;
- }
- pi->current_period = i;
-
- /*
- * Check the frame count. The DMA tends to get a bit
- * ahead of the frame counter, which confuses the core.
- */
- fc = in_le32(&i2sdev->intfregs->frame_count);
- nframes = i * runtime->period_size;
- if (fc < pi->frame_count + nframes)
- pi->frame_count = fc - nframes;
- }
-
- if (dma_stopped) {
- timeout = 1000;
- for (;;) {
- status = in_le32(&pi->dbdma->status);
- if (!(status & ACTIVE) && (!in || (status & 0x80)))
- break;
- if (--timeout <= 0) {
- printk(KERN_ERR "i2sbus: timed out "
- "waiting for DMA to stop!\n");
- break;
- }
- udelay(1);
- }
-
- /* Turn off DMA controller, clear S0 bit */
- out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16);
-
- pi->dbdma_ring.stopping = 0;
- if (pi->stop_completion)
- complete(pi->stop_completion);
- }
-
- if (!pi->dbdma_ring.running)
- goto out_unlock;
- spin_unlock(&i2sdev->low_lock);
- /* may call _trigger again, hence needs to be unlocked */
- snd_pcm_period_elapsed(pi->substream);
- return;
-
- out_unlock:
- spin_unlock(&i2sdev->low_lock);
-}
-
-irqreturn_t i2sbus_tx_intr(int irq, void *devid)
-{
- handle_interrupt((struct i2sbus_dev *)devid, 0);
- return IRQ_HANDLED;
-}
-
-irqreturn_t i2sbus_rx_intr(int irq, void *devid)
-{
- handle_interrupt((struct i2sbus_dev *)devid, 1);
- return IRQ_HANDLED;
-}
-
-static int i2sbus_playback_open(struct snd_pcm_substream *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- i2sdev->out.substream = substream;
- return i2sbus_pcm_open(i2sdev, 0);
-}
-
-static int i2sbus_playback_close(struct snd_pcm_substream *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
- int err;
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->out.substream != substream)
- return -EINVAL;
- err = i2sbus_pcm_close(i2sdev, 0);
- if (!err)
- i2sdev->out.substream = NULL;
- return err;
-}
-
-static int i2sbus_playback_prepare(struct snd_pcm_substream *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->out.substream != substream)
- return -EINVAL;
- return i2sbus_pcm_prepare(i2sdev, 0);
-}
-
-static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->out.substream != substream)
- return -EINVAL;
- return i2sbus_pcm_trigger(i2sdev, 0, cmd);
-}
-
-static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
- *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->out.substream != substream)
- return 0;
- return i2sbus_pcm_pointer(i2sdev, 0);
-}
-
-static struct snd_pcm_ops i2sbus_playback_ops = {
- .open = i2sbus_playback_open,
- .close = i2sbus_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = i2sbus_hw_params,
- .hw_free = i2sbus_playback_hw_free,
- .prepare = i2sbus_playback_prepare,
- .trigger = i2sbus_playback_trigger,
- .pointer = i2sbus_playback_pointer,
-};
-
-static int i2sbus_record_open(struct snd_pcm_substream *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- i2sdev->in.substream = substream;
- return i2sbus_pcm_open(i2sdev, 1);
-}
-
-static int i2sbus_record_close(struct snd_pcm_substream *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
- int err;
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->in.substream != substream)
- return -EINVAL;
- err = i2sbus_pcm_close(i2sdev, 1);
- if (!err)
- i2sdev->in.substream = NULL;
- return err;
-}
-
-static int i2sbus_record_prepare(struct snd_pcm_substream *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->in.substream != substream)
- return -EINVAL;
- return i2sbus_pcm_prepare(i2sdev, 1);
-}
-
-static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->in.substream != substream)
- return -EINVAL;
- return i2sbus_pcm_trigger(i2sdev, 1, cmd);
-}
-
-static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
- *substream)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
-
- if (!i2sdev)
- return -EINVAL;
- if (i2sdev->in.substream != substream)
- return 0;
- return i2sbus_pcm_pointer(i2sdev, 1);
-}
-
-static struct snd_pcm_ops i2sbus_record_ops = {
- .open = i2sbus_record_open,
- .close = i2sbus_record_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = i2sbus_hw_params,
- .hw_free = i2sbus_record_hw_free,
- .prepare = i2sbus_record_prepare,
- .trigger = i2sbus_record_trigger,
- .pointer = i2sbus_record_pointer,
-};
-
-static void i2sbus_private_free(struct snd_pcm *pcm)
-{
- struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm);
- struct codec_info_item *p, *tmp;
-
- i2sdev->sound.pcm = NULL;
- i2sdev->out.created = 0;
- i2sdev->in.created = 0;
- list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) {
- printk(KERN_ERR "i2sbus: a codec didn't unregister!\n");
- list_del(&p->list);
- module_put(p->codec->owner);
- kfree(p);
- }
- soundbus_dev_put(&i2sdev->sound);
- module_put(THIS_MODULE);
-}
-
-int
-i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
- struct codec_info *ci, void *data)
-{
- int err, in = 0, out = 0;
- struct transfer_info *tmp;
- struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev);
- struct codec_info_item *cii;
-
- if (!dev->pcmname || dev->pcmid == -1) {
- printk(KERN_ERR "i2sbus: pcm name and id must be set!\n");
- return -EINVAL;
- }
-
- list_for_each_entry(cii, &dev->codec_list, list) {
- if (cii->codec_data == data)
- return -EALREADY;
- }
-
- if (!ci->transfers || !ci->transfers->formats
- || !ci->transfers->rates || !ci->usable)
- return -EINVAL;
-
- /* we currently code the i2s transfer on the clock, and support only
- * 32 and 64 */
- if (ci->bus_factor != 32 && ci->bus_factor != 64)
- return -EINVAL;
-
- /* If you want to fix this, you need to keep track of what transport infos
- * are to be used, which codecs they belong to, and then fix all the
- * sysclock/busclock stuff above to depend on which is usable */
- list_for_each_entry(cii, &dev->codec_list, list) {
- if (cii->codec->sysclock_factor != ci->sysclock_factor) {
- printk(KERN_DEBUG
- "cannot yet handle multiple different sysclocks!\n");
- return -EINVAL;
- }
- if (cii->codec->bus_factor != ci->bus_factor) {
- printk(KERN_DEBUG
- "cannot yet handle multiple different bus clocks!\n");
- return -EINVAL;
- }
- }
-
- tmp = ci->transfers;
- while (tmp->formats && tmp->rates) {
- if (tmp->transfer_in)
- in = 1;
- else
- out = 1;
- tmp++;
- }
-
- cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL);
- if (!cii) {
- printk(KERN_DEBUG "i2sbus: failed to allocate cii\n");
- return -ENOMEM;
- }
-
- /* use the private data to point to the codec info */
- cii->sdev = soundbus_dev_get(dev);
- cii->codec = ci;
- cii->codec_data = data;
-
- if (!cii->sdev) {
- printk(KERN_DEBUG
- "i2sbus: failed to get soundbus dev reference\n");
- err = -ENODEV;
- goto out_free_cii;
- }
-
- if (!try_module_get(THIS_MODULE)) {
- printk(KERN_DEBUG "i2sbus: failed to get module reference!\n");
- err = -EBUSY;
- goto out_put_sdev;
- }
-
- if (!try_module_get(ci->owner)) {
- printk(KERN_DEBUG
- "i2sbus: failed to get module reference to codec owner!\n");
- err = -EBUSY;
- goto out_put_this_module;
- }
-
- if (!dev->pcm) {
- err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0,
- &dev->pcm);
- if (err) {
- printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
- goto out_put_ci_module;
- }
- dev->pcm->dev = &dev->ofdev.dev;
- }
-
- /* ALSA yet again sucks.
- * If it is ever fixed, remove this line. See below. */
- out = in = 1;
-
- if (!i2sdev->out.created && out) {
- if (dev->pcm->card != card) {
- /* eh? */
- printk(KERN_ERR
- "Can't attach same bus to different cards!\n");
- err = -EINVAL;
- goto out_put_ci_module;
- }
- err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
- if (err)
- goto out_put_ci_module;
- snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &i2sbus_playback_ops);
- i2sdev->out.created = 1;
- }
-
- if (!i2sdev->in.created && in) {
- if (dev->pcm->card != card) {
- printk(KERN_ERR
- "Can't attach same bus to different cards!\n");
- err = -EINVAL;
- goto out_put_ci_module;
- }
- err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
- if (err)
- goto out_put_ci_module;
- snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
- &i2sbus_record_ops);
- i2sdev->in.created = 1;
- }
-
- /* so we have to register the pcm after adding any substream
- * to it because alsa doesn't create the devices for the
- * substreams when we add them later.
- * Therefore, force in and out on both busses (above) and
- * register the pcm now instead of just after creating it.
- */
- err = snd_device_register(card, dev->pcm);
- if (err) {
- printk(KERN_ERR "i2sbus: error registering new pcm\n");
- goto out_put_ci_module;
- }
- /* no errors any more, so let's add this to our list */
- list_add(&cii->list, &dev->codec_list);
-
- dev->pcm->private_data = i2sdev;
- dev->pcm->private_free = i2sbus_private_free;
-
- /* well, we really should support scatter/gather DMA */
- snd_pcm_lib_preallocate_pages_for_all(
- dev->pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)),
- 64 * 1024, 64 * 1024);
-
- return 0;
- out_put_ci_module:
- module_put(ci->owner);
- out_put_this_module:
- module_put(THIS_MODULE);
- out_put_sdev:
- soundbus_dev_put(dev);
- out_free_cii:
- kfree(cii);
- return err;
-}
-
-void i2sbus_detach_codec(struct soundbus_dev *dev, void *data)
-{
- struct codec_info_item *cii = NULL, *i;
-
- list_for_each_entry(i, &dev->codec_list, list) {
- if (i->codec_data == data) {
- cii = i;
- break;
- }
- }
- if (cii) {
- list_del(&cii->list);
- module_put(cii->codec->owner);
- kfree(cii);
- }
- /* no more codecs, but still a pcm? */
- if (list_empty(&dev->codec_list) && dev->pcm) {
- /* the actual cleanup is done by the callback above! */
- snd_device_free(dev->pcm->card, dev->pcm);
- }
-}