1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * LM4857 AMP driver 4 * 5 * Copyright 2007 Wolfson Microelectronics PLC. 6 * Author: Graeme Gregory 7 * graeme.gregory@wolfsonmicro.com 8 * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> 9 */ 10 11 #include <linux/init.h> 12 #include <linux/module.h> 13 #include <linux/i2c.h> 14 #include <linux/regmap.h> 15 #include <linux/slab.h> 16 17 #include <sound/core.h> 18 #include <sound/soc.h> 19 #include <sound/tlv.h> 20 21 static const struct reg_default lm4857_default_regs[] = { 22 { 0x0, 0x00 }, 23 { 0x1, 0x00 }, 24 { 0x2, 0x00 }, 25 { 0x3, 0x00 }, 26 }; 27 28 /* The register offsets in the cache array */ 29 #define LM4857_MVOL 0 30 #define LM4857_LVOL 1 31 #define LM4857_RVOL 2 32 #define LM4857_CTRL 3 33 34 /* the shifts required to set these bits */ 35 #define LM4857_3D 5 36 #define LM4857_WAKEUP 5 37 #define LM4857_EPGAIN 4 38 39 static const unsigned int lm4857_mode_values[] = { 40 0, 41 6, 42 7, 43 8, 44 9, 45 }; 46 47 static const char * const lm4857_mode_texts[] = { 48 "Off", 49 "Earpiece", 50 "Loudspeaker", 51 "Loudspeaker + Headphone", 52 "Headphone", 53 }; 54 55 static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum, 56 LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values); 57 58 static const struct snd_kcontrol_new lm4857_mode_ctrl = 59 SOC_DAPM_ENUM("Mode", lm4857_mode_enum); 60 61 static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { 62 SND_SOC_DAPM_INPUT("IN"), 63 64 SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl), 65 66 SND_SOC_DAPM_OUTPUT("LS"), 67 SND_SOC_DAPM_OUTPUT("HP"), 68 SND_SOC_DAPM_OUTPUT("EP"), 69 }; 70 71 static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); 72 static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); 73 74 static const struct snd_kcontrol_new lm4857_controls[] = { 75 SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0, 76 stereo_tlv), 77 SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0, 78 stereo_tlv), 79 SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0, 80 mono_tlv), 81 SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0), 82 SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0), 83 SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL, 84 LM4857_WAKEUP, 1, 0), 85 SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, 86 LM4857_EPGAIN, 1, 0), 87 }; 88 89 static const struct snd_soc_dapm_route lm4857_routes[] = { 90 { "Mode", NULL, "IN" }, 91 { "LS", "Loudspeaker", "Mode" }, 92 { "LS", "Loudspeaker + Headphone", "Mode" }, 93 { "HP", "Headphone", "Mode" }, 94 { "HP", "Loudspeaker + Headphone", "Mode" }, 95 { "EP", "Earpiece", "Mode" }, 96 }; 97 98 static const struct snd_soc_component_driver lm4857_component_driver = { 99 .controls = lm4857_controls, 100 .num_controls = ARRAY_SIZE(lm4857_controls), 101 .dapm_widgets = lm4857_dapm_widgets, 102 .num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets), 103 .dapm_routes = lm4857_routes, 104 .num_dapm_routes = ARRAY_SIZE(lm4857_routes), 105 }; 106 107 static const struct regmap_config lm4857_regmap_config = { 108 .val_bits = 6, 109 .reg_bits = 2, 110 111 .max_register = LM4857_CTRL, 112 113 .cache_type = REGCACHE_FLAT, 114 .reg_defaults = lm4857_default_regs, 115 .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs), 116 }; 117 118 static int lm4857_i2c_probe(struct i2c_client *i2c) 119 { 120 struct regmap *regmap; 121 122 regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config); 123 if (IS_ERR(regmap)) 124 return PTR_ERR(regmap); 125 126 return devm_snd_soc_register_component(&i2c->dev, 127 &lm4857_component_driver, NULL, 0); 128 } 129 130 static const struct i2c_device_id lm4857_i2c_id[] = { 131 { "lm4857", 0 }, 132 { } 133 }; 134 MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); 135 136 static struct i2c_driver lm4857_i2c_driver = { 137 .driver = { 138 .name = "lm4857", 139 }, 140 .probe = lm4857_i2c_probe, 141 .id_table = lm4857_i2c_id, 142 }; 143 144 module_i2c_driver(lm4857_i2c_driver); 145 146 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 147 MODULE_DESCRIPTION("LM4857 amplifier driver"); 148 MODULE_LICENSE("GPL"); 149