[alsa-devel] [PATCH 1/7] ASoC: neo1973_wm8753: Remove scenario management code.
It has been proven to be inflexible to do scenario management in kernel space.
Since actual neo1973 board support has not been merged in mainline and this patch has been in the neo1973 tree for some time now it should be safe to remove this functionality without breaking existing userspace.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/samsung/neo1973_wm8753.c | 148 +++--------------------------------- 1 files changed, 11 insertions(+), 137 deletions(-)
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index d3cd688..fe92946 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -37,17 +37,6 @@ #include "dma.h" #include "s3c24xx-i2s.h"
-/* define the scenarios */ -#define NEO_AUDIO_OFF 0 -#define NEO_GSM_CALL_AUDIO_HANDSET 1 -#define NEO_GSM_CALL_AUDIO_HEADSET 2 -#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3 -#define NEO_STEREO_TO_SPEAKERS 4 -#define NEO_STEREO_TO_HEADPHONES 5 -#define NEO_CAPTURE_HANDSET 6 -#define NEO_CAPTURE_HEADSET 7 -#define NEO_CAPTURE_BLUETOOTH 8 - static struct snd_soc_card neo1973; static struct i2c_client *i2c;
@@ -224,113 +213,6 @@ static struct snd_soc_ops neo1973_voice_ops = { .hw_free = neo1973_voice_hw_free, };
-static int neo1973_scenario; - -static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = neo1973_scenario; - return 0; -} - -static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - pr_debug("Entered %s\n", __func__); - - switch (neo1973_scenario) { - case NEO_AUDIO_OFF: - snd_soc_dapm_disable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - case NEO_GSM_CALL_AUDIO_HANDSET: - snd_soc_dapm_enable_pin(dapm, "Audio Out"); - snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_enable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_enable_pin(dapm, "Call Mic"); - break; - case NEO_GSM_CALL_AUDIO_HEADSET: - snd_soc_dapm_enable_pin(dapm, "Audio Out"); - snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_enable_pin(dapm, "GSM Line In"); - snd_soc_dapm_enable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - case NEO_GSM_CALL_AUDIO_BLUETOOTH: - snd_soc_dapm_disable_pin(dapm, "Audio Out"); - snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_enable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - case NEO_STEREO_TO_SPEAKERS: - snd_soc_dapm_enable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - case NEO_STEREO_TO_HEADPHONES: - snd_soc_dapm_enable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - case NEO_CAPTURE_HANDSET: - snd_soc_dapm_disable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_enable_pin(dapm, "Call Mic"); - break; - case NEO_CAPTURE_HEADSET: - snd_soc_dapm_disable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_enable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - case NEO_CAPTURE_BLUETOOTH: - snd_soc_dapm_disable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - break; - default: - snd_soc_dapm_disable_pin(dapm, "Audio Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); - } - - snd_soc_dapm_sync(dapm); - - return 0; -} - -static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - pr_debug("Entered %s\n", __func__); - - if (neo1973_scenario == ucontrol->value.integer.value[0]) - return 0; - - neo1973_scenario = ucontrol->value.integer.value[0]; - set_scenario_endpoints(codec, neo1973_scenario); - return 1; -} - static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
static void lm4857_write_regs(void) @@ -454,26 +336,16 @@ static const struct soc_enum lm4857_mode_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode), };
-static const char *neo_scenarios[] = { - "Off", - "GSM Handset", - "GSM Headset", - "GSM Bluetooth", - "Speakers", - "Headphones", - "Capture Handset", - "Capture Headset", - "Capture Bluetooth" -}; - -static const struct soc_enum neo_scenario_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), -}; - static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { + SOC_DAPM_PIN_SWITCH("Audio Out"), + SOC_DAPM_PIN_SWITCH("GSM Line Out"), + SOC_DAPM_PIN_SWITCH("GSM Line In"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Call Mic"), + SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, lm4857_get_reg, lm4857_set_reg, stereo_tlv), SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, @@ -482,8 +354,6 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { lm4857_get_reg, lm4857_set_reg, mono_tlv), SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], lm4857_get_mode, lm4857_set_mode), - SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], - neo1973_get_scenario, neo1973_set_scenario), SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0, lm4857_get_reg, lm4857_set_reg), SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0, @@ -520,7 +390,11 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) ARRAY_SIZE(wm8753_dapm_widgets));
/* set endpoints to default mode */ - set_scenario_endpoints(codec, NEO_AUDIO_OFF); + snd_soc_dapm_disable_pin(dapm, "Audio Out"); + snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); + snd_soc_dapm_disable_pin(dapm, "GSM Line In"); + snd_soc_dapm_disable_pin(dapm, "Headset Mic"); + snd_soc_dapm_disable_pin(dapm, "Call Mic");
/* add neo1973 specific controls */ err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
This patch moves the code for the lm4857 AMP from the neo1973_wm8753 sound board driver to its own module. The lm4857 is a generic AMP IC and not specific to the neo1973.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/lm4857.c | 276 ++++++++++++++++++++++++++++++++++++ sound/soc/samsung/Kconfig | 1 + sound/soc/samsung/lm4857.h | 32 ---- sound/soc/samsung/neo1973_wm8753.c | 269 +++++++++-------------------------- 6 files changed, 347 insertions(+), 236 deletions(-) create mode 100644 sound/soc/codecs/lm4857.c delete mode 100644 sound/soc/samsung/lm4857.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 82a4630..37035e6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -347,6 +347,9 @@ config SND_SOC_WM9713 tristate
# Amp +config SND_SOC_LM4857 + tristate + config SND_SOC_MAX9877 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b43f9d4..0663d22 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -77,6 +77,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-jz4740-codec-objs := jz4740.o
# Amp +snd-soc-lm4857-objs := lm4857.o snd-soc-max9877-objs := max9877.o snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-wm2000-objs := wm2000.o @@ -161,6 +162,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
# Amp +obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c new file mode 100644 index 0000000..72de47e --- /dev/null +++ b/sound/soc/codecs/lm4857.c @@ -0,0 +1,276 @@ +/* + * LM4857 AMP driver + * + * Copyright 2007 Wolfson Microelectronics PLC. + * Author: Graeme Gregory + * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * Copyright 2011 Lars-Peter Clausen lars@metafoo.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> + +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +struct lm4857 { + struct i2c_client *i2c; + uint8_t mode; +}; + +static const uint8_t lm4857_default_regs[] = { + 0x00, 0x00, 0x00, 0x00, +}; + +/* The register offsets in the cache array */ +#define LM4857_MVOL 0 +#define LM4857_LVOL 1 +#define LM4857_RVOL 2 +#define LM4857_CTRL 3 + +/* the shifts required to set these bits */ +#define LM4857_3D 5 +#define LM4857_WAKEUP 5 +#define LM4857_EPGAIN 4 + +static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + uint8_t data; + int ret; + + ret = snd_soc_cache_write(codec, reg, value); + if (ret < 0) + return ret; + + data = (reg << 6) | value; + ret = i2c_master_send(codec->control_data, &data, 1); + if (ret != 1) { + dev_err(codec->dev, "Failed to write register: %d\n", ret); + return ret; + } + + return 0; +} + +static unsigned int lm4857_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + unsigned int val; + int ret; + + ret = snd_soc_cache_read(codec, reg, &val); + if (ret) + return -1; + + return val; +} + +static int lm4857_get_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = lm4857->mode; + + return 0; +} + +static int lm4857_set_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); + uint8_t value = ucontrol->value.integer.value[0]; + + lm4857->mode = value; + + if (codec->dapm.bias_level == SND_SOC_BIAS_ON) + snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6); + + return 1; +} + +static int lm4857_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6); + break; + case SND_SOC_BIAS_STANDBY: + snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0); + break; + default: + break; + } + + codec->dapm.bias_level = level; + + return 0; +} + +static const char *lm4857_mode[] = { + "Earpiece", + "Loudspeaker", + "Loudspeaker + Headphone", + "Headphone", +}; + +static const struct soc_enum lm4857_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode); + +static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN"), + + SND_SOC_DAPM_OUTPUT("LS"), + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_OUTPUT("EP"), +}; + +static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); +static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); + +static const struct snd_kcontrol_new lm4857_controls[] = { + SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0, + stereo_tlv), + SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0, + stereo_tlv), + SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0, + mono_tlv), + SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0), + SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0), + SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL, + LM4857_WAKEUP, 1, 0), + SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, + LM4857_EPGAIN, 1, 0), + + SOC_ENUM_EXT("Mode", lm4857_mode_enum, + lm4857_get_mode, lm4857_set_mode), +}; + +/* There is a demux inbetween the the input signal and the output signals. + * Currently there is no easy way to model it in ASoC and since it does not make + * much of a difference in practice simply connect the input direclty to the + * outputs. */ +static const struct snd_soc_dapm_route lm4857_routes[] = { + {"LS", NULL, "IN"}, + {"HP", NULL, "IN"}, + {"EP", NULL, "IN"}, +}; + +static int lm4857_probe(struct snd_soc_codec *codec) +{ + struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + codec->control_data = lm4857->i2c; + + ret = snd_soc_add_controls(codec, lm4857_controls, + ARRAY_SIZE(lm4857_controls)); + if (ret) + return ret; + + ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets, + ARRAY_SIZE(lm4857_dapm_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, lm4857_routes, + ARRAY_SIZE(lm4857_routes)); + if (ret) + return ret; + + snd_soc_dapm_new_widgets(dapm); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { + .write = lm4857_write, + .read = lm4857_read, + .probe = lm4857_probe, + .reg_cache_size = ARRAY_SIZE(lm4857_default_regs), + .reg_word_size = sizeof(uint8_t), + .reg_cache_default = lm4857_default_regs, + .set_bias_level = lm4857_set_bias_level, +}; + +static int __devinit lm4857_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct lm4857 *lm4857; + int ret; + + lm4857 = kzalloc(sizeof(*lm4857), GFP_KERNEL); + if (!lm4857) + return -ENOMEM; + + i2c_set_clientdata(i2c, lm4857); + + lm4857->i2c = i2c; + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0); + + if (ret) { + kfree(lm4857); + return ret; + } + + return 0; +} + +static int __devexit lm4857_i2c_remove(struct i2c_client *i2c) +{ + struct lm4857 *lm4857 = i2c_get_clientdata(i2c); + + snd_soc_unregister_codec(&i2c->dev); + kfree(lm4857); + + return 0; +} + +static const struct i2c_device_id lm4857_i2c_id[] = { + { "lm4857", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); + +static struct i2c_driver lm4857_i2c_driver = { + .driver = { + .name = "lm4857", + .owner = THIS_MODULE, + }, + .probe = lm4857_i2c_probe, + .remove = __devexit_p(lm4857_i2c_remove), + .id_table = lm4857_i2c_id, +}; + +static int __init lm4857_init(void) +{ + return i2c_add_driver(&lm4857_i2c_driver); +} +module_init(lm4857_init); + +static void __exit lm4857_exit(void) +{ + i2c_del_driver(&lm4857_i2c_driver); +} +module_exit(lm4857_exit); + +MODULE_AUTHOR("Lars-Peter Clausen lars@metafoo.de"); +MODULE_DESCRIPTION("LM4857 amplifier driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index a6a6b5f..ba78e26 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -39,6 +39,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753 depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01 select SND_S3C24XX_I2S select SND_SOC_WM8753 + select SND_SOC_LM4857 help Say Y if you want to add support for SoC audio on smdk2440 with the WM8753. diff --git a/sound/soc/samsung/lm4857.h b/sound/soc/samsung/lm4857.h deleted file mode 100644 index 0cf5b70..0000000 --- a/sound/soc/samsung/lm4857.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * lm4857.h -- ALSA Soc Audio Layer - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Revision history - * 18th Jun 2007 Initial version. - */ - -#ifndef LM4857_H_ -#define LM4857_H_ - -/* The register offsets in the cache array */ -#define LM4857_MVOL 0 -#define LM4857_LVOL 1 -#define LM4857_RVOL 2 -#define LM4857_CTRL 3 - -/* the shifts required to set these bits */ -#define LM4857_3D 5 -#define LM4857_WAKEUP 5 -#define LM4857_EPGAIN 4 - -#endif /*LM4857_H_*/ - diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index fe92946..7761827 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -17,11 +17,9 @@ #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/platform_device.h> -#include <linux/i2c.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> -#include <sound/tlv.h>
#include <asm/mach-types.h> #include <mach/regs-clock.h> @@ -33,12 +31,10 @@ #include <plat/regs-iis.h>
#include "../codecs/wm8753.h" -#include "lm4857.h" #include "dma.h" #include "s3c24xx-i2s.h"
static struct snd_soc_card neo1973; -static struct i2c_client *i2c;
static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -213,85 +209,7 @@ static struct snd_soc_ops neo1973_voice_ops = { .hw_free = neo1973_voice_hw_free, };
-static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; - -static void lm4857_write_regs(void) -{ - pr_debug("Entered %s\n", __func__); - - if (i2c_master_send(i2c, lm4857_regs, 4) != 4) - printk(KERN_ERR "lm4857: i2c write failed\n"); -} - -static int lm4857_get_reg(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int reg = mc->reg; - int shift = mc->shift; - int mask = mc->max; - - pr_debug("Entered %s\n", __func__); - - ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; - return 0; -} - -static int lm4857_set_reg(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - int reg = mc->reg; - int shift = mc->shift; - int mask = mc->max; - - if (((lm4857_regs[reg] >> shift) & mask) == - ucontrol->value.integer.value[0]) - return 0; - - lm4857_regs[reg] &= ~(mask << shift); - lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift; - lm4857_write_regs(); - return 1; -} - -static int lm4857_get_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; - - pr_debug("Entered %s\n", __func__); - - if (value) - value -= 5; - - ucontrol->value.integer.value[0] = value; - return 0; -} - -static int lm4857_set_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u8 value = ucontrol->value.integer.value[0]; - - pr_debug("Entered %s\n", __func__); - - if (value) - value += 5; - - if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value) - return 0; - - lm4857_regs[LM4857_CTRL] &= 0xF0; - lm4857_regs[LM4857_CTRL] |= value; - lm4857_write_regs(); - return 1; -} - static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { - SND_SOC_DAPM_LINE("Audio Out", NULL), SND_SOC_DAPM_LINE("GSM Line Out", NULL), SND_SOC_DAPM_LINE("GSM Line In", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -299,12 +217,7 @@ static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { };
-static const struct snd_soc_dapm_route dapm_routes[] = { - - /* Connections to the lm4857 amp */ - {"Audio Out", NULL, "LOUT1"}, - {"Audio Out", NULL, "ROUT1"}, - +static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { /* Connections to the GSM Module */ {"GSM Line Out", NULL, "MONO1"}, {"GSM Line Out", NULL, "MONO2"}, @@ -324,46 +237,14 @@ static const struct snd_soc_dapm_route dapm_routes[] = { {"ACIN", NULL, "ACOP"}, };
-static const char *lm4857_mode[] = { - "Off", - "Call Speaker", - "Stereo Speakers", - "Stereo Speakers + Headphones", - "Headphones" -}; - -static const struct soc_enum lm4857_mode_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode), -}; - -static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); -static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); - -static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { - SOC_DAPM_PIN_SWITCH("Audio Out"), +static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { SOC_DAPM_PIN_SWITCH("GSM Line Out"), SOC_DAPM_PIN_SWITCH("GSM Line In"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Call Mic"), - - SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, - lm4857_get_reg, lm4857_set_reg, stereo_tlv), - SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, - lm4857_get_reg, lm4857_set_reg, stereo_tlv), - SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, - lm4857_get_reg, lm4857_set_reg, mono_tlv), - SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], - lm4857_get_mode, lm4857_set_mode), - SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0, - lm4857_get_reg, lm4857_set_reg), - SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0, - lm4857_get_reg, lm4857_set_reg), - SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0, - lm4857_get_reg, lm4857_set_reg), - SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0, - lm4857_get_reg, lm4857_set_reg), };
+ /* * This is an example machine initialisation for a wm8753 connected to a * neo1973 II. It is missing logic to detect hp/mic insertions and logic @@ -387,29 +268,66 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
/* Add neo1973 specific widgets */ snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, - ARRAY_SIZE(wm8753_dapm_widgets)); + ARRAY_SIZE(wm8753_dapm_widgets));
/* set endpoints to default mode */ - snd_soc_dapm_disable_pin(dapm, "Audio Out"); snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); snd_soc_dapm_disable_pin(dapm, "GSM Line In"); snd_soc_dapm_disable_pin(dapm, "Headset Mic"); snd_soc_dapm_disable_pin(dapm, "Call Mic");
/* add neo1973 specific controls */ - err = snd_soc_add_controls(codec, wm8753_neo1973_controls, - ARRAY_SIZE(8753_neo1973_controls)); + err = snd_soc_add_controls(codec, neo1973_wm8753_controls, + ARRAY_SIZE(neo1973_wm8753_controls)); if (err < 0) return err;
/* set up neo1973 specific audio routes */ - err = snd_soc_dapm_add_routes(dapm, dapm_routes, - ARRAY_SIZE(dapm_routes)); + err = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, + ARRAY_SIZE(neo1973_wm8753_routes));
snd_soc_dapm_sync(dapm); return 0; }
+static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { + {"Amp IN", NULL, "ROUT1"}, + {"Amp IN", NULL, "LOUT1"}, + + {"Handset Spk", NULL, "Amp EP"}, + {"Stereo Out", NULL, "Amp LS"}, + {"Headphone", NULL, "Amp HP"}, +}; + +static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Handset Spk", NULL), + SND_SOC_DAPM_SPK("Stereo Out", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), +}; + +static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) +{ + int ret; + + ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, + ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, + ARRAY_SIZE(neo1973_lm4857_routes)); + if (ret) + return ret; + + snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); + snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); + snd_soc_dapm_ignore_suspend(dapm, "Headphone"); + + snd_soc_dapm_sync(dapm); + + return 0; +} + /* * BT Codec DAI */ @@ -449,83 +367,29 @@ static struct snd_soc_dai_link neo1973_dai[] = { }, };
-static struct snd_soc_card neo1973 = { - .name = "neo1973", - .dai_link = neo1973_dai, - .num_links = ARRAY_SIZE(neo1973_dai), +static struct snd_soc_aux_dev neo1973_aux_devs[] = { + { + .name = "lm4857", + .codec_name = "lm4857.0-007c", + .init = neo1973_lm4857_init, + }, };
-static int lm4857_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - pr_debug("Entered %s\n", __func__); - - i2c = client; - - lm4857_write_regs(); - return 0; -} - -static int lm4857_i2c_remove(struct i2c_client *client) -{ - pr_debug("Entered %s\n", __func__); - - i2c = NULL; - - return 0; -} - -static u8 lm4857_state; - -static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) -{ - pr_debug("Entered %s\n", __func__); - - dev_dbg(&dev->dev, "lm4857_suspend\n"); - lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; - if (lm4857_state) { - lm4857_regs[LM4857_CTRL] &= 0xf0; - lm4857_write_regs(); - } - return 0; -} - -static int lm4857_resume(struct i2c_client *dev) -{ - pr_debug("Entered %s\n", __func__); - - if (lm4857_state) { - lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); - lm4857_write_regs(); - } - return 0; -} - -static void lm4857_shutdown(struct i2c_client *dev) -{ - pr_debug("Entered %s\n", __func__); - - dev_dbg(&dev->dev, "lm4857_shutdown\n"); - lm4857_regs[LM4857_CTRL] &= 0xf0; - lm4857_write_regs(); -} - -static const struct i2c_device_id lm4857_i2c_id[] = { - { "neo1973_lm4857", 0 }, - { } +static struct snd_soc_codec_conf neo1973_codec_conf[] = { + { + .dev_name = "lm4857.0-007c", + .name_prefix = "Amp", + }, };
-static struct i2c_driver lm4857_i2c_driver = { - .driver = { - .name = "LM4857 I2C Amp", - .owner = THIS_MODULE, - }, - .suspend = lm4857_suspend, - .resume = lm4857_resume, - .shutdown = lm4857_shutdown, - .probe = lm4857_i2c_probe, - .remove = lm4857_i2c_remove, - .id_table = lm4857_i2c_id, +static struct snd_soc_card neo1973 = { + .name = "neo1973", + .dai_link = neo1973_dai, + .num_links = ARRAY_SIZE(neo1973_dai), + .aux_dev = neo1973_aux_devs, + .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), + .codec_conf = neo1973_codec_conf, + .num_configs = ARRAY_SIZE(neo1973_codec_conf), };
static struct platform_device *neo1973_snd_device; @@ -554,8 +418,6 @@ static int __init neo1973_init(void) return ret; }
- ret = i2c_add_driver(&lm4857_i2c_driver); - if (ret != 0) platform_device_unregister(neo1973_snd_device);
@@ -566,7 +428,6 @@ static void __exit neo1973_exit(void) { pr_debug("Entered %s\n", __func__);
- i2c_del_driver(&lm4857_i2c_driver); platform_device_unregister(neo1973_snd_device); }
On Mon, Mar 07, 2011 at 08:04:55AM +0100, Lars-Peter Clausen wrote:
index 82a4630..37035e6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -347,6 +347,9 @@ config SND_SOC_WM9713 tristate
# Amp +config SND_SOC_LM4857
- tristate
config SND_SOC_MAX9877 tristate
This should also add LM4857 to SND_SOC_ALL_CODECS. I'll fix that incrementally.
This patch drops the lm4853_{set,get}_state functions and the "Amp State Switch" control. Those were noops which existed to maintain alsa state file compatibility. Since the control names have changed due to internal changes in the ASoC core and state file compatibility was broken anyway it makes sense to drop them.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/samsung/neo1973_gta02_wm8753.c | 55 ++++-------------------------- 1 files changed, 7 insertions(+), 48 deletions(-)
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c index 95ebf81..b007dd79 100644 --- a/sound/soc/samsung/neo1973_gta02_wm8753.c +++ b/sound/soc/samsung/neo1973_gta02_wm8753.c @@ -194,47 +194,14 @@ static struct snd_soc_ops neo1973_gta02_voice_ops = { .hw_free = neo1973_gta02_voice_hw_free, };
-#define LM4853_AMP 1 -#define LM4853_SPK 2 - -static u8 lm4853_state; - -/* This has no effect, it exists only to maintain compatibility with - * existing ALSA state files. - */ -static int lm4853_set_state(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int val = ucontrol->value.integer.value[0]; - - if (val) - lm4853_state |= LM4853_AMP; - else - lm4853_state &= ~LM4853_AMP; - - return 0; -} - -static int lm4853_get_state(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP; - - return 0; -} +static int gta02_speaker_enabled;
static int lm4853_set_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - int val = ucontrol->value.integer.value[0]; - - if (val) { - lm4853_state |= LM4853_SPK; - gpio_set_value(GTA02_GPIO_HP_IN, 0); - } else { - lm4853_state &= ~LM4853_SPK; - gpio_set_value(GTA02_GPIO_HP_IN, 1); - } + gta02_speaker_enabled = ucontrol->value.integer.value[0]; + + gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled);
return 0; } @@ -242,14 +209,12 @@ static int lm4853_set_spk(struct snd_kcontrol *kcontrol, static int lm4853_get_spk(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1; - + ucontrol->value.integer.value[0] = gta02_speaker_enabled; return 0; }
static int lm4853_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, - int event) + struct snd_kcontrol *k, int event) { gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
@@ -304,13 +269,7 @@ static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = { SOC_DAPM_PIN_SWITCH("Handset Mic"), SOC_DAPM_PIN_SWITCH("Handset Spk"),
- /* This has no effect, it exists only to maintain compatibility with - * existing ALSA state files. - */ - SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0, - lm4853_get_state, - lm4853_set_state), - SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0, + SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, lm4853_get_spk, lm4853_set_spk), };
Using gpio_request_array instead of requesting and setting up each gpio by hand makes the code more readable and more compact.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/samsung/neo1973_gta02_wm8753.c | 52 ++++++++++-------------------- 1 files changed, 17 insertions(+), 35 deletions(-)
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c index b007dd79..28d8448 100644 --- a/sound/soc/samsung/neo1973_gta02_wm8753.c +++ b/sound/soc/samsung/neo1973_gta02_wm8753.c @@ -370,6 +370,11 @@ static struct snd_soc_card neo1973_gta02 = { .num_links = ARRAY_SIZE(neo1973_gta02_dai), };
+static const struct gpio neo1973_gta02_gpios[] = { + { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, + { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, +}; + static struct platform_device *neo1973_gta02_snd_device;
static int __init neo1973_gta02_init(void) @@ -382,9 +387,16 @@ static int __init neo1973_gta02_init(void) return -ENODEV; }
+ ret = gpio_request_array(neo1973_gta02_gpios, + ARRAY_SIZE(neo1973_gta02_gpios)); + if (ret) + return ret; + neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1); - if (!neo1973_gta02_snd_device) - return -ENOMEM; + if (!neo1973_gta02_snd_device) { + ret = -ENOMEM; + goto err_gpio_free; + }
/* register bluetooth DAI here */ ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, &bt_dai); @@ -397,43 +409,14 @@ static int __init neo1973_gta02_init(void) if (ret) goto err_unregister_dai;
- /* Initialise GPIOs used by amp */ - ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN"); - if (ret) { - pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN); - goto err_del_device; - } - - ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1); - if (ret) { - pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN); - goto err_free_gpio_hp_in; - } - - ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT"); - if (ret) { - pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT); - goto err_free_gpio_hp_in; - } - - ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1); - if (ret) { - pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT); - goto err_free_gpio_amp_shut; - } - return 0;
-err_free_gpio_amp_shut: - gpio_free(GTA02_GPIO_AMP_SHUT); -err_free_gpio_hp_in: - gpio_free(GTA02_GPIO_HP_IN); -err_del_device: - platform_device_del(neo1973_gta02_snd_device); err_unregister_dai: snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev); err_put_device: platform_device_put(neo1973_gta02_snd_device); +err_gpio_free: + gpio_free_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios)); return ret; } module_init(neo1973_gta02_init); @@ -442,8 +425,7 @@ static void __exit neo1973_gta02_exit(void) { snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev); platform_device_unregister(neo1973_gta02_snd_device); - gpio_free(GTA02_GPIO_HP_IN); - gpio_free(GTA02_GPIO_AMP_SHUT); + gpio_free_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios)); } module_exit(neo1973_gta02_exit);
The neo1973(GTA01) and neo1973_gta02(GTA02) have a very similar audio hardware setup. They both use the same codec with the same routing to the gsm modem and bluetooth chip. But they do use different AMPs though and there are some minor differences in the speaker setup.
As a result most of the code of those two drivers is identical. So from a maintenance point of view it makes sense to merge them into a single driver. It also reduces the size of kernel images supporting both the GTA01 and GTA02.
As a side-effect of this merge the GTA01 for example gains support for routing audio to and from the bluetooth DAI.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/samsung/Kconfig | 19 +- sound/soc/samsung/Makefile | 2 - sound/soc/samsung/neo1973_gta02_wm8753.c | 435 ------------------------------ sound/soc/samsung/neo1973_wm8753.c | 262 +++++++++++++----- 4 files changed, 196 insertions(+), 522 deletions(-) delete mode 100644 sound/soc/samsung/neo1973_gta02_wm8753.c
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index ba78e26..c3014e8 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -35,24 +35,15 @@ config SND_SAMSUNG_I2S tristate
config SND_SOC_SAMSUNG_NEO1973_WM8753 - tristate "SoC I2S Audio support for NEO1973 - WM8753" - depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01 + tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)" + depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02) select SND_S3C24XX_I2S select SND_SOC_WM8753 - select SND_SOC_LM4857 + select SND_SOC_LM4857 if MACH_NEO1973_GTA01 help - Say Y if you want to add support for SoC audio on smdk2440 - with the WM8753. + Say Y here to enable audio support for the Openmoko Neo1973 + Smartphones.
-config SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753 - tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)" - depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02 - select SND_S3C24XX_I2S - select SND_SOC_WM8753 - help - This driver provides audio support for the Openmoko Neo FreeRunner - smartphone. - config SND_SOC_SAMSUNG_JIVE_WM8750 tristate "SoC I2S Audio support for Jive" depends on SND_SOC_SAMSUNG && MACH_JIVE diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 705d4e8..294dec0 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o # S3C24XX Machine Support snd-soc-jive-wm8750-objs := jive_wm8750.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o -snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o @@ -38,7 +37,6 @@ snd-soc-smdk-spdif-objs := smdk_spdif.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o -obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c deleted file mode 100644 index 28d8448..0000000 --- a/sound/soc/samsung/neo1973_gta02_wm8753.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02) - * - * Copyright 2007 Openmoko Inc - * Author: Graeme Gregory graeme@openmoko.org - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory linux@wolfsonmicro.com - * Copyright 2009 Wolfson Microelectronics - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <linux/gpio.h> - -#include <sound/soc.h> - -#include <asm/mach-types.h> -#include <plat/regs-iis.h> -#include <mach/gta02.h> - -#include "../codecs/wm8753.h" -#include "s3c24xx-i2s.h" - -static struct snd_soc_card neo1973_gta02; - -static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - unsigned int pll_out = 0, bclk = 0; - int ret = 0; - unsigned long iis_clkrate; - - iis_clkrate = s3c24xx_i2s_get_clockrate(); - - switch (params_rate(params)) { - case 8000: - case 16000: - pll_out = 12288000; - break; - case 48000: - bclk = WM8753_BCLK_DIV_4; - pll_out = 12288000; - break; - case 96000: - bclk = WM8753_BCLK_DIV_2; - pll_out = 12288000; - break; - case 11025: - bclk = WM8753_BCLK_DIV_16; - pll_out = 11289600; - break; - case 22050: - bclk = WM8753_BCLK_DIV_8; - pll_out = 11289600; - break; - case 44100: - bclk = WM8753_BCLK_DIV_4; - pll_out = 11289600; - break; - case 88200: - bclk = WM8753_BCLK_DIV_2; - pll_out = 11289600; - break; - } - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) - return ret; - - /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, - SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - /* set MCLK division for sample rate */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, - S3C2410_IISMOD_32FS); - if (ret < 0) - return ret; - - /* set codec BCLK division for sample rate */ - ret = snd_soc_dai_set_clkdiv(codec_dai, - WM8753_BCLKDIV, bclk); - if (ret < 0) - return ret; - - /* set prescaler division for sample rate */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, - S3C24XX_PRESCALE(4, 4)); - if (ret < 0) - return ret; - - /* codec PLL input is PCLK/4 */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, - iis_clkrate / 4, pll_out); - if (ret < 0) - return ret; - - return 0; -} - -static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); -} - -/* - * Neo1973 WM8753 HiFi DAI opserations. - */ -static struct snd_soc_ops neo1973_gta02_hifi_ops = { - .hw_params = neo1973_gta02_hifi_hw_params, - .hw_free = neo1973_gta02_hifi_hw_free, -}; - -static int neo1973_gta02_voice_hw_params( - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - unsigned int pcmdiv = 0; - int ret = 0; - unsigned long iis_clkrate; - - iis_clkrate = s3c24xx_i2s_get_clockrate(); - - if (params_rate(params) != 8000) - return -EINVAL; - if (params_channels(params) != 1) - return -EINVAL; - - pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ - - /* todo: gg check mode (DSP_B) against CSR datasheet */ - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, - 12288000, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - /* set codec PCM division for sample rate */ - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, - pcmdiv); - if (ret < 0) - return ret; - - /* configure and enable PLL for 12.288MHz output */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, - iis_clkrate / 4, 12288000); - if (ret < 0) - return ret; - - return 0; -} - -static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - - /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); -} - -static struct snd_soc_ops neo1973_gta02_voice_ops = { - .hw_params = neo1973_gta02_voice_hw_params, - .hw_free = neo1973_gta02_voice_hw_free, -}; - -static int gta02_speaker_enabled; - -static int lm4853_set_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - gta02_speaker_enabled = ucontrol->value.integer.value[0]; - - gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); - - return 0; -} - -static int lm4853_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = gta02_speaker_enabled; - return 0; -} - -static int lm4853_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); - - return 0; -} - -static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { - SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), - SND_SOC_DAPM_LINE("GSM Line Out", NULL), - SND_SOC_DAPM_LINE("GSM Line In", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Handset Mic", NULL), - SND_SOC_DAPM_SPK("Handset Spk", NULL), -}; - - -/* example machine audio_mapnections */ -static const struct snd_soc_dapm_route audio_map[] = { - - /* Connections to the lm4853 amp */ - {"Stereo Out", NULL, "LOUT1"}, - {"Stereo Out", NULL, "ROUT1"}, - - /* Connections to the GSM Module */ - {"GSM Line Out", NULL, "MONO1"}, - {"GSM Line Out", NULL, "MONO2"}, - {"RXP", NULL, "GSM Line In"}, - {"RXN", NULL, "GSM Line In"}, - - /* Connections to Headset */ - {"MIC1", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Headset Mic"}, - - /* Call Mic */ - {"MIC2", NULL, "Mic Bias"}, - {"MIC2N", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Handset Mic"}, - - /* Call Speaker */ - {"Handset Spk", NULL, "LOUT2"}, - {"Handset Spk", NULL, "ROUT2"}, - - /* Connect the ALC pins */ - {"ACIN", NULL, "ACOP"}, -}; - -static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = { - SOC_DAPM_PIN_SWITCH("Stereo Out"), - SOC_DAPM_PIN_SWITCH("GSM Line Out"), - SOC_DAPM_PIN_SWITCH("GSM Line In"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Handset Mic"), - SOC_DAPM_PIN_SWITCH("Handset Spk"), - - SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, - lm4853_get_spk, - lm4853_set_spk), -}; - -/* - * This is an example machine initialisation for a wm8753 connected to a - * neo1973 GTA02. - */ -static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - int err; - - /* set up NC codec pins */ - snd_soc_dapm_nc_pin(dapm, "OUT3"); - snd_soc_dapm_nc_pin(dapm, "OUT4"); - snd_soc_dapm_nc_pin(dapm, "LINE1"); - snd_soc_dapm_nc_pin(dapm, "LINE2"); - - /* Add neo1973 gta02 specific widgets */ - snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, - ARRAY_SIZE(wm8753_dapm_widgets)); - - /* add neo1973 gta02 specific controls */ - err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls, - ARRAY_SIZE(wm8753_neo1973_gta02_controls)); - - if (err < 0) - return err; - - /* set up neo1973 gta02 specific audio path audio_map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - /* set endpoints to default off mode */ - snd_soc_dapm_disable_pin(dapm, "Stereo Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Handset Mic"); - snd_soc_dapm_disable_pin(dapm, "Handset Spk"); - - /* allow audio paths from the GSM modem to run during suspend */ - snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); - snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); - snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); - snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); - snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); - snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); - - snd_soc_dapm_sync(dapm); - - return 0; -} - -/* - * BT Codec DAI - */ -static struct snd_soc_dai_driver bt_dai = { - .name = "bluetooth-dai", - .playback = { - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -}; - -static struct snd_soc_dai_link neo1973_gta02_dai[] = { -{ /* Hifi Playback - for similatious use with voice below */ - .name = "WM8753", - .stream_name = "WM8753 HiFi", - .cpu_dai_name = "s3c24xx-iis", - .codec_dai_name = "wm8753-hifi", - .init = neo1973_gta02_wm8753_init, - .platform_name = "samsung-audio", - .codec_name = "wm8753-codec.0-001a", - .ops = &neo1973_gta02_hifi_ops, -}, -{ /* Voice via BT */ - .name = "Bluetooth", - .stream_name = "Voice", - .cpu_dai_name = "bluetooth-dai", - .codec_dai_name = "wm8753-voice", - .ops = &neo1973_gta02_voice_ops, - .codec_name = "wm8753-codec.0-001a", - .platform_name = "samsung-audio", -}, -}; - -static struct snd_soc_card neo1973_gta02 = { - .name = "neo1973-gta02", - .dai_link = neo1973_gta02_dai, - .num_links = ARRAY_SIZE(neo1973_gta02_dai), -}; - -static const struct gpio neo1973_gta02_gpios[] = { - { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, - { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, -}; - -static struct platform_device *neo1973_gta02_snd_device; - -static int __init neo1973_gta02_init(void) -{ - int ret; - - if (!machine_is_neo1973_gta02()) { - printk(KERN_INFO - "Only GTA02 is supported by this ASoC driver\n"); - return -ENODEV; - } - - ret = gpio_request_array(neo1973_gta02_gpios, - ARRAY_SIZE(neo1973_gta02_gpios)); - if (ret) - return ret; - - neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1); - if (!neo1973_gta02_snd_device) { - ret = -ENOMEM; - goto err_gpio_free; - } - - /* register bluetooth DAI here */ - ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, &bt_dai); - if (ret) - goto err_put_device; - - platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02); - ret = platform_device_add(neo1973_gta02_snd_device); - - if (ret) - goto err_unregister_dai; - - return 0; - -err_unregister_dai: - snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev); -err_put_device: - platform_device_put(neo1973_gta02_snd_device); -err_gpio_free: - gpio_free_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios)); - return ret; -} -module_init(neo1973_gta02_init); - -static void __exit neo1973_gta02_exit(void) -{ - snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev); - platform_device_unregister(neo1973_gta02_snd_device); - gpio_free_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios)); -} -module_exit(neo1973_gta02_exit); - -/* Module information */ -MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org"); -MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 7761827..37cfbb8 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -1,41 +1,32 @@ /* - * neo1973_wm8753.c -- SoC audio for Neo1973 + * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices * + * Copyright 2007 Openmoko Inc + * Author: Graeme Gregory graeme@openmoko.org * Copyright 2007 Wolfson Microelectronics PLC. * Author: Graeme Gregory * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * Copyright 2009 Wolfson Microelectronics * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. - * */
#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/timer.h> -#include <linux/interrupt.h> #include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> +#include <linux/gpio.h> + #include <sound/soc.h>
#include <asm/mach-types.h> -#include <mach/regs-clock.h> -#include <mach/regs-gpio.h> -#include <mach/hardware.h> -#include <linux/io.h> -#include <mach/spi-gpio.h> - #include <plat/regs-iis.h> +#include <mach/gta02.h>
#include "../codecs/wm8753.h" -#include "dma.h" #include "s3c24xx-i2s.h"
-static struct snd_soc_card neo1973; - static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -46,8 +37,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, int ret = 0; unsigned long iis_clkrate;
- pr_debug("Entered %s\n", __func__); - iis_clkrate = s3c24xx_i2s_get_clockrate();
switch (params_rate(params)) { @@ -132,8 +121,6 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai;
- pr_debug("Entered %s\n", __func__); - /* disable the PLL */ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); } @@ -155,8 +142,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, int ret = 0; unsigned long iis_clkrate;
- pr_debug("Entered %s\n", __func__); - iis_clkrate = s3c24xx_i2s_get_clockrate();
if (params_rate(params) != 8000) @@ -198,8 +183,6 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai;
- pr_debug("Entered %s\n", __func__); - /* disable the PLL */ return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); } @@ -209,14 +192,15 @@ static struct snd_soc_ops neo1973_voice_ops = { .hw_free = neo1973_voice_hw_free, };
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { +/* Shared routes and controls */ + +static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { SND_SOC_DAPM_LINE("GSM Line Out", NULL), SND_SOC_DAPM_LINE("GSM Line In", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Call Mic", NULL), + SND_SOC_DAPM_MIC("Handset Mic", NULL), };
- static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { /* Connections to the GSM Module */ {"GSM Line Out", NULL, "MONO1"}, @@ -231,7 +215,7 @@ static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { /* Call Mic */ {"MIC2", NULL, "Mic Bias"}, {"MIC2N", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Call Mic"}, + {"Mic Bias", NULL, "Handset Mic"},
/* Connect the ALC pins */ {"ACIN", NULL, "ACOP"}, @@ -241,55 +225,157 @@ static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { SOC_DAPM_PIN_SWITCH("GSM Line Out"), SOC_DAPM_PIN_SWITCH("GSM Line In"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Call Mic"), + SOC_DAPM_PIN_SWITCH("Handset Mic"), };
+/* GTA02 specific routes and controlls */ + +#ifdef CONFIG_MACH_NEO1973_GTA02 + +static int gta02_speaker_enabled; + +static int lm4853_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + gta02_speaker_enabled = ucontrol->value.integer.value[0]; + + gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); + + return 0; +} + +static int lm4853_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = gta02_speaker_enabled; + return 0; +} + +static int lm4853_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); + + return 0; +} + +static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { + /* Connections to the amp */ + {"Stereo Out", NULL, "LOUT1"}, + {"Stereo Out", NULL, "ROUT1"}, + + /* Call Speaker */ + {"Handset Spk", NULL, "LOUT2"}, + {"Handset Spk", NULL, "ROUT2"}, +}; + +static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { + SOC_DAPM_PIN_SWITCH("Handset Spk"), + SOC_DAPM_PIN_SWITCH("Stereo Out"), + + SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, + lm4853_get_spk, + lm4853_set_spk), +}; + +static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Handset Spk", NULL), + SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), +}; + +static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, + ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); + if (ret) + return ret; + + ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, + ARRAY_SIZE(neo1973_gta02_routes)); + if (ret) + return ret; + + ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls, + ARRAY_SIZE(neo1973_gta02_wm8753_controls)); + if (ret) + return ret; + + snd_soc_dapm_disable_pin(dapm, "Stereo Out"); + snd_soc_dapm_disable_pin(dapm, "Handset Spk"); + snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); + snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); + + return 0; +} + +#else +static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } +#endif
-/* - * This is an example machine initialisation for a wm8753 connected to a - * neo1973 II. It is missing logic to detect hp/mic insertions and logic - * to re-route the audio in such an event. - */ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; - int err; - - pr_debug("Entered %s\n", __func__); + int ret;
/* set up NC codec pins */ - snd_soc_dapm_nc_pin(dapm, "LOUT2"); - snd_soc_dapm_nc_pin(dapm, "ROUT2"); + if (machine_is_neo1973_gta01()) { + snd_soc_dapm_nc_pin(dapm, "LOUT2"); + snd_soc_dapm_nc_pin(dapm, "ROUT2"); + } snd_soc_dapm_nc_pin(dapm, "OUT3"); snd_soc_dapm_nc_pin(dapm, "OUT4"); snd_soc_dapm_nc_pin(dapm, "LINE1"); snd_soc_dapm_nc_pin(dapm, "LINE2");
/* Add neo1973 specific widgets */ - snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, - ARRAY_SIZE(wm8753_dapm_widgets)); - - /* set endpoints to default mode */ - snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); - snd_soc_dapm_disable_pin(dapm, "GSM Line In"); - snd_soc_dapm_disable_pin(dapm, "Headset Mic"); - snd_soc_dapm_disable_pin(dapm, "Call Mic"); + ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, + ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); + if (ret) + return ret;
/* add neo1973 specific controls */ - err = snd_soc_add_controls(codec, neo1973_wm8753_controls, - ARRAY_SIZE(neo1973_wm8753_controls)); - if (err < 0) - return err; + ret = snd_soc_add_controls(codec, neo1973_wm8753_controls, + ARRAY_SIZE(neo1973_wm8753_controls)); + if (ret) + return ret;
/* set up neo1973 specific audio routes */ - err = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, + ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, ARRAY_SIZE(neo1973_wm8753_routes)); + if (ret) + return ret; + + /* set endpoints to default off mode */ + snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); + snd_soc_dapm_disable_pin(dapm, "GSM Line In"); + snd_soc_dapm_disable_pin(dapm, "Headset Mic"); + snd_soc_dapm_disable_pin(dapm, "Handset Mic"); + + /* allow audio paths from the GSM modem to run during suspend */ + snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); + snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); + + if (machine_is_neo1973_gta02()) { + ret = neo1973_gta02_wm8753_init(codec); + if (ret) + return ret; + }
snd_soc_dapm_sync(dapm); + return 0; }
+/* GTA01 specific controlls */ + +#ifdef CONFIG_MACH_NEO1973_GTA01 + static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { {"Amp IN", NULL, "ROUT1"}, {"Amp IN", NULL, "LOUT1"}, @@ -328,10 +414,14 @@ static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) return 0; }
+#else +static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; +#endif + /* * BT Codec DAI */ -static struct snd_soc_dai bt_dai = { +static struct snd_soc_dai_driver bt_dai = { .name = "bluetooth-dai", .playback = { .channels_min = 1, @@ -382,6 +472,15 @@ static struct snd_soc_codec_conf neo1973_codec_conf[] = { }, };
+#ifdef CONFIG_MACH_NEO1973_GTA02 +static const struct gpio neo1973_gta02_gpios[] = { + { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, + { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, +}; +#else +static const struct gpio neo1973_gta02_gpios[] = {}; +#endif + static struct snd_soc_card neo1973 = { .name = "neo1973", .dai_link = neo1973_dai, @@ -398,43 +497,64 @@ static int __init neo1973_init(void) { int ret;
- pr_debug("Entered %s\n", __func__); - - if (!machine_is_neo1973_gta01()) { - printk(KERN_INFO - "Only GTA01 hardware supported by ASoC driver\n"); + if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) return -ENODEV; + + if (machine_is_neo1973_gta02()) { + neo1973.name = "neo1973gta02"; + neo1973.num_aux_devs = 0; + + ret = gpio_request_array(neo1973_gta02_gpios, + ARRAY_SIZE(neo1973_gta02_gpios)); + if (ret) + return ret; }
neo1973_snd_device = platform_device_alloc("soc-audio", -1); - if (!neo1973_snd_device) - return -ENOMEM; + if (!neo1973_snd_device) { + ret = -ENOMEM; + goto err_gpio_free; + } + + /* register bluetooth DAI here */ + ret = snd_soc_register_dai(&neo1973_snd_device->dev, &bt_dai); + if (ret) + goto err_put_device;
platform_set_drvdata(neo1973_snd_device, &neo1973); ret = platform_device_add(neo1973_snd_device);
- if (ret) { - platform_device_put(neo1973_snd_device); - return ret; - } + if (ret) + goto err_unregister_dai;
- if (ret != 0) - platform_device_unregister(neo1973_snd_device); + return 0;
+err_unregister_dai: + snd_soc_unregister_dai(&neo1973_snd_device->dev); +err_put_device: + platform_device_put(neo1973_snd_device); +err_gpio_free: + if (machine_is_neo1973_gta02()) { + gpio_free_array(neo1973_gta02_gpios, + ARRAY_SIZE(neo1973_gta02_gpios)); + } return ret; } +module_init(neo1973_init);
static void __exit neo1973_exit(void) { - pr_debug("Entered %s\n", __func__); - + snd_soc_unregister_dai(&neo1973_snd_device->dev); platform_device_unregister(neo1973_snd_device); -}
-module_init(neo1973_init); + if (machine_is_neo1973_gta02()) { + gpio_free_array(neo1973_gta02_gpios, + ARRAY_SIZE(neo1973_gta02_gpios)); + } +} module_exit(neo1973_exit);
/* Module information */ MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); -MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973"); +MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); MODULE_LICENSE("GPL");
This patch adds a codec driver for the dfbmcs320 bluetooth module, which is used on the neo1973 boards.
The patch also modifies the neo1937_wm8753 sound board driver to use the new driver instead of registering the bluetooth DAI manually. Previously there was a name mismatch between the bluetooth DAI and the bluetooth DAI link and the sound card was not instantiated, with this patch the issue is no longer present and sound support works again.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/Kconfig | 5 ++- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/dfbmcs320.c | 72 ++++++++++++++++++++++++++++++++++++ sound/soc/samsung/Kconfig | 1 + sound/soc/samsung/neo1973_wm8753.c | 35 +++-------------- 5 files changed, 86 insertions(+), 29 deletions(-) create mode 100644 sound/soc/codecs/dfbmcs320.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 37035e6..212859c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI select SND_SOC_CX20442 select SND_SOC_DA7210 if I2C + select SND_SOC_DFBMCS320 select SND_SOC_JZ4740_CODEC if SOC_JZ4740 select SND_SOC_MAX98088 if I2C select SND_SOC_MAX9877 if I2C @@ -175,6 +176,9 @@ config SND_SOC_L3 config SND_SOC_DA7210 tristate
+config SND_SOC_DFBMCS320 + tristate + config SND_SOC_DMIC tristate
@@ -361,4 +365,3 @@ config SND_SOC_WM2000
config SND_SOC_WM9090 tristate - diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0663d22..ebb059c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -15,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o +snd-soc-dfbmcs320-objs := dfbmcs320.o snd-soc-dmic-objs := dmic.o snd-soc-l3-objs := l3.o snd-soc-max98088-objs := max98088.o @@ -101,6 +102,7 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o +obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o diff --git a/sound/soc/codecs/dfbmcs320.c b/sound/soc/codecs/dfbmcs320.c new file mode 100644 index 0000000..704bbde --- /dev/null +++ b/sound/soc/codecs/dfbmcs320.c @@ -0,0 +1,72 @@ +/* + * Driver for the DFBM-CS320 bluetooth module + * Copyright 2011 Lars-Peter Clausen lars@metafoo.de + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <sound/soc.h> + +static struct snd_soc_dai_driver dfbmcs320_dai = { + .name = "dfbmcs320-pcm", + .playback = { + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_dfbmcs320; + +static int __devinit dfbmcs320_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_dfbmcs320, + &dfbmcs320_dai, 1); +} + +static int __devexit dfbmcs320_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +static struct platform_driver dfmcs320_driver = { + .driver = { + .name = "dfbmcs320", + .owner = THIS_MODULE, + }, + .probe = dfbmcs320_probe, + .remove = __devexit_p(dfbmcs320_remove), +}; + +static int __init dfbmcs320_init(void) +{ + return platform_driver_register(&dfmcs320_driver); +} +module_init(dfbmcs320_init); + +static void __exit dfbmcs320_exit(void) +{ + platform_driver_unregister(&dfmcs320_driver); +} +module_exit(dfbmcs320_exit); + +MODULE_AUTHOR("Lars-Peter Clausen lars@metafoo.de"); +MODULE_DESCRIPTION("ASoC DFBM-CS320 bluethooth module driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index c3014e8..a08237a 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -40,6 +40,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753 select SND_S3C24XX_I2S select SND_SOC_WM8753 select SND_SOC_LM4857 if MACH_NEO1973_GTA01 + select SND_SOC_DFBMCS320 help Say Y here to enable audio support for the Openmoko Neo1973 Smartphones. diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 37cfbb8..78bfdb3 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -418,23 +418,6 @@ static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; #endif
-/* - * BT Codec DAI - */ -static struct snd_soc_dai_driver bt_dai = { - .name = "bluetooth-dai", - .playback = { - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -}; - static struct snd_soc_dai_link neo1973_dai[] = { { /* Hifi Playback - for similatious use with voice below */ .name = "WM8753", @@ -450,7 +433,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { .name = "Bluetooth", .stream_name = "Voice", .platform_name = "samsung-audio", - .cpu_dai_name = "bluetooth-dai", + .cpu_dai_name = "dfbmcs320-pcm", .codec_dai_name = "wm8753-voice", .codec_name = "wm8753-codec.0-001a", .ops = &neo1973_voice_ops, @@ -459,6 +442,10 @@ static struct snd_soc_dai_link neo1973_dai[] = {
static struct snd_soc_aux_dev neo1973_aux_devs[] = { { + .name = "dfbmcs320", + .codec_name = "dfbmcs320.0", + }, + { .name = "lm4857", .codec_name = "lm4857.0-007c", .init = neo1973_lm4857_init, @@ -502,7 +489,7 @@ static int __init neo1973_init(void)
if (machine_is_neo1973_gta02()) { neo1973.name = "neo1973gta02"; - neo1973.num_aux_devs = 0; + neo1973.num_aux_devs = 1;
ret = gpio_request_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios)); @@ -516,21 +503,14 @@ static int __init neo1973_init(void) goto err_gpio_free; }
- /* register bluetooth DAI here */ - ret = snd_soc_register_dai(&neo1973_snd_device->dev, &bt_dai); - if (ret) - goto err_put_device; - platform_set_drvdata(neo1973_snd_device, &neo1973); ret = platform_device_add(neo1973_snd_device);
if (ret) - goto err_unregister_dai; + goto err_put_device;
return 0;
-err_unregister_dai: - snd_soc_unregister_dai(&neo1973_snd_device->dev); err_put_device: platform_device_put(neo1973_snd_device); err_gpio_free: @@ -544,7 +524,6 @@ module_init(neo1973_init);
static void __exit neo1973_exit(void) { - snd_soc_unregister_dai(&neo1973_snd_device->dev); platform_device_unregister(neo1973_snd_device);
if (machine_is_neo1973_gta02()) {
Register the dfbmcs320 device which provides the PCM DAI for the bluetooth module.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de Cc: Ben Dooks ben-linux@fluff.org Cc: Kukjin Kim kgene.kim@samsung.com --- I've verified that this patch does not cause any merge conflicts with the other gta02 changes in Kukjin's tree, so I think it would be best to merge this patch together with the reset of the series through the ASoC tree. --- arch/arm/mach-s3c2440/mach-gta02.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c index 9f2c14e..3415517 100644 --- a/arch/arm/mach-s3c2440/mach-gta02.c +++ b/arch/arm/mach-s3c2440/mach-gta02.c @@ -416,6 +416,10 @@ struct platform_device s3c24xx_pwm_device = { .num_resources = 0, };
+static struct platform_device gta02_dfbmcs320_device = { + .name = "dfbmcs320", +}; + static struct i2c_board_info gta02_i2c_devs[] __initdata = { { I2C_BOARD_INFO("pcf50633", 0x73), @@ -508,6 +512,7 @@ static struct platform_device *gta02_devices[] __initdata = { &s3c_device_nand, >a02_nor_flash, &s3c24xx_pwm_device, + >a02_dfbmcs320_device, &s3c_device_iis, &s3c_device_i2c0, };
On Mon, 2011-03-07 at 08:04 +0100, Lars-Peter Clausen wrote:
It has been proven to be inflexible to do scenario management in kernel space.
We have UCM for this now too :)
Since actual neo1973 board support has not been merged in mainline and this patch has been in the neo1973 tree for some time now it should be safe to remove this functionality without breaking existing userspace.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
sound/soc/samsung/neo1973_wm8753.c | 148 +++--------------------------------- 1 files changed, 11 insertions(+), 137 deletions(-)
Just had a quick look. All
Acked-by: Liam Girdwood lrg@ti.com
On Mon, Mar 07, 2011 at 11:04:38AM +0000, Liam Girdwood wrote:
Just had a quick look. All
Acked-by: Liam Girdwood lrg@ti.com
Applied 1-6 - I'll wait for Kukjin to check patch 7 just in case he wants it to go via his tree, there's no compile time dependency.
On 03/07/2011 01:25 PM, Mark Brown wrote:
On Mon, Mar 07, 2011 at 11:04:38AM +0000, Liam Girdwood wrote:
Just had a quick look. All
Acked-by: Liam Girdwood lrg@ti.com
Applied 1-6 - I'll wait for Kukjin to check patch 7 just in case he wants it to go via his tree, there's no compile time dependency.
Thanks.
So far patch 7 (adding the dfbmcs320 platform device to gta02 mach file) hasn't been applied. Should I resent it, or do you still have it?
- Lars
On Tue, Apr 12, 2011 at 10:02:46PM +0200, Lars-Peter Clausen wrote:
So far patch 7 (adding the dfbmcs320 platform device to gta02 mach file) hasn't been applied. Should I resent it, or do you still have it?
Resend please.
Lars-Peter Clausen wrote:
On 03/07/2011 01:25 PM, Mark Brown wrote:
On Mon, Mar 07, 2011 at 11:04:38AM +0000, Liam Girdwood wrote:
Just had a quick look. All
Acked-by: Liam Girdwood lrg@ti.com
Applied 1-6 - I'll wait for Kukjin to check patch 7 just in case he wants it to go via his tree, there's no compile time dependency.
Oops, maybe I missed. Because he didn't send to me, Linux ARM Kernel mailing list or Linux Samsung SoC mailing list at that time.
Thanks.
So far patch 7 (adding the dfbmcs320 platform device to gta02 mach file) hasn't been applied. Should I resent it, or do you still have it?
Anyway, I checked Mark's applying just now. It's ok to me :)
Thanks.
Best regards, Kgene. -- Kukjin Kim kgene.kim@samsung.com, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.
participants (4)
-
Kukjin Kim
-
Lars-Peter Clausen
-
Liam Girdwood
-
Mark Brown