From 4a14cf4508a77d03436f34a1f6a9bc3eee12fc08 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 10 Jul 2006 04:44:33 -0700 Subject: [PATCH] Fix snd-aoa irq conversion Use proper irq mapping interface for snd-aoa-i2sbus. Signed-off-by: Andreas Schwab Acked-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Cc: Jaroslav Kysela Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/soundbus/i2sbus/i2sbus-core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index 01c0724..4f0c17e 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -129,9 +129,6 @@ static int i2sbus_add_dev(struct macio_dev *macio, if (strncmp(np->name, "i2s-", 4)) return 0; - if (macio_irq_count(macio) != 3) - return 0; - dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); if (!dev) return 0; @@ -183,10 +180,10 @@ static int i2sbus_add_dev(struct macio_dev *macio, snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name); } for (i=0;i<3;i++) { - if (request_irq(macio_irq(macio, i), ints[i], 0, - dev->rnames[i], dev)) + 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] = macio_irq(macio, i); + dev->interrupts[i] = irq; } for (i=0;i<3;i++) { -- cgit v1.1 From f9d08de57b0beb6623a89d8a8f501040c5eadacb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:34 -0700 Subject: [PATCH] aoa: i2sbus: move module parameter declaration up This patch moves the i2sbus 'force' module parameter declaration to the top of the file. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/soundbus/i2sbus/i2sbus-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index 4f0c17e..8227dbb 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -24,6 +24,11 @@ MODULE_DESCRIPTION("Apple Soundbus: I2S support"); * string that macio puts into the relevant device */ MODULE_ALIAS("of:Ni2sTi2sC"); +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" }, { } @@ -101,11 +106,6 @@ static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs) return IRQ_HANDLED; } -static int force; -module_param(force, int, 0444); -MODULE_PARM_DESC(force, "Force loading i2sbus even when" - " no layout-id property is present"); - /* FIXME: look at device node refcounting */ static int i2sbus_add_dev(struct macio_dev *macio, struct i2sbus_control *control, -- cgit v1.1 From 389ba79582b9bc2463b44ad60df62d709ebcdf97 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:34 -0700 Subject: [PATCH] aoa: i2sbus: fix for PowerMac7,2 and 7,3 This patch cleans up the resource handling in i2sbus and adds workarounds for the broken device trees on the PowerMac7,2 and 7,3. Some of this code will later move again when macio_asic is going to export all the sub-nodes too. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/soundbus/i2sbus/i2sbus-core.c | 112 ++++++++++++++++++++++++++------ sound/aoa/soundbus/i2sbus/i2sbus.h | 6 ++ 2 files changed, 97 insertions(+), 21 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index 8227dbb..23190aa 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c @@ -7,13 +7,16 @@ */ #include -#include -#include #include #include +#include + #include #include -#include + +#include +#include + #include "../soundbus.h" #include "i2sbus.h" @@ -78,12 +81,12 @@ static void i2sbus_release_dev(struct device *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=0;i<3;i++) + 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=0;i<3;i++) + 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); @@ -106,6 +109,50 @@ static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs) 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; + 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 = (u32 *)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, @@ -113,7 +160,8 @@ static int i2sbus_add_dev(struct macio_dev *macio, { struct i2sbus_dev *dev; struct device_node *child = NULL, *sound = NULL; - int i; + struct resource *r; + int i, layout = 0, rlen; static const char *rnames[] = { "i2sbus: %s (control)", "i2sbus: %s (tx)", "i2sbus: %s (rx)" }; @@ -144,8 +192,9 @@ static int i2sbus_add_dev(struct macio_dev *macio, u32 *layout_id; layout_id = (u32*) get_property(sound, "layout-id", NULL); if (layout_id) { + layout = *layout_id; snprintf(dev->sound.modalias, 32, - "sound-layout-%d", *layout_id); + "sound-layout-%d", layout); force = 1; } } @@ -175,23 +224,32 @@ static int i2sbus_add_dev(struct macio_dev *macio, dev->bus_number = np->name[4] - 'a'; INIT_LIST_HEAD(&dev->sound.codec_list); - for (i=0;i<3;i++) { + 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); + snprintf(dev->rnames[i], sizeof(dev->rnames[i]), + rnames[i], np->name); } - for (i=0;i<3;i++) { + 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; } - for (i=0;i<3;i++) { - if (of_address_to_resource(np, i, &dev->resources[i])) + + /* 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]... + /* If only we could use our resource dev->resources[i]... * but request_resource doesn't know about parents and - * contained resources... */ + * contained resources... + */ dev->allocated_resource[i] = request_mem_region(dev->resources[i].start, dev->resources[i].end - @@ -202,13 +260,25 @@ static int i2sbus_add_dev(struct macio_dev *macio, goto err; } } - /* should do sanity checking here about length of them */ - dev->intfregs = ioremap(dev->resources[0].start, - dev->resources[0].end-dev->resources[0].start+1); - dev->out.dbdma = ioremap(dev->resources[1].start, - dev->resources[1].end-dev->resources[1].start+1); - dev->in.dbdma = ioremap(dev->resources[2].start, - dev->resources[2].end-dev->resources[2].start+1); + + r = &dev->resources[aoa_resource_i2smmio]; + rlen = r->end - r->start + 1; + if (rlen < sizeof(struct i2s_interface_regs)) + goto err; + dev->intfregs = ioremap(r->start, rlen); + + r = &dev->resources[aoa_resource_txdbdma]; + rlen = r->end - r->start + 1; + if (rlen < sizeof(struct dbdma_regs)) + goto err; + dev->out.dbdma = ioremap(r->start, rlen); + + r = &dev->resources[aoa_resource_rxdbdma]; + rlen = r->end - r->start + 1; + 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; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index cfa5162..d32f8a9 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -45,6 +45,12 @@ struct pcm_info { volatile struct dbdma_regs __iomem *dbdma; }; +enum { + aoa_resource_i2smmio = 0, + aoa_resource_txdbdma, + aoa_resource_rxdbdma, +}; + struct i2sbus_dev { struct soundbus_dev sound; struct macio_dev *macio; -- cgit v1.1 From a08bc4cb09dfea4cb1d29061d82b04338ed7c21a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:35 -0700 Subject: [PATCH] aoa: fix when all is built into the kernel This patch fixes initialisation issues when all of aoa is built into the kernel by re-ordering the link order in the Makefile and making the soundbus use subsys_initcall so it is initialised earlier. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/Makefile | 4 ++-- sound/aoa/soundbus/core.c | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/Makefile b/sound/aoa/Makefile index d8de3e7..a8c037f 100644 --- a/sound/aoa/Makefile +++ b/sound/aoa/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_SND_AOA) += core/ -obj-$(CONFIG_SND_AOA) += codecs/ -obj-$(CONFIG_SND_AOA) += fabrics/ obj-$(CONFIG_SND_AOA_SOUNDBUS) += soundbus/ +obj-$(CONFIG_SND_AOA) += fabrics/ +obj-$(CONFIG_SND_AOA) += codecs/ diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index abe84a7..47b3e37 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c @@ -194,16 +194,6 @@ static struct bus_type soundbus_bus_type = { .dev_attrs = soundbus_dev_attrs, }; -static int __init soundbus_init(void) -{ - return bus_register(&soundbus_bus_type); -} - -static void __exit soundbus_exit(void) -{ - bus_unregister(&soundbus_bus_type); -} - int soundbus_add_one(struct soundbus_dev *dev) { static int devcount; @@ -246,5 +236,15 @@ void soundbus_unregister_driver(struct soundbus_driver *drv) } EXPORT_SYMBOL_GPL(soundbus_unregister_driver); -module_init(soundbus_init); +static int __init soundbus_init(void) +{ + return bus_register(&soundbus_bus_type); +} + +static void __exit soundbus_exit(void) +{ + bus_unregister(&soundbus_bus_type); +} + +subsys_initcall(soundbus_init); module_exit(soundbus_exit); -- cgit v1.1 From 977c60238cfff1f9eb07cfd78bc02da91b7b499b Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:36 -0700 Subject: [PATCH] aoa: i2sbus: revamp control layer This patch revamps the i2sbus control layer by using the macio/keylargo functions instead of directly mapping. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/soundbus/i2sbus/i2sbus-control.c | 79 +++++++++++++++--------------- sound/aoa/soundbus/i2sbus/i2sbus-control.h | 37 -------------- sound/aoa/soundbus/i2sbus/i2sbus.h | 12 +++-- 3 files changed, 47 insertions(+), 81 deletions(-) delete mode 100644 sound/aoa/soundbus/i2sbus/i2sbus-control.h (limited to 'sound/aoa') diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/i2sbus-control.c index f504079..87beb4a 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-control.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.c @@ -6,12 +6,16 @@ * GPL v2, can be found in COPYING. */ -#include +#include #include + +#include #include #include #include #include +#include + #include "i2sbus.h" int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) @@ -22,26 +26,12 @@ int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) INIT_LIST_HEAD(&(*c)->list); - if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc)) - goto err; - /* we really should be using feature calls instead of mapping - * these registers. It's safe for now since no one else is - * touching them... */ - (*c)->controlregs = ioremap((*c)->rsrc.start, - sizeof(struct i2s_control_regs)); - if (!(*c)->controlregs) - goto err; - + (*c)->macio = dev->bus->chip; return 0; - err: - kfree(*c); - *c = NULL; - return -ENODEV; } void i2sbus_control_destroy(struct i2sbus_control *c) { - iounmap(c->controlregs); kfree(c); } @@ -93,19 +83,22 @@ int i2sbus_control_enable(struct i2sbus_control *c, struct i2sbus_dev *i2sdev) { struct pmf_args args = { .count = 0 }; - int cc; + 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: - cc = in_le32(&c->controlregs->cell_control); - out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE); + /* these need to be locked or done through + * newly created feature calls! */ + MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE); break; case 1: - cc = in_le32(&c->controlregs->cell_control); - out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE); + MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_ENABLE); break; default: return -ENODEV; @@ -118,7 +111,7 @@ int i2sbus_control_cell(struct i2sbus_control *c, int enable) { struct pmf_args args = { .count = 0 }; - int cc; + struct macio_chip *macio = c->macio; switch (enable) { case 0: @@ -133,18 +126,22 @@ int i2sbus_control_cell(struct i2sbus_control *c, 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: - cc = in_le32(&c->controlregs->cell_control); - cc &= ~CTRL_CLOCK_CELL_0_ENABLE; - cc |= enable * CTRL_CLOCK_CELL_0_ENABLE; - out_le32(&c->controlregs->cell_control, cc); + if (enable) + MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); + else + MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); break; case 1: - cc = in_le32(&c->controlregs->cell_control); - cc &= ~CTRL_CLOCK_CELL_1_ENABLE; - cc |= enable * CTRL_CLOCK_CELL_1_ENABLE; - out_le32(&c->controlregs->cell_control, cc); + if (enable) + MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); + else + MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); break; default: return -ENODEV; @@ -157,7 +154,7 @@ int i2sbus_control_clock(struct i2sbus_control *c, int enable) { struct pmf_args args = { .count = 0 }; - int cc; + struct macio_chip *macio = c->macio; switch (enable) { case 0: @@ -172,18 +169,22 @@ int i2sbus_control_clock(struct i2sbus_control *c, 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: - cc = in_le32(&c->controlregs->cell_control); - cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE; - cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE; - out_le32(&c->controlregs->cell_control, cc); + if (enable) + MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); + else + MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); break; case 1: - cc = in_le32(&c->controlregs->cell_control); - cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE; - cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE; - out_le32(&c->controlregs->cell_control, cc); + 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; diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.h b/sound/aoa/soundbus/i2sbus/i2sbus-control.h deleted file mode 100644 index bb05550..0000000 --- a/sound/aoa/soundbus/i2sbus/i2sbus-control.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * i2sbus driver -- bus register definitions - * - * Copyright 2006 Johannes Berg - * - * GPL v2, can be found in COPYING. - */ -#ifndef __I2SBUS_CONTROLREGS_H -#define __I2SBUS_CONTROLREGS_H - -/* i2s 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_control_regs { - PAD(0x38); - __le32 fcr0; /* 0x38 (unknown) */ - __le32 cell_control; /* 0x3c (fcr1) */ - __le32 fcr2; /* 0x40 (unknown) */ - __le32 fcr3; /* 0x44 (fcr3) */ - __le32 clock_control; /* 0x48 (unknown) */ - PAD(4); - /* total size: 0x50 bytes */ -} __attribute__((__packed__)); - -#define CTRL_CLOCK_CELL_0_ENABLE (1<<10) -#define CTRL_CLOCK_CLOCK_0_ENABLE (1<<12) -#define CTRL_CLOCK_SWRESET_0 (1<<11) -#define CTRL_CLOCK_INTF_0_ENABLE (1<<13) - -#define CTRL_CLOCK_CELL_1_ENABLE (1<<17) -#define CTRL_CLOCK_CLOCK_1_ENABLE (1<<18) -#define CTRL_CLOCK_SWRESET_1 (1<<19) -#define CTRL_CLOCK_INTF_1_ENABLE (1<<20) - -#endif /* __I2SBUS_CONTROLREGS_H */ diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index d32f8a9..0c69d20 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -7,20 +7,22 @@ */ #ifndef __I2SBUS_H #define __I2SBUS_H -#include #include -#include #include #include + +#include + #include +#include +#include + #include "i2sbus-interface.h" -#include "i2sbus-control.h" #include "../soundbus.h" struct i2sbus_control { - volatile struct i2s_control_regs __iomem *controlregs; - struct resource rsrc; struct list_head list; + struct macio_chip *macio; }; #define MAX_DBDMA_COMMANDS 32 -- cgit v1.1 From e53fcabc6d923e9c1cdd073ea2e2212daf907622 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:37 -0700 Subject: [PATCH] aoa: pmf gpio: report if function calling fails This patch makes the pmf GPIO layer in aoa report if calling a platform function failed. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/core/snd-aoa-gpio-pmf.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c index 0e9b9bb..3d57fd1 100644 --- a/sound/aoa/core/snd-aoa-gpio-pmf.c +++ b/sound/aoa/core/snd-aoa-gpio-pmf.c @@ -14,9 +14,13 @@ static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\ { \ struct pmf_args args = { .count = 1, .u[0].v = !on }; \ - \ + int rc; \ + \ if (unlikely(!rt)) return; \ - pmf_call_function(rt->node, #name "-mute", &args); \ + rc = pmf_call_function(rt->node, #name "-mute", &args); \ + if (rc) \ + printk(KERN_WARNING "pmf_gpio_set_" #name \ + " failed, rc: %d\n", rc); \ rt->implementation_private &= ~(1<implementation_private |= (!!on << bit); \ } \ @@ -33,9 +37,13 @@ PMF_GPIO(lineout, 2); static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on) { struct pmf_args args = { .count = 1, .u[0].v = !!on }; + int rc; if (unlikely(!rt)) return; - pmf_call_function(rt->node, "hw-reset", &args); + rc = pmf_call_function(rt->node, "hw-reset", &args); + if (rc) + printk(KERN_WARNING "pmf_gpio_set_hw_reset" + " failed, rc: %d\n", rc); } static void pmf_gpio_all_amps_off(struct gpio_runtime *rt) -- cgit v1.1 From a677c8fb8aa03e6ad9c206cb7284d294761ced2c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:37 -0700 Subject: [PATCH] aoa fabric layout: clean up messages This patch cleans up the printk's in the layout fabric and also makes it display which type of GPIO access it is going to use. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/fabrics/snd-aoa-fabric-layout.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index cbc8a3b..94cac71 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -950,11 +950,12 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) layout_id = (unsigned int *) get_property(sound, "layout-id", NULL); if (!layout_id) goto outnodev; - printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d ", *layout_id); + printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n", + *layout_id); layout = find_layout_by_id(*layout_id); if (!layout) { - printk("(no idea how to handle)\n"); + printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n"); goto outnodev; } @@ -972,15 +973,17 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) case 51: /* PowerBook5,4 */ case 58: /* Mac Mini */ ldev->gpio.methods = ftr_gpio_methods; + printk(KERN_DEBUG + "snd-aoa-fabric-layout: Using direct GPIOs\n"); break; default: ldev->gpio.methods = pmf_gpio_methods; + printk(KERN_DEBUG + "snd-aoa-fabric-layout: Using PMF GPIOs\n"); } ldev->selfptr_headphone.ptr = ldev; ldev->selfptr_lineout.ptr = ldev; sdev->ofdev.dev.driver_data = ldev; - - printk("(using)\n"); list_add(&ldev->list, &layouts_list); layouts_list_items++; -- cgit v1.1 From 14b42963f64b98ab61fa9723c03d71aa5ef4f862 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Jul 2006 04:44:38 -0700 Subject: [PATCH] aoa: tas: change PCM1 name to PCM This patch changes the PCM1 control name to PCM to make it play nice with the softvol plugin (which will then go away if it sees a proper PCM slider) Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/codecs/snd-aoa-codec-tas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/aoa') diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 2e39ff6..27c1e2e 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -309,7 +309,7 @@ static struct snd_kcontrol_new n##_control = { \ .private_value = idx, \ } -MIXER_CONTROL(pcm1, "PCM1", 0); +MIXER_CONTROL(pcm1, "PCM", 0); MIXER_CONTROL(monitor, "Monitor", 2); static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol, -- cgit v1.1 From 6a4f57874538fc05b99bd3bf7106f3df9b23a4ab Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 10 Jul 2006 04:44:39 -0700 Subject: [PATCH] aoa: tas: fix initialisation/reset This patch fixes the initialisation and reset of the tas codec. The tas will often reset if the i2s clocks go away so it needs to be completely re-initialised when clocks come back. Also, this patch adds some code for DRC that will be exploited later to add a DRC control again, fixing a regression over snd-powermac. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/codecs/snd-aoa-codec-tas.c | 126 ++++++++++++++++++++++++++++------- sound/aoa/codecs/snd-aoa-codec-tas.h | 8 +++ 2 files changed, 110 insertions(+), 24 deletions(-) (limited to 'sound/aoa') diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 27c1e2e..23643b3 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -75,19 +75,24 @@ MODULE_DESCRIPTION("tas codec driver for snd-aoa"); #include "../aoa.h" #include "../soundbus/soundbus.h" - #define PFX "snd-aoa-codec-tas: " + struct tas { struct aoa_codec codec; struct i2c_client i2c; - u32 muted_l:1, muted_r:1, - controls_created:1; + u32 mute_l:1, mute_r:1 , + controls_created:1 , + drc_enabled:1, + hw_enabled:1; u8 cached_volume_l, cached_volume_r; u8 mixer_l[3], mixer_r[3]; u8 acr; + int drc_range; }; +static int tas_reset_init(struct tas *tas); + static struct tas *codec_to_tas(struct aoa_codec *codec) { return container_of(codec, struct tas, codec); @@ -101,6 +106,28 @@ static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data) return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data); } +static void tas3004_set_drc(struct tas *tas) +{ + unsigned char val[6]; + + if (tas->drc_enabled) + val[0] = 0x50; /* 3:1 above threshold */ + else + val[0] = 0x51; /* disabled */ + val[1] = 0x02; /* 1:1 below threshold */ + if (tas->drc_range > 0xef) + val[2] = 0xef; + else if (tas->drc_range < 0) + val[2] = 0x00; + else + val[2] = tas->drc_range; + val[3] = 0xb0; + val[4] = 0x60; + val[5] = 0xa0; + + tas_write_reg(tas, TAS_REG_DRC, 6, val); +} + static void tas_set_volume(struct tas *tas) { u8 block[6]; @@ -113,8 +140,8 @@ static void tas_set_volume(struct tas *tas) if (left > 177) left = 177; if (right > 177) right = 177; - if (tas->muted_l) left = 0; - if (tas->muted_r) right = 0; + if (tas->mute_l) left = 0; + if (tas->mute_r) right = 0; /* analysing the volume and mixer tables shows * that they are similar enough when we shift @@ -202,7 +229,8 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, tas->cached_volume_l = ucontrol->value.integer.value[0]; tas->cached_volume_r = ucontrol->value.integer.value[1]; - tas_set_volume(tas); + if (tas->hw_enabled) + tas_set_volume(tas); return 1; } @@ -230,8 +258,8 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = !tas->muted_l; - ucontrol->value.integer.value[1] = !tas->muted_r; + ucontrol->value.integer.value[0] = !tas->mute_l; + ucontrol->value.integer.value[1] = !tas->mute_r; return 0; } @@ -240,13 +268,14 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, { struct tas *tas = snd_kcontrol_chip(kcontrol); - if (tas->muted_l == !ucontrol->value.integer.value[0] - && tas->muted_r == !ucontrol->value.integer.value[1]) + if (tas->mute_l == !ucontrol->value.integer.value[0] + && tas->mute_r == !ucontrol->value.integer.value[1]) return 0; - tas->muted_l = !ucontrol->value.integer.value[0]; - tas->muted_r = !ucontrol->value.integer.value[1]; - tas_set_volume(tas); + tas->mute_l = !ucontrol->value.integer.value[0]; + tas->mute_r = !ucontrol->value.integer.value[1]; + if (tas->hw_enabled) + tas_set_volume(tas); return 1; } @@ -294,7 +323,8 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, tas->mixer_l[idx] = ucontrol->value.integer.value[0]; tas->mixer_r[idx] = ucontrol->value.integer.value[1]; - tas_set_mixer(tas); + if (tas->hw_enabled) + tas_set_mixer(tas); return 1; } @@ -346,7 +376,8 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, tas->acr |= TAS_ACR_INPUT_B; if (oldacr == tas->acr) return 0; - tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); + if (tas->hw_enabled) + tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); return 1; } @@ -399,26 +430,66 @@ static int tas_usable(struct codec_info_item *cii, static int tas_reset_init(struct tas *tas) { u8 tmp; + + tas->codec.gpio->methods->all_amps_off(tas->codec.gpio); + msleep(5); tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); - msleep(1); + msleep(5); tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1); - msleep(1); + msleep(20); tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); - msleep(1); - - tas->acr &= ~TAS_ACR_ANALOG_PDOWN; - tas->acr |= TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT; - if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) - return -ENODEV; + msleep(10); + tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) return -ENODEV; + tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | + TAS_ACR_B_MON_SEL_RIGHT; + if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) + return -ENODEV; + tmp = 0; if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) return -ENODEV; + tas3004_set_drc(tas); + + /* Set treble & bass to 0dB */ + tmp = 114; + tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp); + tas_write_reg(tas, TAS_REG_BASS, 1, &tmp); + + tas->acr &= ~TAS_ACR_ANALOG_PDOWN; + if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) + return -ENODEV; + + return 0; +} + +static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) +{ + struct tas *tas = cii->codec_data; + + switch(clock) { + case CLOCK_SWITCH_PREPARE_SLAVE: + /* Clocks are going away, mute mute mute */ + tas->codec.gpio->methods->all_amps_off(tas->codec.gpio); + tas->hw_enabled = 0; + break; + case CLOCK_SWITCH_SLAVE: + /* Clocks are back, re-init the codec */ + tas_reset_init(tas); + tas_set_volume(tas); + tas_set_mixer(tas); + tas->hw_enabled = 1; + tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); + break; + default: + /* doesn't happen as of now */ + return -EINVAL; + } return 0; } @@ -427,6 +498,7 @@ static int tas_reset_init(struct tas *tas) * our i2c device is suspended, and then take note of that! */ static int tas_suspend(struct tas *tas) { + tas->hw_enabled = 0; tas->acr |= TAS_ACR_ANALOG_PDOWN; tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); return 0; @@ -438,6 +510,7 @@ static int tas_resume(struct tas *tas) tas_reset_init(tas); tas_set_volume(tas); tas_set_mixer(tas); + tas->hw_enabled = 1; return 0; } @@ -463,6 +536,7 @@ static struct codec_info tas_codec_info = { .bus_factor = 64, .owner = THIS_MODULE, .usable = tas_usable, + .switch_clock = tas_switch_clock, #ifdef CONFIG_PM .suspend = _tas_suspend, .resume = _tas_resume, @@ -483,6 +557,7 @@ static int tas_init_codec(struct aoa_codec *codec) printk(KERN_ERR PFX "tas failed to initialise\n"); return -ENXIO; } + tas->hw_enabled = 1; if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, aoa_get_card(), @@ -548,6 +623,7 @@ static int tas_create(struct i2c_adapter *adapter, tas->i2c.driver = &tas_driver; tas->i2c.adapter = adapter; tas->i2c.addr = addr; + tas->drc_range = TAS3004_DRC_MAX; strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1); if (i2c_attach_client(&tas->i2c)) { @@ -564,7 +640,9 @@ static int tas_create(struct i2c_adapter *adapter, if (aoa_codec_register(&tas->codec)) { goto detach; } - printk(KERN_DEBUG "snd-aoa-codec-tas: created and attached tas instance\n"); + printk(KERN_DEBUG + "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n", + addr, node->full_name); return 0; detach: i2c_detach_client(&tas->i2c); diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/snd-aoa-codec-tas.h index daf81f4..ae177e3 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.h +++ b/sound/aoa/codecs/snd-aoa-codec-tas.h @@ -44,4 +44,12 @@ #define TAS_REG_LEFT_BIQUAD6 0x10 #define TAS_REG_RIGHT_BIQUAD6 0x19 +#define TAS_REG_LEFT_LOUDNESS 0x21 +#define TAS_REG_RIGHT_LOUDNESS 0x22 +#define TAS_REG_LEFT_LOUDNESS_GAIN 0x23 +#define TAS_REG_RIGHT_LOUDNESS_GAIN 0x24 + +#define TAS3001_DRC_MAX 0x5f +#define TAS3004_DRC_MAX 0xef + #endif /* __SND_AOA_CODECTASH */ -- cgit v1.1 From 9b8f52f5b93e08f04b08e64e62d675bc43dd618e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Jul 2006 04:44:39 -0700 Subject: [PATCH] aoa: tas: surface DRC control again This patch makes the DRC control visible again for TAS chips. Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/codecs/snd-aoa-codec-tas.c | 95 +++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) (limited to 'sound/aoa') diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 23643b3..009f575 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -342,6 +342,90 @@ static struct snd_kcontrol_new n##_control = { \ MIXER_CONTROL(pcm1, "PCM", 0); MIXER_CONTROL(monitor, "Monitor", 2); +static int tas_snd_drc_range_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = TAS3004_DRC_MAX; + return 0; +} + +static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas->drc_range; + return 0; +} + +static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + if (tas->drc_range == ucontrol->value.integer.value[0]) + return 0; + + tas->drc_range = ucontrol->value.integer.value[0]; + if (tas->hw_enabled) + tas3004_set_drc(tas); + return 1; +} + +static struct snd_kcontrol_new drc_range_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DRC Range", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = tas_snd_drc_range_info, + .get = tas_snd_drc_range_get, + .put = tas_snd_drc_range_put, +}; + +static int tas_snd_drc_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas->drc_enabled; + return 0; +} + +static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + if (tas->drc_enabled == ucontrol->value.integer.value[0]) + return 0; + + tas->drc_enabled = ucontrol->value.integer.value[0]; + if (tas->hw_enabled) + tas3004_set_drc(tas); + return 1; +} + +static struct snd_kcontrol_new drc_switch_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DRC Range Switch", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = tas_snd_drc_switch_info, + .get = tas_snd_drc_switch_get, + .put = tas_snd_drc_switch_put, +}; + static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -590,6 +674,14 @@ static int tas_init_codec(struct aoa_codec *codec) if (err) goto error; + err = aoa_snd_ctl_add(snd_ctl_new1(&drc_range_control, tas)); + if (err) + goto error; + + err = aoa_snd_ctl_add(snd_ctl_new1(&drc_switch_control, tas)); + if (err) + goto error; + return 0; error: tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); @@ -623,7 +715,8 @@ static int tas_create(struct i2c_adapter *adapter, tas->i2c.driver = &tas_driver; tas->i2c.adapter = adapter; tas->i2c.addr = addr; - tas->drc_range = TAS3004_DRC_MAX; + /* seems that half is a saner default */ + tas->drc_range = TAS3004_DRC_MAX / 2; strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1); if (i2c_attach_client(&tas->i2c)) { -- cgit v1.1 From 3e5102ad70aaafe49823a02b368c0c3032c91439 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Jul 2006 04:44:40 -0700 Subject: [PATCH] aoa: layout fabric: add missing module aliases The layout fabric gained support for all IDs when I extracted those from the OSX description file. But apparently I had forgotten to add them all as module aliases so the module will also load. This patch adds them. Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/fabrics/snd-aoa-fabric-layout.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound/aoa') diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 94cac71..172eb95 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -77,24 +77,39 @@ struct layout { int pcmid; }; +MODULE_ALIAS("sound-layout-36"); MODULE_ALIAS("sound-layout-41"); MODULE_ALIAS("sound-layout-45"); +MODULE_ALIAS("sound-layout-47"); +MODULE_ALIAS("sound-layout-48"); +MODULE_ALIAS("sound-layout-49"); +MODULE_ALIAS("sound-layout-50"); MODULE_ALIAS("sound-layout-51"); +MODULE_ALIAS("sound-layout-56"); +MODULE_ALIAS("sound-layout-57"); MODULE_ALIAS("sound-layout-58"); MODULE_ALIAS("sound-layout-60"); MODULE_ALIAS("sound-layout-61"); +MODULE_ALIAS("sound-layout-62"); MODULE_ALIAS("sound-layout-64"); MODULE_ALIAS("sound-layout-65"); +MODULE_ALIAS("sound-layout-66"); +MODULE_ALIAS("sound-layout-67"); MODULE_ALIAS("sound-layout-68"); MODULE_ALIAS("sound-layout-69"); MODULE_ALIAS("sound-layout-70"); MODULE_ALIAS("sound-layout-72"); +MODULE_ALIAS("sound-layout-76"); MODULE_ALIAS("sound-layout-80"); MODULE_ALIAS("sound-layout-82"); MODULE_ALIAS("sound-layout-84"); MODULE_ALIAS("sound-layout-86"); +MODULE_ALIAS("sound-layout-90"); MODULE_ALIAS("sound-layout-92"); +MODULE_ALIAS("sound-layout-94"); MODULE_ALIAS("sound-layout-96"); +MODULE_ALIAS("sound-layout-98"); +MODULE_ALIAS("sound-layout-100"); /* onyx with all but microphone connected */ static struct codec_connection onyx_connections_nomic[] = { -- cgit v1.1 From 50099328e4fe7c9f8981f408071a1ff82d59ddf8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Jul 2006 04:44:41 -0700 Subject: [PATCH] aoa: tas: add missing bass/treble controls This patch adds the bass/treble controls to snd-aoa that snd-powermac always had for tas3004 based machines. Signed-off-by: Johannes Berg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h | 134 ++++++++++++++++++++++++ sound/aoa/codecs/snd-aoa-codec-tas.c | 116 +++++++++++++++++++- 2 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h (limited to 'sound/aoa') diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h b/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h new file mode 100644 index 0000000..69b6113 --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h @@ -0,0 +1,134 @@ +/* + * This file is only included exactly once! + * + * The tables here are derived from the tas3004 datasheet, + * modulo typo corrections and some smoothing... + */ + +#define TAS3004_TREBLE_MIN 0 +#define TAS3004_TREBLE_MAX 72 +#define TAS3004_BASS_MIN 0 +#define TAS3004_BASS_MAX 72 +#define TAS3004_TREBLE_ZERO 36 +#define TAS3004_BASS_ZERO 36 + +static u8 tas3004_treble_table[] = { + 150, /* -18 dB */ + 149, + 148, + 147, + 146, + 145, + 144, + 143, + 142, + 141, + 140, + 139, + 138, + 137, + 136, + 135, + 134, + 133, + 132, + 131, + 130, + 129, + 128, + 127, + 126, + 125, + 124, + 123, + 122, + 121, + 120, + 119, + 118, + 117, + 116, + 115, + 114, /* 0 dB */ + 113, + 112, + 111, + 109, + 108, + 107, + 105, + 104, + 103, + 101, + 99, + 98, + 96, + 93, + 91, + 89, + 86, + 83, + 81, + 77, + 74, + 71, + 67, + 63, + 59, + 54, + 49, + 44, + 38, + 32, + 26, + 19, + 10, + 4, + 2, + 1, /* +18 dB */ +}; + +static inline u8 tas3004_treble(int idx) +{ + return tas3004_treble_table[idx]; +} + +/* I only save the difference here to the treble table + * so that the binary is smaller... + * I have also ignored completely differences of + * +/- 1 + */ +static s8 tas3004_bass_diff_to_treble[] = { + 2, /* 7 dB, offset 50 */ + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 3, + 4, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 14, + 13, + 8, + 1, /* 18 dB */ +}; + +static inline u8 tas3004_bass(int idx) +{ + u8 result = tas3004_treble_table[idx]; + + if (idx >= 50) + result += tas3004_bass_diff_to_treble[idx-50]; + return result; +} diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 009f575..16c0b6b 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -72,6 +72,7 @@ MODULE_DESCRIPTION("tas codec driver for snd-aoa"); #include "snd-aoa-codec-tas.h" #include "snd-aoa-codec-tas-gain-table.h" +#include "snd-aoa-codec-tas-basstreble.h" #include "../aoa.h" #include "../soundbus/soundbus.h" @@ -87,6 +88,7 @@ struct tas { hw_enabled:1; u8 cached_volume_l, cached_volume_r; u8 mixer_l[3], mixer_r[3]; + u8 bass, treble; u8 acr; int drc_range; }; @@ -128,6 +130,22 @@ static void tas3004_set_drc(struct tas *tas) tas_write_reg(tas, TAS_REG_DRC, 6, val); } +static void tas_set_treble(struct tas *tas) +{ + u8 tmp; + + tmp = tas3004_treble(tas->treble); + tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp); +} + +static void tas_set_bass(struct tas *tas) +{ + u8 tmp; + + tmp = tas3004_bass(tas->bass); + tas_write_reg(tas, TAS_REG_BASS, 1, &tmp); +} + static void tas_set_volume(struct tas *tas) { u8 block[6]; @@ -485,6 +503,89 @@ static struct snd_kcontrol_new capture_source_control = { .put = tas_snd_capture_source_put, }; +static int tas_snd_treble_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = TAS3004_TREBLE_MIN; + uinfo->value.integer.max = TAS3004_TREBLE_MAX; + return 0; +} + +static int tas_snd_treble_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas->treble; + return 0; +} + +static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + if (tas->treble == ucontrol->value.integer.value[0]) + return 0; + + tas->treble = ucontrol->value.integer.value[0]; + if (tas->hw_enabled) + tas_set_treble(tas); + return 1; +} + +static struct snd_kcontrol_new treble_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Treble", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = tas_snd_treble_info, + .get = tas_snd_treble_get, + .put = tas_snd_treble_put, +}; + +static int tas_snd_bass_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = TAS3004_BASS_MIN; + uinfo->value.integer.max = TAS3004_BASS_MAX; + return 0; +} + +static int tas_snd_bass_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = tas->bass; + return 0; +} + +static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tas *tas = snd_kcontrol_chip(kcontrol); + + if (tas->bass == ucontrol->value.integer.value[0]) + return 0; + + tas->bass = ucontrol->value.integer.value[0]; + if (tas->hw_enabled) + tas_set_bass(tas); + return 1; +} + +static struct snd_kcontrol_new bass_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Bass", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = tas_snd_bass_info, + .get = tas_snd_bass_get, + .put = tas_snd_bass_put, +}; static struct transfer_info tas_transfers[] = { { @@ -541,9 +642,10 @@ static int tas_reset_init(struct tas *tas) tas3004_set_drc(tas); /* Set treble & bass to 0dB */ - tmp = 114; - tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp); - tas_write_reg(tas, TAS_REG_BASS, 1, &tmp); + tas->treble = TAS3004_TREBLE_ZERO; + tas->bass = TAS3004_BASS_ZERO; + tas_set_treble(tas); + tas_set_bass(tas); tas->acr &= ~TAS_ACR_ANALOG_PDOWN; if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) @@ -682,6 +784,14 @@ static int tas_init_codec(struct aoa_codec *codec) if (err) goto error; + err = aoa_snd_ctl_add(snd_ctl_new1(&treble_control, tas)); + if (err) + goto error; + + err = aoa_snd_ctl_add(snd_ctl_new1(&bass_control, tas)); + if (err) + goto error; + return 0; error: tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); -- cgit v1.1