max9759.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * MAX9759 Amplifier Driver
  4. *
  5. * Copyright (c) 2017 BayLibre, SAS.
  6. * Author: Neil Armstrong <narmstrong@baylibre.com>
  7. */
  8. #include <linux/gpio/consumer.h>
  9. #include <linux/module.h>
  10. #include <sound/soc.h>
  11. #include <sound/soc-dapm.h>
  12. #include <sound/tlv.h>
  13. #define DRV_NAME "max9759"
  14. struct max9759 {
  15. struct gpio_desc *gpiod_shutdown;
  16. struct gpio_desc *gpiod_mute;
  17. struct gpio_descs *gpiod_gain;
  18. bool is_mute;
  19. unsigned int gain;
  20. };
  21. static int pga_event(struct snd_soc_dapm_widget *w,
  22. struct snd_kcontrol *control, int event)
  23. {
  24. struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
  25. struct max9759 *priv = snd_soc_component_get_drvdata(c);
  26. if (SND_SOC_DAPM_EVENT_ON(event))
  27. gpiod_set_value_cansleep(priv->gpiod_shutdown, 0);
  28. else
  29. gpiod_set_value_cansleep(priv->gpiod_shutdown, 1);
  30. return 0;
  31. }
  32. /* From 6dB to 24dB in steps of 6dB */
  33. static const DECLARE_TLV_DB_SCALE(speaker_gain_tlv, 600, 600, 0);
  34. static int speaker_gain_control_get(struct snd_kcontrol *kcontrol,
  35. struct snd_ctl_elem_value *ucontrol)
  36. {
  37. struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
  38. struct max9759 *priv = snd_soc_component_get_drvdata(c);
  39. ucontrol->value.integer.value[0] = priv->gain;
  40. return 0;
  41. }
  42. static const bool speaker_gain_table[4][2] = {
  43. /* G1, G2 */
  44. {true, true}, /* +6dB */
  45. {false, true}, /* +12dB */
  46. {true, false}, /* +18dB */
  47. {false, false}, /* +24dB */
  48. };
  49. static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
  50. struct snd_ctl_elem_value *ucontrol)
  51. {
  52. struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
  53. struct max9759 *priv = snd_soc_component_get_drvdata(c);
  54. if (ucontrol->value.integer.value[0] < 0 ||
  55. ucontrol->value.integer.value[0] > 3)
  56. return -EINVAL;
  57. priv->gain = ucontrol->value.integer.value[0];
  58. /* G1 */
  59. gpiod_set_value_cansleep(priv->gpiod_gain->desc[0],
  60. speaker_gain_table[priv->gain][0]);
  61. /* G2 */
  62. gpiod_set_value_cansleep(priv->gpiod_gain->desc[1],
  63. speaker_gain_table[priv->gain][1]);
  64. return 1;
  65. }
  66. static int speaker_mute_get(struct snd_kcontrol *kcontrol,
  67. struct snd_ctl_elem_value *ucontrol)
  68. {
  69. struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
  70. struct max9759 *priv = snd_soc_component_get_drvdata(c);
  71. ucontrol->value.integer.value[0] = !priv->is_mute;
  72. return 0;
  73. }
  74. static int speaker_mute_put(struct snd_kcontrol *kcontrol,
  75. struct snd_ctl_elem_value *ucontrol)
  76. {
  77. struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
  78. struct max9759 *priv = snd_soc_component_get_drvdata(c);
  79. priv->is_mute = !ucontrol->value.integer.value[0];
  80. gpiod_set_value_cansleep(priv->gpiod_mute, priv->is_mute);
  81. return 1;
  82. }
  83. static const struct snd_kcontrol_new max9759_dapm_controls[] = {
  84. SOC_SINGLE_EXT_TLV("Speaker Gain Volume", 0, 0, 3, 0,
  85. speaker_gain_control_get, speaker_gain_control_put,
  86. speaker_gain_tlv),
  87. SOC_SINGLE_BOOL_EXT("Playback Switch", 0,
  88. speaker_mute_get, speaker_mute_put),
  89. };
  90. static const struct snd_soc_dapm_widget max9759_dapm_widgets[] = {
  91. SND_SOC_DAPM_INPUT("INL"),
  92. SND_SOC_DAPM_INPUT("INR"),
  93. SND_SOC_DAPM_PGA_E("PGA", SND_SOC_NOPM, 0, 0, NULL, 0, pga_event,
  94. (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)),
  95. SND_SOC_DAPM_OUTPUT("OUTL"),
  96. SND_SOC_DAPM_OUTPUT("OUTR"),
  97. };
  98. static const struct snd_soc_dapm_route max9759_dapm_routes[] = {
  99. { "PGA", NULL, "INL" },
  100. { "PGA", NULL, "INR" },
  101. { "OUTL", NULL, "PGA" },
  102. { "OUTR", NULL, "PGA" },
  103. };
  104. static const struct snd_soc_component_driver max9759_component_driver = {
  105. .controls = max9759_dapm_controls,
  106. .num_controls = ARRAY_SIZE(max9759_dapm_controls),
  107. .dapm_widgets = max9759_dapm_widgets,
  108. .num_dapm_widgets = ARRAY_SIZE(max9759_dapm_widgets),
  109. .dapm_routes = max9759_dapm_routes,
  110. .num_dapm_routes = ARRAY_SIZE(max9759_dapm_routes),
  111. };
  112. static int max9759_probe(struct platform_device *pdev)
  113. {
  114. struct device *dev = &pdev->dev;
  115. struct max9759 *priv;
  116. int err;
  117. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  118. if (!priv)
  119. return -ENOMEM;
  120. platform_set_drvdata(pdev, priv);
  121. priv->gpiod_shutdown = devm_gpiod_get(dev, "shutdown", GPIOD_OUT_HIGH);
  122. if (IS_ERR(priv->gpiod_shutdown)) {
  123. err = PTR_ERR(priv->gpiod_shutdown);
  124. if (err != -EPROBE_DEFER)
  125. dev_err(dev, "Failed to get 'shutdown' gpio: %d", err);
  126. return err;
  127. }
  128. priv->gpiod_mute = devm_gpiod_get(dev, "mute", GPIOD_OUT_HIGH);
  129. if (IS_ERR(priv->gpiod_mute)) {
  130. err = PTR_ERR(priv->gpiod_mute);
  131. if (err != -EPROBE_DEFER)
  132. dev_err(dev, "Failed to get 'mute' gpio: %d", err);
  133. return err;
  134. }
  135. priv->is_mute = true;
  136. priv->gpiod_gain = devm_gpiod_get_array(dev, "gain", GPIOD_OUT_HIGH);
  137. if (IS_ERR(priv->gpiod_gain)) {
  138. err = PTR_ERR(priv->gpiod_gain);
  139. if (err != -EPROBE_DEFER)
  140. dev_err(dev, "Failed to get 'gain' gpios: %d", err);
  141. return err;
  142. }
  143. priv->gain = 0;
  144. if (priv->gpiod_gain->ndescs != 2) {
  145. dev_err(dev, "Invalid 'gain' gpios count: %d",
  146. priv->gpiod_gain->ndescs);
  147. return -EINVAL;
  148. }
  149. return devm_snd_soc_register_component(dev, &max9759_component_driver,
  150. NULL, 0);
  151. }
  152. #ifdef CONFIG_OF
  153. static const struct of_device_id max9759_ids[] = {
  154. { .compatible = "maxim,max9759", },
  155. { }
  156. };
  157. MODULE_DEVICE_TABLE(of, max9759_ids);
  158. #endif
  159. static struct platform_driver max9759_driver = {
  160. .driver = {
  161. .name = DRV_NAME,
  162. .of_match_table = of_match_ptr(max9759_ids),
  163. },
  164. .probe = max9759_probe,
  165. };
  166. module_platform_driver(max9759_driver);
  167. MODULE_DESCRIPTION("ASoC MAX9759 amplifier driver");
  168. MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
  169. MODULE_LICENSE("GPL");