Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * max9877.c  --  amp driver for max9877
0004  *
0005  * Copyright (C) 2009 Samsung Electronics Co.Ltd
0006  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/i2c.h>
0012 #include <linux/regmap.h>
0013 #include <sound/soc.h>
0014 #include <sound/tlv.h>
0015 
0016 #include "max9877.h"
0017 
0018 static const struct reg_default max9877_regs[] = {
0019     { 0, 0x40 },
0020     { 1, 0x00 },
0021     { 2, 0x00 },
0022     { 3, 0x00 },
0023     { 4, 0x49 },
0024 };
0025 
0026 static const DECLARE_TLV_DB_RANGE(max9877_pgain_tlv,
0027     0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
0028     2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0)
0029 );
0030 
0031 static const DECLARE_TLV_DB_RANGE(max9877_output_tlv,
0032     0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
0033     8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
0034     16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
0035     24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0)
0036 );
0037 
0038 static const char *max9877_out_mode[] = {
0039     "INA -> SPK",
0040     "INA -> HP",
0041     "INA -> SPK and HP",
0042     "INB -> SPK",
0043     "INB -> HP",
0044     "INB -> SPK and HP",
0045     "INA + INB -> SPK",
0046     "INA + INB -> HP",
0047     "INA + INB -> SPK and HP",
0048 };
0049 
0050 static const char *max9877_osc_mode[] = {
0051     "1176KHz",
0052     "1100KHz",
0053     "700KHz",
0054 };
0055 
0056 static const struct soc_enum max9877_enum[] = {
0057     SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode),
0058             max9877_out_mode),
0059     SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET,
0060             ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
0061 };
0062 
0063 static const struct snd_kcontrol_new max9877_controls[] = {
0064     SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume",
0065                MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv),
0066     SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume",
0067                MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv),
0068     SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume",
0069                MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv),
0070     SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume",
0071              MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
0072              max9877_output_tlv),
0073     SOC_SINGLE("MAX9877 INB Stereo Switch",
0074            MAX9877_INPUT_MODE, 4, 1, 1),
0075     SOC_SINGLE("MAX9877 INA Stereo Switch",
0076            MAX9877_INPUT_MODE, 5, 1, 1),
0077     SOC_SINGLE("MAX9877 Zero-crossing detection Switch",
0078            MAX9877_INPUT_MODE, 6, 1, 0),
0079     SOC_SINGLE("MAX9877 Bypass Mode Switch",
0080            MAX9877_OUTPUT_MODE, 6, 1, 0),
0081     SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]),
0082     SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]),
0083 };
0084 
0085 static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = {
0086 SND_SOC_DAPM_INPUT("INA1"),
0087 SND_SOC_DAPM_INPUT("INA2"),
0088 SND_SOC_DAPM_INPUT("INB1"),
0089 SND_SOC_DAPM_INPUT("INB2"),
0090 SND_SOC_DAPM_INPUT("RXIN+"),
0091 SND_SOC_DAPM_INPUT("RXIN-"),
0092 
0093 SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0),
0094 
0095 SND_SOC_DAPM_OUTPUT("OUT+"),
0096 SND_SOC_DAPM_OUTPUT("OUT-"),
0097 SND_SOC_DAPM_OUTPUT("HPL"),
0098 SND_SOC_DAPM_OUTPUT("HPR"),
0099 };
0100 
0101 static const struct snd_soc_dapm_route max9877_dapm_routes[] = {
0102     { "SHDN", NULL, "INA1" },
0103     { "SHDN", NULL, "INA2" },
0104     { "SHDN", NULL, "INB1" },
0105     { "SHDN", NULL, "INB2" },
0106 
0107     { "OUT+", NULL, "RXIN+" },
0108     { "OUT+", NULL, "SHDN" },
0109 
0110     { "OUT-", NULL, "SHDN" },
0111     { "OUT-", NULL, "RXIN-" },
0112 
0113     { "HPL", NULL, "SHDN" },
0114     { "HPR", NULL, "SHDN" },
0115 };
0116 
0117 static const struct snd_soc_component_driver max9877_component_driver = {
0118     .controls = max9877_controls,
0119     .num_controls = ARRAY_SIZE(max9877_controls),
0120 
0121     .dapm_widgets = max9877_dapm_widgets,
0122     .num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets),
0123     .dapm_routes = max9877_dapm_routes,
0124     .num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes),
0125 };
0126 
0127 static const struct regmap_config max9877_regmap = {
0128     .reg_bits = 8,
0129     .val_bits = 8,
0130 
0131     .reg_defaults = max9877_regs,
0132     .num_reg_defaults = ARRAY_SIZE(max9877_regs),
0133     .cache_type = REGCACHE_RBTREE,
0134 };
0135 
0136 static int max9877_i2c_probe(struct i2c_client *client)
0137 {
0138     struct regmap *regmap;
0139     int i;
0140 
0141     regmap = devm_regmap_init_i2c(client, &max9877_regmap);
0142     if (IS_ERR(regmap))
0143         return PTR_ERR(regmap);
0144 
0145     /* Ensure the device is in reset state */
0146     for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
0147         regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def);
0148 
0149     return devm_snd_soc_register_component(&client->dev,
0150             &max9877_component_driver, NULL, 0);
0151 }
0152 
0153 static const struct i2c_device_id max9877_i2c_id[] = {
0154     { "max9877", 0 },
0155     { }
0156 };
0157 MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
0158 
0159 static struct i2c_driver max9877_i2c_driver = {
0160     .driver = {
0161         .name = "max9877",
0162     },
0163     .probe_new = max9877_i2c_probe,
0164     .id_table = max9877_i2c_id,
0165 };
0166 
0167 module_i2c_driver(max9877_i2c_driver);
0168 
0169 MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
0170 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
0171 MODULE_LICENSE("GPL");