Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * SSM4567 amplifier audio driver
0004  *
0005  * Copyright 2014 Google Chromium project.
0006  *  Author: Anatol Pomozov <anatol@chromium.org>
0007  *
0008  * Based on code copyright/by:
0009  *   Copyright 2013 Analog Devices Inc.
0010  */
0011 
0012 #include <linux/acpi.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/i2c.h>
0016 #include <linux/regmap.h>
0017 #include <linux/slab.h>
0018 #include <sound/core.h>
0019 #include <sound/pcm.h>
0020 #include <sound/pcm_params.h>
0021 #include <sound/soc.h>
0022 #include <sound/initval.h>
0023 #include <sound/tlv.h>
0024 
0025 #define SSM4567_REG_POWER_CTRL      0x00
0026 #define SSM4567_REG_AMP_SNS_CTRL        0x01
0027 #define SSM4567_REG_DAC_CTRL        0x02
0028 #define SSM4567_REG_DAC_VOLUME      0x03
0029 #define SSM4567_REG_SAI_CTRL_1      0x04
0030 #define SSM4567_REG_SAI_CTRL_2      0x05
0031 #define SSM4567_REG_SAI_PLACEMENT_1     0x06
0032 #define SSM4567_REG_SAI_PLACEMENT_2     0x07
0033 #define SSM4567_REG_SAI_PLACEMENT_3     0x08
0034 #define SSM4567_REG_SAI_PLACEMENT_4     0x09
0035 #define SSM4567_REG_SAI_PLACEMENT_5     0x0a
0036 #define SSM4567_REG_SAI_PLACEMENT_6     0x0b
0037 #define SSM4567_REG_BATTERY_V_OUT       0x0c
0038 #define SSM4567_REG_LIMITER_CTRL_1      0x0d
0039 #define SSM4567_REG_LIMITER_CTRL_2      0x0e
0040 #define SSM4567_REG_LIMITER_CTRL_3      0x0f
0041 #define SSM4567_REG_STATUS_1        0x10
0042 #define SSM4567_REG_STATUS_2        0x11
0043 #define SSM4567_REG_FAULT_CTRL      0x12
0044 #define SSM4567_REG_PDM_CTRL        0x13
0045 #define SSM4567_REG_MCLK_RATIO      0x14
0046 #define SSM4567_REG_BOOST_CTRL_1        0x15
0047 #define SSM4567_REG_BOOST_CTRL_2        0x16
0048 #define SSM4567_REG_SOFT_RESET      0xff
0049 
0050 /* POWER_CTRL */
0051 #define SSM4567_POWER_APWDN_EN      BIT(7)
0052 #define SSM4567_POWER_BSNS_PWDN     BIT(6)
0053 #define SSM4567_POWER_VSNS_PWDN     BIT(5)
0054 #define SSM4567_POWER_ISNS_PWDN     BIT(4)
0055 #define SSM4567_POWER_BOOST_PWDN        BIT(3)
0056 #define SSM4567_POWER_AMP_PWDN      BIT(2)
0057 #define SSM4567_POWER_VBAT_ONLY     BIT(1)
0058 #define SSM4567_POWER_SPWDN         BIT(0)
0059 
0060 /* DAC_CTRL */
0061 #define SSM4567_DAC_HV          BIT(7)
0062 #define SSM4567_DAC_MUTE        BIT(6)
0063 #define SSM4567_DAC_HPF         BIT(5)
0064 #define SSM4567_DAC_LPM         BIT(4)
0065 #define SSM4567_DAC_FS_MASK 0x7
0066 #define SSM4567_DAC_FS_8000_12000   0x0
0067 #define SSM4567_DAC_FS_16000_24000  0x1
0068 #define SSM4567_DAC_FS_32000_48000  0x2
0069 #define SSM4567_DAC_FS_64000_96000  0x3
0070 #define SSM4567_DAC_FS_128000_192000    0x4
0071 
0072 /* SAI_CTRL_1 */
0073 #define SSM4567_SAI_CTRL_1_BCLK         BIT(6)
0074 #define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK   (0x3 << 4)
0075 #define SSM4567_SAI_CTRL_1_TDM_BLCKS_32     (0x0 << 4)
0076 #define SSM4567_SAI_CTRL_1_TDM_BLCKS_48     (0x1 << 4)
0077 #define SSM4567_SAI_CTRL_1_TDM_BLCKS_64     (0x2 << 4)
0078 #define SSM4567_SAI_CTRL_1_FSYNC        BIT(3)
0079 #define SSM4567_SAI_CTRL_1_LJ           BIT(2)
0080 #define SSM4567_SAI_CTRL_1_TDM          BIT(1)
0081 #define SSM4567_SAI_CTRL_1_PDM          BIT(0)
0082 
0083 /* SAI_CTRL_2 */
0084 #define SSM4567_SAI_CTRL_2_AUTO_SLOT        BIT(3)
0085 #define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK    0x7
0086 #define SSM4567_SAI_CTRL_2_TDM_SLOT(x)      (x)
0087 
0088 struct ssm4567 {
0089     struct regmap *regmap;
0090 };
0091 
0092 static const struct reg_default ssm4567_reg_defaults[] = {
0093     { SSM4567_REG_POWER_CTRL,   0x81 },
0094     { SSM4567_REG_AMP_SNS_CTRL, 0x09 },
0095     { SSM4567_REG_DAC_CTRL, 0x32 },
0096     { SSM4567_REG_DAC_VOLUME, 0x40 },
0097     { SSM4567_REG_SAI_CTRL_1, 0x00 },
0098     { SSM4567_REG_SAI_CTRL_2, 0x08 },
0099     { SSM4567_REG_SAI_PLACEMENT_1, 0x01 },
0100     { SSM4567_REG_SAI_PLACEMENT_2, 0x20 },
0101     { SSM4567_REG_SAI_PLACEMENT_3, 0x32 },
0102     { SSM4567_REG_SAI_PLACEMENT_4, 0x07 },
0103     { SSM4567_REG_SAI_PLACEMENT_5, 0x07 },
0104     { SSM4567_REG_SAI_PLACEMENT_6, 0x07 },
0105     { SSM4567_REG_BATTERY_V_OUT, 0x00 },
0106     { SSM4567_REG_LIMITER_CTRL_1, 0xa4 },
0107     { SSM4567_REG_LIMITER_CTRL_2, 0x73 },
0108     { SSM4567_REG_LIMITER_CTRL_3, 0x00 },
0109     { SSM4567_REG_STATUS_1, 0x00 },
0110     { SSM4567_REG_STATUS_2, 0x00 },
0111     { SSM4567_REG_FAULT_CTRL, 0x30 },
0112     { SSM4567_REG_PDM_CTRL, 0x40 },
0113     { SSM4567_REG_MCLK_RATIO, 0x11 },
0114     { SSM4567_REG_BOOST_CTRL_1, 0x03 },
0115     { SSM4567_REG_BOOST_CTRL_2, 0x00 },
0116     { SSM4567_REG_SOFT_RESET, 0x00 },
0117 };
0118 
0119 
0120 static bool ssm4567_readable_reg(struct device *dev, unsigned int reg)
0121 {
0122     switch (reg) {
0123     case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2:
0124         return true;
0125     default:
0126         return false;
0127     }
0128 
0129 }
0130 
0131 static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg)
0132 {
0133     switch (reg) {
0134     case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6:
0135     case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3:
0136     case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2:
0137     /* The datasheet states that soft reset register is read-only,
0138      * but logically it is write-only. */
0139     case SSM4567_REG_SOFT_RESET:
0140         return true;
0141     default:
0142         return false;
0143     }
0144 }
0145 
0146 static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg)
0147 {
0148     switch (reg) {
0149     case SSM4567_REG_BATTERY_V_OUT:
0150     case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2:
0151     case SSM4567_REG_SOFT_RESET:
0152         return true;
0153     default:
0154         return false;
0155     }
0156 }
0157 
0158 static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400);
0159 
0160 static const struct snd_kcontrol_new ssm4567_snd_controls[] = {
0161     SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0,
0162         0xff, 1, ssm4567_vol_tlv),
0163     SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0),
0164     SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL,
0165         5, 1, 0),
0166 };
0167 
0168 static const struct snd_kcontrol_new ssm4567_amplifier_boost_control =
0169     SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1);
0170 
0171 static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
0172     SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1),
0173     SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1,
0174         &ssm4567_amplifier_boost_control),
0175 
0176     SND_SOC_DAPM_SIGGEN("Sense"),
0177 
0178     SND_SOC_DAPM_PGA("Current Sense", SSM4567_REG_POWER_CTRL, 4, 1, NULL, 0),
0179     SND_SOC_DAPM_PGA("Voltage Sense", SSM4567_REG_POWER_CTRL, 5, 1, NULL, 0),
0180     SND_SOC_DAPM_PGA("VBAT Sense", SSM4567_REG_POWER_CTRL, 6, 1, NULL, 0),
0181 
0182     SND_SOC_DAPM_OUTPUT("OUT"),
0183 };
0184 
0185 static const struct snd_soc_dapm_route ssm4567_routes[] = {
0186     { "OUT", NULL, "Amplifier Boost" },
0187     { "Amplifier Boost", "Switch", "DAC" },
0188     { "OUT", NULL, "DAC" },
0189 
0190     { "Current Sense", NULL, "Sense" },
0191     { "Voltage Sense", NULL, "Sense" },
0192     { "VBAT Sense", NULL, "Sense" },
0193     { "Capture Sense", NULL, "Current Sense" },
0194     { "Capture Sense", NULL, "Voltage Sense" },
0195     { "Capture Sense", NULL, "VBAT Sense" },
0196 };
0197 
0198 static int ssm4567_hw_params(struct snd_pcm_substream *substream,
0199     struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
0200 {
0201     struct snd_soc_component *component = dai->component;
0202     struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
0203     unsigned int rate = params_rate(params);
0204     unsigned int dacfs;
0205 
0206     if (rate >= 8000 && rate <= 12000)
0207         dacfs = SSM4567_DAC_FS_8000_12000;
0208     else if (rate >= 16000 && rate <= 24000)
0209         dacfs = SSM4567_DAC_FS_16000_24000;
0210     else if (rate >= 32000 && rate <= 48000)
0211         dacfs = SSM4567_DAC_FS_32000_48000;
0212     else if (rate >= 64000 && rate <= 96000)
0213         dacfs = SSM4567_DAC_FS_64000_96000;
0214     else if (rate >= 128000 && rate <= 192000)
0215         dacfs = SSM4567_DAC_FS_128000_192000;
0216     else
0217         return -EINVAL;
0218 
0219     return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
0220                 SSM4567_DAC_FS_MASK, dacfs);
0221 }
0222 
0223 static int ssm4567_mute(struct snd_soc_dai *dai, int mute, int direction)
0224 {
0225     struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(dai->component);
0226     unsigned int val;
0227 
0228     val = mute ? SSM4567_DAC_MUTE : 0;
0229     return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL,
0230             SSM4567_DAC_MUTE, val);
0231 }
0232 
0233 static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
0234     unsigned int rx_mask, int slots, int width)
0235 {
0236     struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
0237     unsigned int blcks;
0238     int slot;
0239     int ret;
0240 
0241     if (tx_mask == 0)
0242         return -EINVAL;
0243 
0244     if (rx_mask && rx_mask != tx_mask)
0245         return -EINVAL;
0246 
0247     slot = __ffs(tx_mask);
0248     if (tx_mask != BIT(slot))
0249         return -EINVAL;
0250 
0251     switch (width) {
0252     case 32:
0253         blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32;
0254         break;
0255     case 48:
0256         blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48;
0257         break;
0258     case 64:
0259         blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64;
0260         break;
0261     default:
0262         return -EINVAL;
0263     }
0264 
0265     ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2,
0266         SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK,
0267         SSM4567_SAI_CTRL_2_TDM_SLOT(slot));
0268     if (ret)
0269         return ret;
0270 
0271     return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
0272         SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks);
0273 }
0274 
0275 static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0276 {
0277     struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
0278     unsigned int ctrl1 = 0;
0279     bool invert_fclk;
0280 
0281     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0282     case SND_SOC_DAIFMT_CBC_CFC:
0283         break;
0284     default:
0285         return -EINVAL;
0286     }
0287 
0288     switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0289     case SND_SOC_DAIFMT_NB_NF:
0290         invert_fclk = false;
0291         break;
0292     case SND_SOC_DAIFMT_IB_NF:
0293         ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
0294         invert_fclk = false;
0295         break;
0296     case SND_SOC_DAIFMT_NB_IF:
0297         ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
0298         invert_fclk = true;
0299         break;
0300     case SND_SOC_DAIFMT_IB_IF:
0301         ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
0302         invert_fclk = true;
0303         break;
0304     default:
0305         return -EINVAL;
0306     }
0307 
0308     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0309     case SND_SOC_DAIFMT_I2S:
0310         break;
0311     case SND_SOC_DAIFMT_LEFT_J:
0312         ctrl1 |= SSM4567_SAI_CTRL_1_LJ;
0313         invert_fclk = !invert_fclk;
0314         break;
0315     case SND_SOC_DAIFMT_DSP_A:
0316         ctrl1 |= SSM4567_SAI_CTRL_1_TDM;
0317         break;
0318     case SND_SOC_DAIFMT_DSP_B:
0319         ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ;
0320         break;
0321     case SND_SOC_DAIFMT_PDM:
0322         ctrl1 |= SSM4567_SAI_CTRL_1_PDM;
0323         break;
0324     default:
0325         return -EINVAL;
0326     }
0327 
0328     if (invert_fclk)
0329         ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
0330 
0331     return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
0332             SSM4567_SAI_CTRL_1_BCLK |
0333             SSM4567_SAI_CTRL_1_FSYNC |
0334             SSM4567_SAI_CTRL_1_LJ |
0335             SSM4567_SAI_CTRL_1_TDM |
0336             SSM4567_SAI_CTRL_1_PDM,
0337             ctrl1);
0338 }
0339 
0340 static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
0341 {
0342     int ret = 0;
0343 
0344     if (!enable) {
0345         ret = regmap_update_bits(ssm4567->regmap,
0346             SSM4567_REG_POWER_CTRL,
0347             SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN);
0348         regcache_mark_dirty(ssm4567->regmap);
0349     }
0350 
0351     regcache_cache_only(ssm4567->regmap, !enable);
0352 
0353     if (enable) {
0354         ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET,
0355             0x00);
0356         if (ret)
0357             return ret;
0358 
0359         ret = regmap_update_bits(ssm4567->regmap,
0360             SSM4567_REG_POWER_CTRL,
0361             SSM4567_POWER_SPWDN, 0x00);
0362         regcache_sync(ssm4567->regmap);
0363     }
0364 
0365     return ret;
0366 }
0367 
0368 static int ssm4567_set_bias_level(struct snd_soc_component *component,
0369     enum snd_soc_bias_level level)
0370 {
0371     struct ssm4567 *ssm4567 = snd_soc_component_get_drvdata(component);
0372     int ret = 0;
0373 
0374     switch (level) {
0375     case SND_SOC_BIAS_ON:
0376         break;
0377     case SND_SOC_BIAS_PREPARE:
0378         break;
0379     case SND_SOC_BIAS_STANDBY:
0380         if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
0381             ret = ssm4567_set_power(ssm4567, true);
0382         break;
0383     case SND_SOC_BIAS_OFF:
0384         ret = ssm4567_set_power(ssm4567, false);
0385         break;
0386     }
0387 
0388     return ret;
0389 }
0390 
0391 static const struct snd_soc_dai_ops ssm4567_dai_ops = {
0392     .hw_params  = ssm4567_hw_params,
0393     .mute_stream    = ssm4567_mute,
0394     .set_fmt    = ssm4567_set_dai_fmt,
0395     .set_tdm_slot   = ssm4567_set_tdm_slot,
0396     .no_capture_mute = 1,
0397 };
0398 
0399 static struct snd_soc_dai_driver ssm4567_dai = {
0400     .name = "ssm4567-hifi",
0401     .playback = {
0402         .stream_name = "Playback",
0403         .channels_min = 1,
0404         .channels_max = 1,
0405         .rates = SNDRV_PCM_RATE_8000_192000,
0406         .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
0407             SNDRV_PCM_FMTBIT_S32,
0408     },
0409     .capture = {
0410         .stream_name = "Capture Sense",
0411         .channels_min = 1,
0412         .channels_max = 1,
0413         .rates = SNDRV_PCM_RATE_8000_192000,
0414         .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
0415             SNDRV_PCM_FMTBIT_S32,
0416     },
0417     .ops = &ssm4567_dai_ops,
0418 };
0419 
0420 static const struct snd_soc_component_driver ssm4567_component_driver = {
0421     .set_bias_level     = ssm4567_set_bias_level,
0422     .controls       = ssm4567_snd_controls,
0423     .num_controls       = ARRAY_SIZE(ssm4567_snd_controls),
0424     .dapm_widgets       = ssm4567_dapm_widgets,
0425     .num_dapm_widgets   = ARRAY_SIZE(ssm4567_dapm_widgets),
0426     .dapm_routes        = ssm4567_routes,
0427     .num_dapm_routes    = ARRAY_SIZE(ssm4567_routes),
0428     .use_pmdown_time    = 1,
0429     .endianness     = 1,
0430 };
0431 
0432 static const struct regmap_config ssm4567_regmap_config = {
0433     .val_bits = 8,
0434     .reg_bits = 8,
0435 
0436     .max_register = SSM4567_REG_SOFT_RESET,
0437     .readable_reg = ssm4567_readable_reg,
0438     .writeable_reg = ssm4567_writeable_reg,
0439     .volatile_reg = ssm4567_volatile_reg,
0440 
0441     .cache_type = REGCACHE_RBTREE,
0442     .reg_defaults = ssm4567_reg_defaults,
0443     .num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults),
0444 };
0445 
0446 static int ssm4567_i2c_probe(struct i2c_client *i2c)
0447 {
0448     struct ssm4567 *ssm4567;
0449     int ret;
0450 
0451     ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL);
0452     if (ssm4567 == NULL)
0453         return -ENOMEM;
0454 
0455     i2c_set_clientdata(i2c, ssm4567);
0456 
0457     ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config);
0458     if (IS_ERR(ssm4567->regmap))
0459         return PTR_ERR(ssm4567->regmap);
0460 
0461     ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00);
0462     if (ret)
0463         return ret;
0464 
0465     ret = ssm4567_set_power(ssm4567, false);
0466     if (ret)
0467         return ret;
0468 
0469     return devm_snd_soc_register_component(&i2c->dev, &ssm4567_component_driver,
0470             &ssm4567_dai, 1);
0471 }
0472 
0473 static const struct i2c_device_id ssm4567_i2c_ids[] = {
0474     { "ssm4567", 0 },
0475     { }
0476 };
0477 MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids);
0478 
0479 #ifdef CONFIG_OF
0480 static const struct of_device_id ssm4567_of_match[] = {
0481     { .compatible = "adi,ssm4567", },
0482     { }
0483 };
0484 MODULE_DEVICE_TABLE(of, ssm4567_of_match);
0485 #endif
0486 
0487 #ifdef CONFIG_ACPI
0488 
0489 static const struct acpi_device_id ssm4567_acpi_match[] = {
0490     { "INT343B", 0 },
0491     {},
0492 };
0493 MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match);
0494 
0495 #endif
0496 
0497 static struct i2c_driver ssm4567_driver = {
0498     .driver = {
0499         .name = "ssm4567",
0500         .of_match_table = of_match_ptr(ssm4567_of_match),
0501         .acpi_match_table = ACPI_PTR(ssm4567_acpi_match),
0502     },
0503     .probe_new = ssm4567_i2c_probe,
0504     .id_table = ssm4567_i2c_ids,
0505 };
0506 module_i2c_driver(ssm4567_driver);
0507 
0508 MODULE_DESCRIPTION("ASoC SSM4567 driver");
0509 MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>");
0510 MODULE_LICENSE("GPL");