0001
0002
0003
0004
0005
0006
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
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
0055 {true, true},
0056 {false, true},
0057 {true, false},
0058 {false, false},
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
0074 gpiod_set_value_cansleep(priv->gpiod_gain->desc[0],
0075 speaker_gain_table[priv->gain][0]);
0076
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");