Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * MAX9759 Amplifier Driver
0004  *
0005  * Copyright (c) 2017 BayLibre, SAS.
0006  * Author: Neil Armstrong <narmstrong@baylibre.com>
0007  */
0008 
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/module.h>
0011 #include <sound/soc.h>
0012 #include <sound/soc-dapm.h>
0013 #include <sound/tlv.h>
0014 
0015 #define DRV_NAME "max9759"
0016 
0017 struct max9759 {
0018     struct gpio_desc *gpiod_shutdown;
0019     struct gpio_desc *gpiod_mute;
0020     struct gpio_descs *gpiod_gain;
0021     bool is_mute;
0022     unsigned int gain;
0023 };
0024 
0025 static int pga_event(struct snd_soc_dapm_widget *w,
0026              struct snd_kcontrol *control, int event)
0027 {
0028     struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
0029     struct max9759 *priv = snd_soc_component_get_drvdata(c);
0030 
0031     if (SND_SOC_DAPM_EVENT_ON(event))
0032         gpiod_set_value_cansleep(priv->gpiod_shutdown, 0);
0033     else
0034         gpiod_set_value_cansleep(priv->gpiod_shutdown, 1);
0035 
0036     return 0;
0037 }
0038 
0039 /* From 6dB to 24dB in steps of 6dB */
0040 static const DECLARE_TLV_DB_SCALE(speaker_gain_tlv, 600, 600, 0);
0041 
0042 static int speaker_gain_control_get(struct snd_kcontrol *kcontrol,
0043                     struct snd_ctl_elem_value *ucontrol)
0044 {
0045     struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
0046     struct max9759 *priv = snd_soc_component_get_drvdata(c);
0047 
0048     ucontrol->value.integer.value[0] = priv->gain;
0049 
0050     return 0;
0051 }
0052 
0053 static const bool speaker_gain_table[4][2] = {
0054     /* G1, G2 */
0055     {true, true},   /* +6dB */
0056     {false, true},  /* +12dB */
0057     {true, false},  /* +18dB */
0058     {false, false}, /* +24dB */
0059 };
0060 
0061 static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
0062                     struct snd_ctl_elem_value *ucontrol)
0063 {
0064     struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
0065     struct max9759 *priv = snd_soc_component_get_drvdata(c);
0066 
0067     if (ucontrol->value.integer.value[0] < 0 ||
0068         ucontrol->value.integer.value[0] > 3)
0069         return -EINVAL;
0070 
0071     priv->gain = ucontrol->value.integer.value[0];
0072 
0073     /* G1 */
0074     gpiod_set_value_cansleep(priv->gpiod_gain->desc[0],
0075                  speaker_gain_table[priv->gain][0]);
0076     /* G2 */
0077     gpiod_set_value_cansleep(priv->gpiod_gain->desc[1],
0078                  speaker_gain_table[priv->gain][1]);
0079 
0080     return 1;
0081 }
0082 
0083 static int speaker_mute_get(struct snd_kcontrol *kcontrol,
0084                 struct snd_ctl_elem_value *ucontrol)
0085 {
0086     struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
0087     struct max9759 *priv = snd_soc_component_get_drvdata(c);
0088 
0089     ucontrol->value.integer.value[0] = !priv->is_mute;
0090 
0091     return 0;
0092 }
0093 
0094 static int speaker_mute_put(struct snd_kcontrol *kcontrol,
0095                 struct snd_ctl_elem_value *ucontrol)
0096 {
0097     struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
0098     struct max9759 *priv = snd_soc_component_get_drvdata(c);
0099 
0100     priv->is_mute = !ucontrol->value.integer.value[0];
0101 
0102     gpiod_set_value_cansleep(priv->gpiod_mute, priv->is_mute);
0103 
0104     return 1;
0105 }
0106 
0107 static const struct snd_kcontrol_new max9759_dapm_controls[] = {
0108     SOC_SINGLE_EXT_TLV("Speaker Gain Volume", 0, 0, 3, 0,
0109                speaker_gain_control_get, speaker_gain_control_put,
0110                speaker_gain_tlv),
0111     SOC_SINGLE_BOOL_EXT("Playback Switch", 0,
0112                 speaker_mute_get, speaker_mute_put),
0113 };
0114 
0115 static const struct snd_soc_dapm_widget max9759_dapm_widgets[] = {
0116     SND_SOC_DAPM_INPUT("INL"),
0117     SND_SOC_DAPM_INPUT("INR"),
0118     SND_SOC_DAPM_PGA_E("PGA", SND_SOC_NOPM, 0, 0, NULL, 0, pga_event,
0119                (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
0120     SND_SOC_DAPM_OUTPUT("OUTL"),
0121     SND_SOC_DAPM_OUTPUT("OUTR"),
0122 };
0123 
0124 static const struct snd_soc_dapm_route max9759_dapm_routes[] = {
0125     { "PGA", NULL, "INL" },
0126     { "PGA", NULL, "INR" },
0127     { "OUTL", NULL, "PGA" },
0128     { "OUTR", NULL, "PGA" },
0129 };
0130 
0131 static const struct snd_soc_component_driver max9759_component_driver = {
0132     .controls       = max9759_dapm_controls,
0133     .num_controls       = ARRAY_SIZE(max9759_dapm_controls),
0134     .dapm_widgets       = max9759_dapm_widgets,
0135     .num_dapm_widgets   = ARRAY_SIZE(max9759_dapm_widgets),
0136     .dapm_routes        = max9759_dapm_routes,
0137     .num_dapm_routes    = ARRAY_SIZE(max9759_dapm_routes),
0138 };
0139 
0140 static int max9759_probe(struct platform_device *pdev)
0141 {
0142     struct device *dev = &pdev->dev;
0143     struct max9759 *priv;
0144 
0145     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0146     if (!priv)
0147         return -ENOMEM;
0148 
0149     platform_set_drvdata(pdev, priv);
0150 
0151     priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_HIGH);
0152     if (IS_ERR(priv->gpiod_shutdown))
0153         return dev_err_probe(dev, PTR_ERR(priv->gpiod_shutdown),
0154                      "Failed to get 'shutdown' gpio");
0155 
0156     priv->gpiod_mute = devm_gpiod_get(dev, "mute", GPIOD_OUT_HIGH);
0157     if (IS_ERR(priv->gpiod_mute))
0158         return dev_err_probe(dev, PTR_ERR(priv->gpiod_mute),
0159                      "Failed to get 'mute' gpio");
0160     priv->is_mute = true;
0161 
0162     priv->gpiod_gain = devm_gpiod_get_array(dev, "gain", GPIOD_OUT_HIGH);
0163     if (IS_ERR(priv->gpiod_gain))
0164         return dev_err_probe(dev, PTR_ERR(priv->gpiod_gain),
0165                      "Failed to get 'gain' gpios");
0166     priv->gain = 0;
0167 
0168     if (priv->gpiod_gain->ndescs != 2) {
0169         dev_err(dev, "Invalid 'gain' gpios count: %d",
0170             priv->gpiod_gain->ndescs);
0171         return -EINVAL;
0172     }
0173 
0174     return devm_snd_soc_register_component(dev, &max9759_component_driver,
0175                            NULL, 0);
0176 }
0177 
0178 #ifdef CONFIG_OF
0179 static const struct of_device_id max9759_ids[] = {
0180     { .compatible = "maxim,max9759", },
0181     { }
0182 };
0183 MODULE_DEVICE_TABLE(of, max9759_ids);
0184 #endif
0185 
0186 static struct platform_driver max9759_driver = {
0187     .driver = {
0188         .name = DRV_NAME,
0189         .of_match_table = of_match_ptr(max9759_ids),
0190     },
0191     .probe = max9759_probe,
0192 };
0193 
0194 module_platform_driver(max9759_driver);
0195 
0196 MODULE_DESCRIPTION("ASoC MAX9759 amplifier driver");
0197 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0198 MODULE_LICENSE("GPL");