1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 29b0a25f0SLars-Peter Clausen /* 39b0a25f0SLars-Peter Clausen * LM4857 AMP driver 49b0a25f0SLars-Peter Clausen * 59b0a25f0SLars-Peter Clausen * Copyright 2007 Wolfson Microelectronics PLC. 69b0a25f0SLars-Peter Clausen * Author: Graeme Gregory 79a185b9aSMark Brown * graeme.gregory@wolfsonmicro.com 89b0a25f0SLars-Peter Clausen * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> 99b0a25f0SLars-Peter Clausen */ 109b0a25f0SLars-Peter Clausen 119b0a25f0SLars-Peter Clausen #include <linux/init.h> 129b0a25f0SLars-Peter Clausen #include <linux/module.h> 139b0a25f0SLars-Peter Clausen #include <linux/i2c.h> 149b270968SLars-Peter Clausen #include <linux/regmap.h> 159b0a25f0SLars-Peter Clausen #include <linux/slab.h> 169b0a25f0SLars-Peter Clausen 179b0a25f0SLars-Peter Clausen #include <sound/core.h> 189b0a25f0SLars-Peter Clausen #include <sound/soc.h> 199b0a25f0SLars-Peter Clausen #include <sound/tlv.h> 209b0a25f0SLars-Peter Clausen 219b270968SLars-Peter Clausen static const struct reg_default lm4857_default_regs[] = { 229b270968SLars-Peter Clausen { 0x0, 0x00 }, 239b270968SLars-Peter Clausen { 0x1, 0x00 }, 249b270968SLars-Peter Clausen { 0x2, 0x00 }, 259b270968SLars-Peter Clausen { 0x3, 0x00 }, 269b0a25f0SLars-Peter Clausen }; 279b0a25f0SLars-Peter Clausen 289b0a25f0SLars-Peter Clausen /* The register offsets in the cache array */ 299b0a25f0SLars-Peter Clausen #define LM4857_MVOL 0 309b0a25f0SLars-Peter Clausen #define LM4857_LVOL 1 319b0a25f0SLars-Peter Clausen #define LM4857_RVOL 2 329b0a25f0SLars-Peter Clausen #define LM4857_CTRL 3 339b0a25f0SLars-Peter Clausen 349b0a25f0SLars-Peter Clausen /* the shifts required to set these bits */ 359b0a25f0SLars-Peter Clausen #define LM4857_3D 5 369b0a25f0SLars-Peter Clausen #define LM4857_WAKEUP 5 379b0a25f0SLars-Peter Clausen #define LM4857_EPGAIN 4 389b0a25f0SLars-Peter Clausen 390eb93ef0SLars-Peter Clausen static const unsigned int lm4857_mode_values[] = { 400eb93ef0SLars-Peter Clausen 0, 410eb93ef0SLars-Peter Clausen 6, 420eb93ef0SLars-Peter Clausen 7, 430eb93ef0SLars-Peter Clausen 8, 440eb93ef0SLars-Peter Clausen 9, 450eb93ef0SLars-Peter Clausen }; 469b0a25f0SLars-Peter Clausen 470eb93ef0SLars-Peter Clausen static const char * const lm4857_mode_texts[] = { 480eb93ef0SLars-Peter Clausen "Off", 499b0a25f0SLars-Peter Clausen "Earpiece", 509b0a25f0SLars-Peter Clausen "Loudspeaker", 519b0a25f0SLars-Peter Clausen "Loudspeaker + Headphone", 529b0a25f0SLars-Peter Clausen "Headphone", 539b0a25f0SLars-Peter Clausen }; 549b0a25f0SLars-Peter Clausen 550eb93ef0SLars-Peter Clausen static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum, 560eb93ef0SLars-Peter Clausen LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values); 570eb93ef0SLars-Peter Clausen 580eb93ef0SLars-Peter Clausen static const struct snd_kcontrol_new lm4857_mode_ctrl = 590eb93ef0SLars-Peter Clausen SOC_DAPM_ENUM("Mode", lm4857_mode_enum); 609b0a25f0SLars-Peter Clausen 619b0a25f0SLars-Peter Clausen static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { 629b0a25f0SLars-Peter Clausen SND_SOC_DAPM_INPUT("IN"), 639b0a25f0SLars-Peter Clausen 640eb93ef0SLars-Peter Clausen SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl), 650eb93ef0SLars-Peter Clausen 669b0a25f0SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("LS"), 679b0a25f0SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("HP"), 689b0a25f0SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("EP"), 699b0a25f0SLars-Peter Clausen }; 709b0a25f0SLars-Peter Clausen 719b0a25f0SLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); 729b0a25f0SLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); 739b0a25f0SLars-Peter Clausen 749b0a25f0SLars-Peter Clausen static const struct snd_kcontrol_new lm4857_controls[] = { 759b0a25f0SLars-Peter Clausen SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0, 769b0a25f0SLars-Peter Clausen stereo_tlv), 779b0a25f0SLars-Peter Clausen SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0, 789b0a25f0SLars-Peter Clausen stereo_tlv), 799b0a25f0SLars-Peter Clausen SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0, 809b0a25f0SLars-Peter Clausen mono_tlv), 819b0a25f0SLars-Peter Clausen SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0), 829b0a25f0SLars-Peter Clausen SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0), 839b0a25f0SLars-Peter Clausen SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL, 849b0a25f0SLars-Peter Clausen LM4857_WAKEUP, 1, 0), 859b0a25f0SLars-Peter Clausen SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, 869b0a25f0SLars-Peter Clausen LM4857_EPGAIN, 1, 0), 879b0a25f0SLars-Peter Clausen }; 889b0a25f0SLars-Peter Clausen 899b0a25f0SLars-Peter Clausen static const struct snd_soc_dapm_route lm4857_routes[] = { 900eb93ef0SLars-Peter Clausen { "Mode", NULL, "IN" }, 910eb93ef0SLars-Peter Clausen { "LS", "Loudspeaker", "Mode" }, 920eb93ef0SLars-Peter Clausen { "LS", "Loudspeaker + Headphone", "Mode" }, 930eb93ef0SLars-Peter Clausen { "HP", "Headphone", "Mode" }, 940eb93ef0SLars-Peter Clausen { "HP", "Loudspeaker + Headphone", "Mode" }, 950eb93ef0SLars-Peter Clausen { "EP", "Earpiece", "Mode" }, 969b0a25f0SLars-Peter Clausen }; 979b0a25f0SLars-Peter Clausen 986e37f933SBhumika Goyal static const struct snd_soc_component_driver lm4857_component_driver = { 9907ccc0f4SLars-Peter Clausen .controls = lm4857_controls, 10007ccc0f4SLars-Peter Clausen .num_controls = ARRAY_SIZE(lm4857_controls), 10107ccc0f4SLars-Peter Clausen .dapm_widgets = lm4857_dapm_widgets, 10207ccc0f4SLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets), 10307ccc0f4SLars-Peter Clausen .dapm_routes = lm4857_routes, 10407ccc0f4SLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(lm4857_routes), 1059b0a25f0SLars-Peter Clausen }; 1069b0a25f0SLars-Peter Clausen 1079b270968SLars-Peter Clausen static const struct regmap_config lm4857_regmap_config = { 1089b270968SLars-Peter Clausen .val_bits = 6, 1099b270968SLars-Peter Clausen .reg_bits = 2, 1109b270968SLars-Peter Clausen 1119b270968SLars-Peter Clausen .max_register = LM4857_CTRL, 1129b270968SLars-Peter Clausen 1139b270968SLars-Peter Clausen .cache_type = REGCACHE_FLAT, 1149b270968SLars-Peter Clausen .reg_defaults = lm4857_default_regs, 1159b270968SLars-Peter Clausen .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs), 1169b270968SLars-Peter Clausen }; 1179b270968SLars-Peter Clausen 1187a79e94eSBill Pemberton static int lm4857_i2c_probe(struct i2c_client *i2c, 1199b0a25f0SLars-Peter Clausen const struct i2c_device_id *id) 1209b0a25f0SLars-Peter Clausen { 1210eb93ef0SLars-Peter Clausen struct regmap *regmap; 1229b0a25f0SLars-Peter Clausen 1230eb93ef0SLars-Peter Clausen regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config); 1240eb93ef0SLars-Peter Clausen if (IS_ERR(regmap)) 1250eb93ef0SLars-Peter Clausen return PTR_ERR(regmap); 1269b0a25f0SLars-Peter Clausen 12708a1e646SLars-Peter Clausen return devm_snd_soc_register_component(&i2c->dev, 12808a1e646SLars-Peter Clausen &lm4857_component_driver, NULL, 0); 1299b0a25f0SLars-Peter Clausen } 1309b0a25f0SLars-Peter Clausen 1319b0a25f0SLars-Peter Clausen static const struct i2c_device_id lm4857_i2c_id[] = { 1329b0a25f0SLars-Peter Clausen { "lm4857", 0 }, 1339b0a25f0SLars-Peter Clausen { } 1349b0a25f0SLars-Peter Clausen }; 1359b0a25f0SLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); 1369b0a25f0SLars-Peter Clausen 1379b0a25f0SLars-Peter Clausen static struct i2c_driver lm4857_i2c_driver = { 1389b0a25f0SLars-Peter Clausen .driver = { 1399b0a25f0SLars-Peter Clausen .name = "lm4857", 1409b0a25f0SLars-Peter Clausen }, 1419b0a25f0SLars-Peter Clausen .probe = lm4857_i2c_probe, 1429b0a25f0SLars-Peter Clausen .id_table = lm4857_i2c_id, 1439b0a25f0SLars-Peter Clausen }; 1449b0a25f0SLars-Peter Clausen 145f6ec139fSSachin Kamat module_i2c_driver(lm4857_i2c_driver); 1469b0a25f0SLars-Peter Clausen 1479b0a25f0SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1489b0a25f0SLars-Peter Clausen MODULE_DESCRIPTION("LM4857 amplifier driver"); 1499b0a25f0SLars-Peter Clausen MODULE_LICENSE("GPL"); 150