diff options
Diffstat (limited to 'sound/soc/codecs/ssm2518.c')
| -rw-r--r-- | sound/soc/codecs/ssm2518.c | 180 |
1 files changed, 69 insertions, 111 deletions
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 95aed552139a..9008e5416004 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -1,20 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SSM2518 amplifier audio driver * * Copyright 2013 Analog Devices Inc. * Author: Lars-Peter Clausen <lars@metafoo.de> - * - * Licensed under the GPL-2. */ +#include <linux/err.h> #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> -#include <linux/platform_data/ssm2518.h> +#include <linux/gpio/consumer.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -115,7 +113,7 @@ struct ssm2518 { unsigned int sysclk; const struct snd_pcm_hw_constraint_list *constraints; - int enable_gpio; + struct gpio_desc *enable_gpio; }; static const struct reg_default ssm2518_reg_defaults[] = { @@ -169,19 +167,19 @@ static const char * const ssm2518_drc_hold_time_text[] = { "682.24 ms", "1364 ms", }; -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); -static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, +static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text); static const struct snd_kcontrol_new ssm2518_snd_controls[] = { @@ -309,7 +307,7 @@ static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = { .count = ARRAY_SIZE(ssm2518_rates_12288000), }; -static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, +static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, unsigned int rate) { const unsigned int *sysclks = NULL; @@ -336,8 +334,8 @@ static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, static int ssm2518_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component); unsigned int rate = params_rate(params); unsigned int ctrl1, ctrl1_mask; int mcs; @@ -361,11 +359,11 @@ static int ssm2518_hw_params(struct snd_pcm_substream *substream, return -EINVAL; if (ssm2518->right_j) { - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_16BIT; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT; break; default: @@ -389,9 +387,9 @@ static int ssm2518_hw_params(struct snd_pcm_substream *substream, SSM2518_POWER1_MCS_MASK, mcs << 1); } -static int ssm2518_mute(struct snd_soc_dai *dai, int mute) +static int ssm2518_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec); + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component); unsigned int val; if (mute) @@ -405,13 +403,13 @@ static int ssm2518_mute(struct snd_soc_dai *dai, int mute) static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec); + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component); unsigned int ctrl1 = 0, ctrl2 = 0; bool invert_fclk; int ret; - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -484,8 +482,8 @@ static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable) regcache_mark_dirty(ssm2518->regmap); } - if (gpio_is_valid(ssm2518->enable_gpio)) - gpio_set_value(ssm2518->enable_gpio, enable); + if (ssm2518->enable_gpio) + gpiod_set_value_cansleep(ssm2518->enable_gpio, enable); regcache_cache_only(ssm2518->regmap, !enable); @@ -498,10 +496,11 @@ static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable) return ret; } -static int ssm2518_set_bias_level(struct snd_soc_codec *codec, +static int ssm2518_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec); + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret = 0; switch (level) { @@ -510,7 +509,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) ret = ssm2518_set_power(ssm2518, true); break; case SND_SOC_BIAS_OFF: @@ -518,18 +517,13 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec, break; } - if (ret) - return ret; - - codec->dapm.bias_level = level; - - return 0; + return ret; } static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int width) { - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec); + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component); unsigned int ctrl1, ctrl2; int left_slot, right_slot; int ret; @@ -549,13 +543,13 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, right_slot = 0; } else { /* We assume the left channel < right channel */ - left_slot = ffs(tx_mask); - tx_mask &= ~(1 << tx_mask); + left_slot = __ffs(tx_mask); + tx_mask &= ~(1 << left_slot); if (tx_mask == 0) { right_slot = left_slot; } else { - right_slot = ffs(tx_mask); - tx_mask &= ~(1 << tx_mask); + right_slot = __ffs(tx_mask); + tx_mask &= ~(1 << right_slot); } } @@ -614,7 +608,7 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, static int ssm2518_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec); + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(dai->component); if (ssm2518->constraints) snd_pcm_hw_constraint_list(substream->runtime, 0, @@ -629,9 +623,10 @@ static int ssm2518_startup(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops ssm2518_dai_ops = { .startup = ssm2518_startup, .hw_params = ssm2518_hw_params, - .digital_mute = ssm2518_mute, + .mute_stream = ssm2518_mute, .set_fmt = ssm2518_set_dai_fmt, .set_tdm_slot = ssm2518_set_tdm_slot, + .no_capture_mute = 1, }; static struct snd_soc_dai_driver ssm2518_dai = { @@ -646,31 +641,10 @@ static struct snd_soc_dai_driver ssm2518_dai = { .ops = &ssm2518_dai_ops, }; -static int ssm2518_probe(struct snd_soc_codec *codec) -{ - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec); - int ret; - - codec->control_data = ssm2518->regmap; - ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - - return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int ssm2518_remove(struct snd_soc_codec *codec) -{ - ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, +static int ssm2518_set_sysclk(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir) { - struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec); + struct ssm2518 *ssm2518 = snd_soc_component_get_drvdata(component); unsigned int val; if (clk_id != SSM2518_SYSCLK) @@ -736,42 +710,32 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, SSM2518_POWER1_NO_BCLK, val); } -static struct snd_soc_codec_driver ssm2518_codec_driver = { - .probe = ssm2518_probe, - .remove = ssm2518_remove, - .set_bias_level = ssm2518_set_bias_level, - .set_sysclk = ssm2518_set_sysclk, - .idle_bias_off = true, - - .controls = ssm2518_snd_controls, - .num_controls = ARRAY_SIZE(ssm2518_snd_controls), - .dapm_widgets = ssm2518_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets), - .dapm_routes = ssm2518_routes, - .num_dapm_routes = ARRAY_SIZE(ssm2518_routes), +static const struct snd_soc_component_driver ssm2518_component_driver = { + .set_bias_level = ssm2518_set_bias_level, + .set_sysclk = ssm2518_set_sysclk, + .controls = ssm2518_snd_controls, + .num_controls = ARRAY_SIZE(ssm2518_snd_controls), + .dapm_widgets = ssm2518_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets), + .dapm_routes = ssm2518_routes, + .num_dapm_routes = ARRAY_SIZE(ssm2518_routes), + .use_pmdown_time = 1, + .endianness = 1, }; -static bool ssm2518_register_volatile(struct device *dev, unsigned int reg) -{ - return false; -} - static const struct regmap_config ssm2518_regmap_config = { .val_bits = 8, .reg_bits = 8, .max_register = SSM2518_REG_DRC_9, - .volatile_reg = ssm2518_register_volatile, .cache_type = REGCACHE_RBTREE, .reg_defaults = ssm2518_reg_defaults, .num_reg_defaults = ARRAY_SIZE(ssm2518_reg_defaults), }; -static int ssm2518_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int ssm2518_i2c_probe(struct i2c_client *i2c) { - struct ssm2518_platform_data *pdata = i2c->dev.platform_data; struct ssm2518 *ssm2518; int ret; @@ -779,22 +743,14 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c, if (ssm2518 == NULL) return -ENOMEM; - if (pdata) { - ssm2518->enable_gpio = pdata->enable_gpio; - } else if (i2c->dev.of_node) { - ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0); - if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT) - return ssm2518->enable_gpio; - } else { - ssm2518->enable_gpio = -1; - } + /* Start with enabling the chip */ + ssm2518->enable_gpio = devm_gpiod_get_optional(&i2c->dev, NULL, + GPIOD_OUT_HIGH); + ret = PTR_ERR_OR_ZERO(ssm2518->enable_gpio); + if (ret) + return ret; - if (gpio_is_valid(ssm2518->enable_gpio)) { - ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio, - GPIOF_OUT_INIT_HIGH, "SSM2518 nSD"); - if (ret) - return ret; - } + gpiod_set_consumer_name(ssm2518->enable_gpio, "SSM2518 nSD"); i2c_set_clientdata(i2c, ssm2518); @@ -824,18 +780,21 @@ static int ssm2518_i2c_probe(struct i2c_client *i2c, if (ret) return ret; - return snd_soc_register_codec(&i2c->dev, &ssm2518_codec_driver, + return devm_snd_soc_register_component(&i2c->dev, + &ssm2518_component_driver, &ssm2518_dai, 1); } -static int ssm2518_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - return 0; -} +#ifdef CONFIG_OF +static const struct of_device_id ssm2518_dt_ids[] = { + { .compatible = "adi,ssm2518", }, + { } +}; +MODULE_DEVICE_TABLE(of, ssm2518_dt_ids); +#endif static const struct i2c_device_id ssm2518_i2c_ids[] = { - { "ssm2518", 0 }, + { "ssm2518" }, { } }; MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids); @@ -843,10 +802,9 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids); static struct i2c_driver ssm2518_driver = { .driver = { .name = "ssm2518", - .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ssm2518_dt_ids), }, .probe = ssm2518_i2c_probe, - .remove = ssm2518_i2c_remove, .id_table = ssm2518_i2c_ids, }; module_i2c_driver(ssm2518_driver); |
