From 739e38eabe11d29536710f5a31764ed68947206a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 14 May 2010 00:39:26 +0200 Subject: sound: SoC: neo1973_wm8753: Move lm4857 specefic code to its own module --- sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/lm4857.c | 224 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/lm4857.h | 34 ++++++ sound/soc/s3c24xx/Kconfig | 1 + sound/soc/s3c24xx/lm4857.h | 32 ------ sound/soc/s3c24xx/neo1973_wm8753.c | 192 +------------------------------ 6 files changed, 265 insertions(+), 221 deletions(-) create mode 100644 sound/soc/codecs/lm4857.c create mode 100644 sound/soc/codecs/lm4857.h delete mode 100644 sound/soc/s3c24xx/lm4857.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1743d565e99..36678f74ca2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -261,6 +261,9 @@ config SND_SOC_WM9713 tristate # Amp +config SND_SOC_LM4857 + tristate + config SND_SOC_MAX9877 tristate diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c new file mode 100644 index 00000000000..314379706e3 --- /dev/null +++ b/sound/soc/codecs/lm4857.c @@ -0,0 +1,224 @@ +/* + * LM4857 AMP driver + * + * 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. + * + */ + +#include +#include + +#include +#include +#include + +#include "lm4857.h" + +static struct { + struct i2c_client *i2c; + uint8_t regs[4]; + uint8_t state; +} lm4857 = { + .regs = {0x00, 0x40, 0x80, 0xC0}, +}; + +static void lm4857_write_regs(void) +{ + if (!lm4857.i2c) + return; + + if (i2c_master_send(lm4857.i2c, lm4857.regs, 4) != 4) + dev_err(&lm4857_i2c->dev, "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; + + 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) +{ + uint8_t value = lm4857.regs[LM4857_CTRL] & 0x0F; + + 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) +{ + uint8_t value = ucontrol->value.integer.value[0]; + + 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 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 lm4857_controls[] = { + 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), +}; + +int lm4857_add_controls(struct snd_soc_codec *codec) +{ + return snd_soc_add_controls(codec, lm4857_controls, + ARRAY_SIZE(lm5857_controls)); +} +EXPORT_GPL(lm4857_add_controlls); + +static int __devinit lm4857_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + lm4857.i2c = client; + lm4857_write_regs(); + return 0; +} + +static int __devexit lm4857_remove(struct i2c_client *client) +{ + lm4857.i2c = NULL; + return 0; +} + +static void lm4857_shutdown(struct i2c_client *client) +{ + lm4857_regs[LM4857_CTRL] &= 0xf0; + lm4857_write_regs(); +} + +#ifdef CONFIG_PM + +static int lm4857_suspend(struct i2c_client *client, pm_message_t state) +{ + lm4857.state = lm4857_regs[LM4857_CTRL] & 0xf; + + if (lm4857.state) + lm4857_shutdown(client); + + return 0; +} + +static int lm4857_resume(struct i2c_client *dev) +{ + if (lm4857.state) { + lm4857_regs[LM4857_CTRL] |= (lm4857.state & 0x0f); + lm4857_write_regs(); + } + return 0; +} + +#else +#define lm4857_suspend NULL +#define lm4857_resume NULL +#endif + +static const struct i2c_device_id lm4857_i2c_id[] = { + { "lm4857", 0 }, + { } +}; + +static struct i2c_driver lm4857_i2c_driver = { + .driver = { + .name = "LM4857 I2C Amp", + .owner = THIS_MODULE, + }, + .probe = lm4857_probe, + .remove = __devexit_p(lm4857_remove), + .suspend = lm4857_suspend, + .resume = lm4857_resume, + .shutdown = lm4857_shutdown, + .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 "); +MODULE_DESCRIPTION("LM4857 amplifier driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/lm4857.h b/sound/soc/codecs/lm4857.h new file mode 100644 index 00000000000..a107d2f5241 --- /dev/null +++ b/sound/soc/codecs/lm4857.h @@ -0,0 +1,34 @@ +/* + * 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_ + +int lm4857_add_controls(struct snd_soc_codec *codec); + +/* 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/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 15fe57e5a23..d1ae47fbc62 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -36,6 +36,7 @@ config SND_S3C24XX_SOC_NEO1973_WM8753 depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 select SND_S3C24XX_SOC_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/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h deleted file mode 100644 index 0cf5b7011d6..00000000000 --- a/sound/soc/s3c24xx/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/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 1b0044f19e3..9001120a4dc 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -35,12 +34,11 @@ #include #include "../codecs/wm8753.h" -#include "lm4857.h" +#include "../codecs/lm4857.h" #include "s3c-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) @@ -215,83 +213,6 @@ 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), @@ -325,40 +246,6 @@ 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_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 @@ -390,8 +277,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) snd_soc_dapm_disable_pin(codec, "Call Mic"); /* add neo1973 specific controls */ - err = snd_soc_add_controls(codec, wm8753_neo1973_controls, - ARRAY_SIZE(8753_neo1973_controls)); + err = lm4857_add_controls(codec); if (err < 0) return err; @@ -400,6 +286,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) ARRAY_SIZE(dapm_routes)); snd_soc_dapm_sync(codec); + return 0; } @@ -451,79 +338,6 @@ static struct snd_soc_device neo1973_snd_devdata = { .codec_dev = &soc_codec_dev_wm8753, }; -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 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 platform_device *neo1973_snd_device; static int __init neo1973_init(void) -- cgit v1.2.3