162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * max9877.c -- amp driver for max9877 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009 Samsung Electronics Co.Ltd 662306a36Sopenharmony_ci * Author: Joonyoung Shim <jy0922.shim@samsung.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/regmap.h> 1362306a36Sopenharmony_ci#include <sound/soc.h> 1462306a36Sopenharmony_ci#include <sound/tlv.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "max9877.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const struct reg_default max9877_regs[] = { 1962306a36Sopenharmony_ci { 0, 0x40 }, 2062306a36Sopenharmony_ci { 1, 0x00 }, 2162306a36Sopenharmony_ci { 2, 0x00 }, 2262306a36Sopenharmony_ci { 3, 0x00 }, 2362306a36Sopenharmony_ci { 4, 0x49 }, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(max9877_pgain_tlv, 2762306a36Sopenharmony_ci 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0), 2862306a36Sopenharmony_ci 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0) 2962306a36Sopenharmony_ci); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(max9877_output_tlv, 3262306a36Sopenharmony_ci 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1), 3362306a36Sopenharmony_ci 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0), 3462306a36Sopenharmony_ci 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0), 3562306a36Sopenharmony_ci 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0) 3662306a36Sopenharmony_ci); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const char *max9877_out_mode[] = { 3962306a36Sopenharmony_ci "INA -> SPK", 4062306a36Sopenharmony_ci "INA -> HP", 4162306a36Sopenharmony_ci "INA -> SPK and HP", 4262306a36Sopenharmony_ci "INB -> SPK", 4362306a36Sopenharmony_ci "INB -> HP", 4462306a36Sopenharmony_ci "INB -> SPK and HP", 4562306a36Sopenharmony_ci "INA + INB -> SPK", 4662306a36Sopenharmony_ci "INA + INB -> HP", 4762306a36Sopenharmony_ci "INA + INB -> SPK and HP", 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic const char *max9877_osc_mode[] = { 5162306a36Sopenharmony_ci "1176KHz", 5262306a36Sopenharmony_ci "1100KHz", 5362306a36Sopenharmony_ci "700KHz", 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic const struct soc_enum max9877_enum[] = { 5762306a36Sopenharmony_ci SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode), 5862306a36Sopenharmony_ci max9877_out_mode), 5962306a36Sopenharmony_ci SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET, 6062306a36Sopenharmony_ci ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const struct snd_kcontrol_new max9877_controls[] = { 6462306a36Sopenharmony_ci SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume", 6562306a36Sopenharmony_ci MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv), 6662306a36Sopenharmony_ci SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume", 6762306a36Sopenharmony_ci MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv), 6862306a36Sopenharmony_ci SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume", 6962306a36Sopenharmony_ci MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv), 7062306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume", 7162306a36Sopenharmony_ci MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, 7262306a36Sopenharmony_ci max9877_output_tlv), 7362306a36Sopenharmony_ci SOC_SINGLE("MAX9877 INB Stereo Switch", 7462306a36Sopenharmony_ci MAX9877_INPUT_MODE, 4, 1, 1), 7562306a36Sopenharmony_ci SOC_SINGLE("MAX9877 INA Stereo Switch", 7662306a36Sopenharmony_ci MAX9877_INPUT_MODE, 5, 1, 1), 7762306a36Sopenharmony_ci SOC_SINGLE("MAX9877 Zero-crossing detection Switch", 7862306a36Sopenharmony_ci MAX9877_INPUT_MODE, 6, 1, 0), 7962306a36Sopenharmony_ci SOC_SINGLE("MAX9877 Bypass Mode Switch", 8062306a36Sopenharmony_ci MAX9877_OUTPUT_MODE, 6, 1, 0), 8162306a36Sopenharmony_ci SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]), 8262306a36Sopenharmony_ci SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]), 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget max9877_dapm_widgets[] = { 8662306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("INA1"), 8762306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("INA2"), 8862306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("INB1"), 8962306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("INB2"), 9062306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("RXIN+"), 9162306a36Sopenharmony_ciSND_SOC_DAPM_INPUT("RXIN-"), 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciSND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0), 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("OUT+"), 9662306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("OUT-"), 9762306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPL"), 9862306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("HPR"), 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route max9877_dapm_routes[] = { 10262306a36Sopenharmony_ci { "SHDN", NULL, "INA1" }, 10362306a36Sopenharmony_ci { "SHDN", NULL, "INA2" }, 10462306a36Sopenharmony_ci { "SHDN", NULL, "INB1" }, 10562306a36Sopenharmony_ci { "SHDN", NULL, "INB2" }, 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci { "OUT+", NULL, "RXIN+" }, 10862306a36Sopenharmony_ci { "OUT+", NULL, "SHDN" }, 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci { "OUT-", NULL, "SHDN" }, 11162306a36Sopenharmony_ci { "OUT-", NULL, "RXIN-" }, 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci { "HPL", NULL, "SHDN" }, 11462306a36Sopenharmony_ci { "HPR", NULL, "SHDN" }, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic const struct snd_soc_component_driver max9877_component_driver = { 11862306a36Sopenharmony_ci .controls = max9877_controls, 11962306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(max9877_controls), 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci .dapm_widgets = max9877_dapm_widgets, 12262306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets), 12362306a36Sopenharmony_ci .dapm_routes = max9877_dapm_routes, 12462306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes), 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const struct regmap_config max9877_regmap = { 12862306a36Sopenharmony_ci .reg_bits = 8, 12962306a36Sopenharmony_ci .val_bits = 8, 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci .reg_defaults = max9877_regs, 13262306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(max9877_regs), 13362306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int max9877_i2c_probe(struct i2c_client *client) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct regmap *regmap; 13962306a36Sopenharmony_ci int i; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci regmap = devm_regmap_init_i2c(client, &max9877_regmap); 14262306a36Sopenharmony_ci if (IS_ERR(regmap)) 14362306a36Sopenharmony_ci return PTR_ERR(regmap); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Ensure the device is in reset state */ 14662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) 14762306a36Sopenharmony_ci regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return devm_snd_soc_register_component(&client->dev, 15062306a36Sopenharmony_ci &max9877_component_driver, NULL, 0); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic const struct i2c_device_id max9877_i2c_id[] = { 15462306a36Sopenharmony_ci { "max9877", 0 }, 15562306a36Sopenharmony_ci { } 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max9877_i2c_id); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic struct i2c_driver max9877_i2c_driver = { 16062306a36Sopenharmony_ci .driver = { 16162306a36Sopenharmony_ci .name = "max9877", 16262306a36Sopenharmony_ci }, 16362306a36Sopenharmony_ci .probe = max9877_i2c_probe, 16462306a36Sopenharmony_ci .id_table = max9877_i2c_id, 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cimodule_i2c_driver(max9877_i2c_driver); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC MAX9877 amp driver"); 17062306a36Sopenharmony_ciMODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 17162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 172