cregit-Linux how code gets into the kernel

Release 4.7 sound/soc/codecs/wl1273.c

Directory: sound/soc/codecs
/*
 * ALSA SoC WL1273 codec driver
 *
 * Author:      Matti Aaltonen, <matti.j.aaltonen@nokia.com>
 *
 * Copyright:   (C) 2010, 2011 Nokia Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <linux/mfd/wl1273-core.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>

#include "wl1273.h"





enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };

/* codec private data */

struct wl1273_priv {
	
enum wl1273_mode mode;
	
struct wl1273_core *core;
	
unsigned int channels;
};


static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core, int rate, int width) { struct device *dev = &core->client->dev; int r = 0; u16 mode; dev_dbg(dev, "rate: %d\n", rate); dev_dbg(dev, "width: %d\n", width); mutex_lock(&core->lock); mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE; switch (rate) { case 48000: mode |= WL1273_IS2_RATE_48K; break; case 44100: mode |= WL1273_IS2_RATE_44_1K; break; case 32000: mode |= WL1273_IS2_RATE_32K; break; case 22050: mode |= WL1273_IS2_RATE_22_05K; break; case 16000: mode |= WL1273_IS2_RATE_16K; break; case 12000: mode |= WL1273_IS2_RATE_12K; break; case 11025: mode |= WL1273_IS2_RATE_11_025; break; case 8000: mode |= WL1273_IS2_RATE_8K; break; default: dev_err(dev, "Sampling rate: %d not supported\n", rate); r = -EINVAL; goto out; } switch (width) { case 16: mode |= WL1273_IS2_WIDTH_32; break; case 20: mode |= WL1273_IS2_WIDTH_40; break; case 24: mode |= WL1273_IS2_WIDTH_48; break; case 25: mode |= WL1273_IS2_WIDTH_50; break; case 30: mode |= WL1273_IS2_WIDTH_60; break; case 32: mode |= WL1273_IS2_WIDTH_64; break; case 40: mode |= WL1273_IS2_WIDTH_80; break; case 48: mode |= WL1273_IS2_WIDTH_96; break; case 64: mode |= WL1273_IS2_WIDTH_128; break; default: dev_err(dev, "Data width: %d not supported\n", width); r = -EINVAL; goto out; } dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n", WL1273_I2S_DEF_MODE); dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode); dev_dbg(dev, "mode: 0x%04x\n", mode); if (core->i2s_mode != mode) { r = core->write(core, WL1273_I2S_MODE_CONFIG_SET, mode); if (r) goto out; core->i2s_mode = mode; r = core->write(core, WL1273_AUDIO_ENABLE, WL1273_AUDIO_ENABLE_I2S); if (r) goto out; } out: mutex_unlock(&core->lock); return r; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen357100.00%2100.00%
Total357100.00%2100.00%


static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core, int channel_number) { struct device *dev = &core->client->dev; int r = 0; dev_dbg(dev, "%s\n", __func__); mutex_lock(&core->lock); if (core->channel_number == channel_number) goto out; if (channel_number == 1 && core->mode == WL1273_MODE_RX) r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); else if (channel_number == 1 && core->mode == WL1273_MODE_TX) r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); else if (channel_number == 2 && core->mode == WL1273_MODE_RX) r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); else if (channel_number == 2 && core->mode == WL1273_MODE_TX) r = core->write(core, WL1273_MONO_SET, WL1273_TX_STEREO); else r = -EINVAL; out: mutex_unlock(&core->lock); return r; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen181100.00%2100.00%
Total181100.00%2100.00%


static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); ucontrol->value.enumerated.item[0] = wl1273->mode; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen5194.44%133.33%
takashi iwaitakashi iwai23.70%133.33%
lars-peter clausenlars-peter clausen11.85%133.33%
Total54100.00%3100.00%

/* * TODO: Implement the audio routing in the driver. Now this control * only indicates the setting that has been done elsewhere (in the user * space). */ static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); if (wl1273->mode == ucontrol->value.enumerated.item[0]) return 0; /* Do not allow changes while stream is running */ if (snd_soc_codec_is_active(codec)) return -EPERM; if (ucontrol->value.enumerated.item[0] >= ARRAY_SIZE(wl1273_audio_route)) return -EINVAL; wl1273->mode = ucontrol->value.enumerated.item[0]; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen9890.74%240.00%
takashi iwaitakashi iwai65.56%120.00%
lars-peter clausenlars-peter clausen43.70%240.00%
Total108100.00%5100.00%

static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route);
static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: enter.\n", __func__); ucontrol->value.enumerated.item[0] = wl1273->core->audio_mode; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen6495.52%133.33%
takashi iwaitakashi iwai22.99%133.33%
lars-peter clausenlars-peter clausen11.49%133.33%
Total67100.00%3100.00%


static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); int val, r = 0; dev_dbg(codec->dev, "%s: enter.\n", __func__); val = ucontrol->value.enumerated.item[0]; if (wl1273->core->audio_mode == val) return 0; r = wl1273->core->set_audio(wl1273->core, val); if (r < 0) return r; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen10497.20%250.00%
takashi iwaitakashi iwai21.87%125.00%
lars-peter clausenlars-peter clausen10.93%125.00%
Total107100.00%4100.00%

static const char * const wl1273_audio_strings[] = { "Digital", "Analog" }; static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings);
static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: enter.\n", __func__); ucontrol->value.integer.value[0] = wl1273->core->volume; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen6698.51%150.00%
lars-peter clausenlars-peter clausen11.49%150.00%
Total67100.00%2100.00%


static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); int r; dev_dbg(codec->dev, "%s: enter.\n", __func__); r = wl1273->core->set_volume(wl1273->core, ucontrol->value.integer.value[0]); if (r) return r; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen8398.81%266.67%
lars-peter clausenlars-peter clausen11.19%133.33%
Total84100.00%3100.00%

static const struct snd_kcontrol_new wl1273_controls[] = { SOC_ENUM_EXT("Codec Mode", wl1273_enum, snd_wl1273_get_audio_route, snd_wl1273_set_audio_route), SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum, snd_wl1273_fm_audio_get, snd_wl1273_fm_audio_put), SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0, snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put), }; static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = { SND_SOC_DAPM_INPUT("RX"), SND_SOC_DAPM_OUTPUT("TX"), }; static const struct snd_soc_dapm_route wl1273_dapm_routes[] = { { "Capture", NULL, "RX" }, { "TX", NULL, "Playback" }, };
static int wl1273_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); switch (wl1273->mode) { case WL1273_MODE_BT: snd_pcm_hw_constraint_single(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, 8000); snd_pcm_hw_constraint_single(substream->runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 1); break; case WL1273_MODE_FM_RX: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pr_err("Cannot play in RX mode.\n"); return -EINVAL; } break; case WL1273_MODE_FM_TX: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { pr_err("Cannot capture in TX mode.\n"); return -EINVAL; } break; default: return -EINVAL; break; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen12197.58%133.33%
lars-peter clausenlars-peter clausen21.61%133.33%
mark brownmark brown10.81%133.33%
Total124100.00%3100.00%


static int wl1273_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(dai->codec); struct wl1273_core *core = wl1273->core; unsigned int rate, width, r; if (params_width(params) != 16) { dev_err(dai->dev, "%d bits/sample not supported\n", params_width(params)); return -EINVAL; } rate = params_rate(params); width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; if (wl1273->mode == WL1273_MODE_BT) { if (rate != 8000) { pr_err("Rate %d not supported.\n", params_rate(params)); return -EINVAL; } if (params_channels(params) != 1) { pr_err("Only mono supported.\n"); return -EINVAL; } return 0; } if (wl1273->mode == WL1273_MODE_FM_TX && substream->stream == SNDRV_PCM_STREAM_CAPTURE) { pr_err("Only playback supported with TX.\n"); return -EINVAL; } if (wl1273->mode == WL1273_MODE_FM_RX && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pr_err("Only capture supported with RX.\n"); return -EINVAL; } if (wl1273->mode != WL1273_MODE_FM_RX && wl1273->mode != WL1273_MODE_FM_TX) { pr_err("Unexpected mode: %d.\n", wl1273->mode); return -EINVAL; } r = snd_wl1273_fm_set_i2s_mode(core, rate, width); if (r) return r; wl1273->channels = params_channels(params); r = snd_wl1273_fm_set_channel_number(core, wl1273->channels); if (r) return r; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen26695.34%133.33%
mark brownmark brown134.66%266.67%
Total279100.00%3100.00%

static const struct snd_soc_dai_ops wl1273_dai_ops = { .startup = wl1273_startup, .hw_params = wl1273_hw_params, }; static struct snd_soc_dai_driver wl1273_dai = { .name = "wl1273-fm", .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE}, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE}, .ops = &wl1273_dai_ops, }; /* Audio interface format for the soc_card driver */
int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt) { struct wl1273_priv *wl1273; if (codec == NULL || fmt == NULL) return -EINVAL; wl1273 = snd_soc_codec_get_drvdata(codec); switch (wl1273->mode) { case WL1273_MODE_FM_RX: case WL1273_MODE_FM_TX: *fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM; break; case WL1273_MODE_BT: *fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM; break; default: return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen86100.00%1100.00%
Total86100.00%1100.00%

EXPORT_SYMBOL_GPL(wl1273_get_format);
static int wl1273_probe(struct snd_soc_codec *codec) { struct wl1273_core **core = codec->dev->platform_data; struct wl1273_priv *wl1273; dev_dbg(codec->dev, "%s.\n", __func__); if (!core) { dev_err(codec->dev, "Platform data is missing.\n"); return -EINVAL; } wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL); if (!wl1273) return -ENOMEM; wl1273->mode = WL1273_MODE_BT; wl1273->core = *core; snd_soc_codec_set_drvdata(codec, wl1273); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen10096.15%125.00%
samuel ortizsamuel ortiz21.92%125.00%
sachin kamatsachin kamat10.96%125.00%
lars-peter clausenlars-peter clausen10.96%125.00%
Total104100.00%4100.00%


static int wl1273_remove(struct snd_soc_codec *codec) { struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s\n", __func__); kfree(wl1273); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen40100.00%1100.00%
Total40100.00%1100.00%

static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { .probe = wl1273_probe, .remove = wl1273_remove, .controls = wl1273_controls, .num_controls = ARRAY_SIZE(wl1273_controls), .dapm_widgets = wl1273_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), .dapm_routes = wl1273_dapm_routes, .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes), };
static int wl1273_platform_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273, &wl1273_dai, 1); }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen28100.00%1100.00%
Total28100.00%1100.00%


static int wl1273_platform_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen22100.00%1100.00%
Total22100.00%1100.00%

MODULE_ALIAS("platform:wl1273-codec"); static struct platform_driver wl1273_platform_driver = { .driver = { .name = "wl1273-codec", }, .probe = wl1273_platform_probe, .remove = wl1273_platform_remove, }; module_platform_driver(wl1273_platform_driver); MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>"); MODULE_DESCRIPTION("ASoC WL1273 codec driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
matti j. aaltonenmatti j. aaltonen197593.56%421.05%
mark brownmark brown854.03%421.05%
lars-peter clausenlars-peter clausen261.23%526.32%
takashi iwaitakashi iwai180.85%210.53%
paul gortmakerpaul gortmaker30.14%15.26%
samuel ortizsamuel ortiz20.09%15.26%
jarkko nikulajarkko nikula10.05%15.26%
sachin kamatsachin kamat10.05%15.26%
Total2111100.00%19100.00%
Directory: sound/soc/codecs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}