lm4857.c (3782B)
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 21static 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 39static const unsigned int lm4857_mode_values[] = { 40 0, 41 6, 42 7, 43 8, 44 9, 45}; 46 47static const char * const lm4857_mode_texts[] = { 48 "Off", 49 "Earpiece", 50 "Loudspeaker", 51 "Loudspeaker + Headphone", 52 "Headphone", 53}; 54 55static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum, 56 LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values); 57 58static const struct snd_kcontrol_new lm4857_mode_ctrl = 59 SOC_DAPM_ENUM("Mode", lm4857_mode_enum); 60 61static 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 71static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); 72static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); 73 74static 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 89static 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 98static 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 107static 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 118static 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 130static const struct i2c_device_id lm4857_i2c_id[] = { 131 { "lm4857", 0 }, 132 { } 133}; 134MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); 135 136static struct i2c_driver lm4857_i2c_driver = { 137 .driver = { 138 .name = "lm4857", 139 }, 140 .probe_new = lm4857_i2c_probe, 141 .id_table = lm4857_i2c_id, 142}; 143 144module_i2c_driver(lm4857_i2c_driver); 145 146MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 147MODULE_DESCRIPTION("LM4857 amplifier driver"); 148MODULE_LICENSE("GPL");