19b0a25f0SLars-Peter Clausen /* 29b0a25f0SLars-Peter Clausen * LM4857 AMP driver 39b0a25f0SLars-Peter Clausen * 49b0a25f0SLars-Peter Clausen * Copyright 2007 Wolfson Microelectronics PLC. 59b0a25f0SLars-Peter Clausen * Author: Graeme Gregory 69a185b9aSMark Brown * graeme.gregory@wolfsonmicro.com 79b0a25f0SLars-Peter Clausen * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> 89b0a25f0SLars-Peter Clausen * 99b0a25f0SLars-Peter Clausen * This program is free software; you can redistribute it and/or modify it 109b0a25f0SLars-Peter Clausen * under the terms of the GNU General Public License as published by the 119b0a25f0SLars-Peter Clausen * Free Software Foundation; either version 2 of the License, or (at your 129b0a25f0SLars-Peter Clausen * option) any later version. 139b0a25f0SLars-Peter Clausen * 149b0a25f0SLars-Peter Clausen */ 159b0a25f0SLars-Peter Clausen 169b0a25f0SLars-Peter Clausen #include <linux/init.h> 179b0a25f0SLars-Peter Clausen #include <linux/module.h> 189b0a25f0SLars-Peter Clausen #include <linux/i2c.h> 199b270968SLars-Peter Clausen #include <linux/regmap.h> 209b0a25f0SLars-Peter Clausen #include <linux/slab.h> 219b0a25f0SLars-Peter Clausen 229b0a25f0SLars-Peter Clausen #include <sound/core.h> 239b0a25f0SLars-Peter Clausen #include <sound/soc.h> 249b0a25f0SLars-Peter Clausen #include <sound/tlv.h> 259b0a25f0SLars-Peter Clausen 269b270968SLars-Peter Clausen static const struct reg_default lm4857_default_regs[] = { 279b270968SLars-Peter Clausen { 0x0, 0x00 }, 289b270968SLars-Peter Clausen { 0x1, 0x00 }, 299b270968SLars-Peter Clausen { 0x2, 0x00 }, 309b270968SLars-Peter Clausen { 0x3, 0x00 }, 319b0a25f0SLars-Peter Clausen }; 329b0a25f0SLars-Peter Clausen 339b0a25f0SLars-Peter Clausen /* The register offsets in the cache array */ 349b0a25f0SLars-Peter Clausen #define LM4857_MVOL 0 359b0a25f0SLars-Peter Clausen #define LM4857_LVOL 1 369b0a25f0SLars-Peter Clausen #define LM4857_RVOL 2 379b0a25f0SLars-Peter Clausen #define LM4857_CTRL 3 389b0a25f0SLars-Peter Clausen 399b0a25f0SLars-Peter Clausen /* the shifts required to set these bits */ 409b0a25f0SLars-Peter Clausen #define LM4857_3D 5 419b0a25f0SLars-Peter Clausen #define LM4857_WAKEUP 5 429b0a25f0SLars-Peter Clausen #define LM4857_EPGAIN 4 439b0a25f0SLars-Peter Clausen 440eb93ef0SLars-Peter Clausen static const unsigned int lm4857_mode_values[] = { 450eb93ef0SLars-Peter Clausen 0, 460eb93ef0SLars-Peter Clausen 6, 470eb93ef0SLars-Peter Clausen 7, 480eb93ef0SLars-Peter Clausen 8, 490eb93ef0SLars-Peter Clausen 9, 500eb93ef0SLars-Peter Clausen }; 519b0a25f0SLars-Peter Clausen 520eb93ef0SLars-Peter Clausen static const char * const lm4857_mode_texts[] = { 530eb93ef0SLars-Peter Clausen "Off", 549b0a25f0SLars-Peter Clausen "Earpiece", 559b0a25f0SLars-Peter Clausen "Loudspeaker", 569b0a25f0SLars-Peter Clausen "Loudspeaker + Headphone", 579b0a25f0SLars-Peter Clausen "Headphone", 589b0a25f0SLars-Peter Clausen }; 599b0a25f0SLars-Peter Clausen 600eb93ef0SLars-Peter Clausen static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum, 610eb93ef0SLars-Peter Clausen LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values); 620eb93ef0SLars-Peter Clausen 630eb93ef0SLars-Peter Clausen static const struct snd_kcontrol_new lm4857_mode_ctrl = 640eb93ef0SLars-Peter Clausen SOC_DAPM_ENUM("Mode", lm4857_mode_enum); 659b0a25f0SLars-Peter Clausen 669b0a25f0SLars-Peter Clausen static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { 679b0a25f0SLars-Peter Clausen SND_SOC_DAPM_INPUT("IN"), 689b0a25f0SLars-Peter Clausen 690eb93ef0SLars-Peter Clausen SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl), 700eb93ef0SLars-Peter Clausen 719b0a25f0SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("LS"), 729b0a25f0SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("HP"), 739b0a25f0SLars-Peter Clausen SND_SOC_DAPM_OUTPUT("EP"), 749b0a25f0SLars-Peter Clausen }; 759b0a25f0SLars-Peter Clausen 769b0a25f0SLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); 779b0a25f0SLars-Peter Clausen static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); 789b0a25f0SLars-Peter Clausen 799b0a25f0SLars-Peter Clausen static const struct snd_kcontrol_new lm4857_controls[] = { 809b0a25f0SLars-Peter Clausen SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0, 819b0a25f0SLars-Peter Clausen stereo_tlv), 829b0a25f0SLars-Peter Clausen SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0, 839b0a25f0SLars-Peter Clausen stereo_tlv), 849b0a25f0SLars-Peter Clausen SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0, 859b0a25f0SLars-Peter Clausen mono_tlv), 869b0a25f0SLars-Peter Clausen SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0), 879b0a25f0SLars-Peter Clausen SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0), 889b0a25f0SLars-Peter Clausen SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL, 899b0a25f0SLars-Peter Clausen LM4857_WAKEUP, 1, 0), 909b0a25f0SLars-Peter Clausen SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, 919b0a25f0SLars-Peter Clausen LM4857_EPGAIN, 1, 0), 929b0a25f0SLars-Peter Clausen }; 939b0a25f0SLars-Peter Clausen 949b0a25f0SLars-Peter Clausen static const struct snd_soc_dapm_route lm4857_routes[] = { 950eb93ef0SLars-Peter Clausen { "Mode", NULL, "IN" }, 960eb93ef0SLars-Peter Clausen { "LS", "Loudspeaker", "Mode" }, 970eb93ef0SLars-Peter Clausen { "LS", "Loudspeaker + Headphone", "Mode" }, 980eb93ef0SLars-Peter Clausen { "HP", "Headphone", "Mode" }, 990eb93ef0SLars-Peter Clausen { "HP", "Loudspeaker + Headphone", "Mode" }, 1000eb93ef0SLars-Peter Clausen { "EP", "Earpiece", "Mode" }, 1019b0a25f0SLars-Peter Clausen }; 1029b0a25f0SLars-Peter Clausen 103*08a1e646SLars-Peter Clausen static struct snd_soc_component_driver lm4857_component_driver = { 10407ccc0f4SLars-Peter Clausen .controls = lm4857_controls, 10507ccc0f4SLars-Peter Clausen .num_controls = ARRAY_SIZE(lm4857_controls), 10607ccc0f4SLars-Peter Clausen .dapm_widgets = lm4857_dapm_widgets, 10707ccc0f4SLars-Peter Clausen .num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets), 10807ccc0f4SLars-Peter Clausen .dapm_routes = lm4857_routes, 10907ccc0f4SLars-Peter Clausen .num_dapm_routes = ARRAY_SIZE(lm4857_routes), 1109b0a25f0SLars-Peter Clausen }; 1119b0a25f0SLars-Peter Clausen 1129b270968SLars-Peter Clausen static const struct regmap_config lm4857_regmap_config = { 1139b270968SLars-Peter Clausen .val_bits = 6, 1149b270968SLars-Peter Clausen .reg_bits = 2, 1159b270968SLars-Peter Clausen 1169b270968SLars-Peter Clausen .max_register = LM4857_CTRL, 1179b270968SLars-Peter Clausen 1189b270968SLars-Peter Clausen .cache_type = REGCACHE_FLAT, 1199b270968SLars-Peter Clausen .reg_defaults = lm4857_default_regs, 1209b270968SLars-Peter Clausen .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs), 1219b270968SLars-Peter Clausen }; 1229b270968SLars-Peter Clausen 1237a79e94eSBill Pemberton static int lm4857_i2c_probe(struct i2c_client *i2c, 1249b0a25f0SLars-Peter Clausen const struct i2c_device_id *id) 1259b0a25f0SLars-Peter Clausen { 1260eb93ef0SLars-Peter Clausen struct regmap *regmap; 1279b0a25f0SLars-Peter Clausen 1280eb93ef0SLars-Peter Clausen regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config); 1290eb93ef0SLars-Peter Clausen if (IS_ERR(regmap)) 1300eb93ef0SLars-Peter Clausen return PTR_ERR(regmap); 1319b0a25f0SLars-Peter Clausen 132*08a1e646SLars-Peter Clausen return devm_snd_soc_register_component(&i2c->dev, 133*08a1e646SLars-Peter Clausen &lm4857_component_driver, NULL, 0); 1349b0a25f0SLars-Peter Clausen } 1359b0a25f0SLars-Peter Clausen 1369b0a25f0SLars-Peter Clausen static const struct i2c_device_id lm4857_i2c_id[] = { 1379b0a25f0SLars-Peter Clausen { "lm4857", 0 }, 1389b0a25f0SLars-Peter Clausen { } 1399b0a25f0SLars-Peter Clausen }; 1409b0a25f0SLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); 1419b0a25f0SLars-Peter Clausen 1429b0a25f0SLars-Peter Clausen static struct i2c_driver lm4857_i2c_driver = { 1439b0a25f0SLars-Peter Clausen .driver = { 1449b0a25f0SLars-Peter Clausen .name = "lm4857", 1459b0a25f0SLars-Peter Clausen .owner = THIS_MODULE, 1469b0a25f0SLars-Peter Clausen }, 1479b0a25f0SLars-Peter Clausen .probe = lm4857_i2c_probe, 1489b0a25f0SLars-Peter Clausen .id_table = lm4857_i2c_id, 1499b0a25f0SLars-Peter Clausen }; 1509b0a25f0SLars-Peter Clausen 151f6ec139fSSachin Kamat module_i2c_driver(lm4857_i2c_driver); 1529b0a25f0SLars-Peter Clausen 1539b0a25f0SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1549b0a25f0SLars-Peter Clausen MODULE_DESCRIPTION("LM4857 amplifier driver"); 1559b0a25f0SLars-Peter Clausen MODULE_LICENSE("GPL"); 156