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