14ac690bbSMartin Povišer // SPDX-License-Identifier: GPL-2.0-only OR MIT
24ac690bbSMartin Povišer //
34ac690bbSMartin Povišer // Analog Devices' SSM3515 audio amp driver
44ac690bbSMartin Povišer //
54ac690bbSMartin Povišer // Copyright (C) The Asahi Linux Contributors
64ac690bbSMartin Povišer
74ac690bbSMartin Povišer #include <linux/bits.h>
84ac690bbSMartin Povišer #include <linux/bitfield.h>
94ac690bbSMartin Povišer #include <linux/device.h>
104ac690bbSMartin Povišer #include <linux/i2c.h>
114ac690bbSMartin Povišer #include <linux/module.h>
124ac690bbSMartin Povišer #include <linux/of.h>
134ac690bbSMartin Povišer #include <linux/regmap.h>
144ac690bbSMartin Povišer
154ac690bbSMartin Povišer #include <sound/pcm.h>
164ac690bbSMartin Povišer #include <sound/pcm_params.h>
174ac690bbSMartin Povišer #include <sound/soc.h>
184ac690bbSMartin Povišer #include <sound/tlv.h>
194ac690bbSMartin Povišer
204ac690bbSMartin Povišer
214ac690bbSMartin Povišer #define SSM3515_PWR 0x00
224ac690bbSMartin Povišer #define SSM3515_PWR_APWDN_EN BIT(7)
234ac690bbSMartin Povišer #define SSM3515_PWR_BSNS_PWDN BIT(6)
244ac690bbSMartin Povišer #define SSM3515_PWR_S_RST BIT(1)
254ac690bbSMartin Povišer #define SSM3515_PWR_SPWDN BIT(0)
264ac690bbSMartin Povišer
274ac690bbSMartin Povišer #define SSM3515_GEC 0x01
284ac690bbSMartin Povišer #define SSM3515_GEC_EDGE BIT(4)
294ac690bbSMartin Povišer #define SSM3515_GEC_EDGE_SHIFT 4
304ac690bbSMartin Povišer #define SSM3515_GEC_ANA_GAIN GENMASK(1, 0)
314ac690bbSMartin Povišer
324ac690bbSMartin Povišer #define SSM3515_DAC 0x02
334ac690bbSMartin Povišer #define SSM3515_DAC_HV BIT(7)
344ac690bbSMartin Povišer #define SSM3515_DAC_MUTE BIT(6)
354ac690bbSMartin Povišer #define SSM3515_DAC_HPF BIT(5)
364ac690bbSMartin Povišer #define SSM3515_DAC_LPM BIT(4)
374ac690bbSMartin Povišer #define SSM3515_DAC_FS GENMASK(2, 0)
384ac690bbSMartin Povišer
394ac690bbSMartin Povišer #define SSM3515_DAC_VOL 0x03
404ac690bbSMartin Povišer
414ac690bbSMartin Povišer #define SSM3515_SAI1 0x04
424ac690bbSMartin Povišer #define SSM3515_SAI1_DAC_POL BIT(7)
434ac690bbSMartin Povišer #define SSM3515_SAI1_BCLK_POL BIT(6)
444ac690bbSMartin Povišer #define SSM3515_SAI1_TDM_BCLKS GENMASK(5, 3)
454ac690bbSMartin Povišer #define SSM3515_SAI1_FSYNC_MODE BIT(2)
464ac690bbSMartin Povišer #define SSM3515_SAI1_SDATA_FMT BIT(1)
474ac690bbSMartin Povišer #define SSM3515_SAI1_SAI_MODE BIT(0)
484ac690bbSMartin Povišer
494ac690bbSMartin Povišer #define SSM3515_SAI2 0x05
504ac690bbSMartin Povišer #define SSM3515_SAI2_DATA_WIDTH BIT(7)
514ac690bbSMartin Povišer #define SSM3515_SAI2_AUTO_SLOT BIT(4)
524ac690bbSMartin Povišer #define SSM3515_SAI2_TDM_SLOT GENMASK(3, 0)
534ac690bbSMartin Povišer
544ac690bbSMartin Povišer #define SSM3515_VBAT_OUT 0x06
554ac690bbSMartin Povišer
564ac690bbSMartin Povišer #define SSM3515_STATUS 0x0a
574ac690bbSMartin Povišer #define SSM3515_STATUS_UVLO_REG BIT(6)
584ac690bbSMartin Povišer #define SSM3515_STATUS_LIM_EG BIT(5)
594ac690bbSMartin Povišer #define SSM3515_STATUS_CLIP BIT(4)
604ac690bbSMartin Povišer #define SSM3515_STATUS_AMP_OC BIT(3)
614ac690bbSMartin Povišer #define SSM3515_STATUS_OTF BIT(2)
624ac690bbSMartin Povišer #define SSM3515_STATUS_OTW BIT(1)
634ac690bbSMartin Povišer #define SSM3515_STATUS_BAT_WARN BIT(0)
644ac690bbSMartin Povišer
ssm3515_volatile_reg(struct device * dev,unsigned int reg)654ac690bbSMartin Povišer static bool ssm3515_volatile_reg(struct device *dev, unsigned int reg)
664ac690bbSMartin Povišer {
674ac690bbSMartin Povišer switch (reg) {
684ac690bbSMartin Povišer case SSM3515_STATUS:
694ac690bbSMartin Povišer case SSM3515_VBAT_OUT:
704ac690bbSMartin Povišer return true;
714ac690bbSMartin Povišer
724ac690bbSMartin Povišer default:
734ac690bbSMartin Povišer return false;
744ac690bbSMartin Povišer }
754ac690bbSMartin Povišer }
764ac690bbSMartin Povišer
774ac690bbSMartin Povišer static const struct reg_default ssm3515_reg_defaults[] = {
784ac690bbSMartin Povišer { SSM3515_PWR, 0x81 },
794ac690bbSMartin Povišer { SSM3515_GEC, 0x01 },
804ac690bbSMartin Povišer { SSM3515_DAC, 0x32 },
814ac690bbSMartin Povišer { SSM3515_DAC_VOL, 0x40 },
824ac690bbSMartin Povišer { SSM3515_SAI1, 0x11 },
834ac690bbSMartin Povišer { SSM3515_SAI2, 0x00 },
844ac690bbSMartin Povišer };
854ac690bbSMartin Povišer
864ac690bbSMartin Povišer static const struct regmap_config ssm3515_i2c_regmap = {
874ac690bbSMartin Povišer .reg_bits = 8,
884ac690bbSMartin Povišer .val_bits = 8,
894ac690bbSMartin Povišer .volatile_reg = ssm3515_volatile_reg,
904ac690bbSMartin Povišer .max_register = 0xb,
914ac690bbSMartin Povišer .reg_defaults = ssm3515_reg_defaults,
924ac690bbSMartin Povišer .num_reg_defaults = ARRAY_SIZE(ssm3515_reg_defaults),
934ac690bbSMartin Povišer .cache_type = REGCACHE_FLAT,
944ac690bbSMartin Povišer };
954ac690bbSMartin Povišer
964ac690bbSMartin Povišer struct ssm3515_data {
974ac690bbSMartin Povišer struct device *dev;
984ac690bbSMartin Povišer struct regmap *regmap;
994ac690bbSMartin Povišer };
1004ac690bbSMartin Povišer
1014ac690bbSMartin Povišer // The specced range is -71.25...24.00 dB with step size of 0.375 dB,
1024ac690bbSMartin Povišer // and a mute item below that. This is represented by -71.62...24.00 dB
1034ac690bbSMartin Povišer // with the mute item mapped onto the low end.
1044ac690bbSMartin Povišer static DECLARE_TLV_DB_MINMAX_MUTE(ssm3515_dac_volume, -7162, 2400);
1054ac690bbSMartin Povišer
1064ac690bbSMartin Povišer static const char * const ssm3515_ana_gain_text[] = {
1074ac690bbSMartin Povišer "8.4 V Span", "12.6 V Span", "14 V Span", "15 V Span",
1084ac690bbSMartin Povišer };
1094ac690bbSMartin Povišer
1104ac690bbSMartin Povišer static SOC_ENUM_SINGLE_DECL(ssm3515_ana_gain_enum, SSM3515_GEC,
1114ac690bbSMartin Povišer __bf_shf(SSM3515_GEC_ANA_GAIN),
1124ac690bbSMartin Povišer ssm3515_ana_gain_text);
1134ac690bbSMartin Povišer
1144ac690bbSMartin Povišer static const struct snd_kcontrol_new ssm3515_snd_controls[] = {
1154ac690bbSMartin Povišer SOC_SINGLE_TLV("DAC Playback Volume", SSM3515_DAC_VOL,
1164ac690bbSMartin Povišer 0, 255, 1, ssm3515_dac_volume),
1174ac690bbSMartin Povišer SOC_SINGLE("Low EMI Mode Switch", SSM3515_GEC,
1184ac690bbSMartin Povišer __bf_shf(SSM3515_GEC_EDGE), 1, 0),
1194ac690bbSMartin Povišer SOC_SINGLE("Soft Volume Ramping Switch", SSM3515_DAC,
1204ac690bbSMartin Povišer __bf_shf(SSM3515_DAC_HV), 1, 1),
1214ac690bbSMartin Povišer SOC_SINGLE("HPF Switch", SSM3515_DAC,
1224ac690bbSMartin Povišer __bf_shf(SSM3515_DAC_HPF), 1, 0),
1234ac690bbSMartin Povišer SOC_SINGLE("DAC Invert Switch", SSM3515_SAI1,
1244ac690bbSMartin Povišer __bf_shf(SSM3515_SAI1_DAC_POL), 1, 0),
1254ac690bbSMartin Povišer SOC_ENUM("DAC Analog Gain Select", ssm3515_ana_gain_enum),
1264ac690bbSMartin Povišer };
1274ac690bbSMartin Povišer
ssm3515_read_faults(struct snd_soc_component * component)1284ac690bbSMartin Povišer static void ssm3515_read_faults(struct snd_soc_component *component)
1294ac690bbSMartin Povišer {
1304ac690bbSMartin Povišer int ret;
1314ac690bbSMartin Povišer
1324ac690bbSMartin Povišer ret = snd_soc_component_read(component, SSM3515_STATUS);
1334ac690bbSMartin Povišer if (ret <= 0) {
1344ac690bbSMartin Povišer /*
1354ac690bbSMartin Povišer * If the read was erroneous, ASoC core has printed a message,
1364ac690bbSMartin Povišer * and that's all that's appropriate in handling the error here.
1374ac690bbSMartin Povišer */
1384ac690bbSMartin Povišer return;
1394ac690bbSMartin Povišer }
1404ac690bbSMartin Povišer
1414ac690bbSMartin Povišer dev_err(component->dev, "device reports:%s%s%s%s%s%s%s\n",
1424ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_UVLO_REG, ret) ? " voltage regulator fault" : "",
1434ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_LIM_EG, ret) ? " limiter engaged" : "",
1444ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_CLIP, ret) ? " clipping detected" : "",
1454ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_AMP_OC, ret) ? " amp over-current fault" : "",
1464ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_OTF, ret) ? " overtemperature fault" : "",
1474ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_OTW, ret) ? " overtemperature warning" : "",
1484ac690bbSMartin Povišer FIELD_GET(SSM3515_STATUS_BAT_WARN, ret) ? " bat voltage low warning" : "");
1494ac690bbSMartin Povišer }
1504ac690bbSMartin Povišer
ssm3515_probe(struct snd_soc_component * component)1514ac690bbSMartin Povišer static int ssm3515_probe(struct snd_soc_component *component)
1524ac690bbSMartin Povišer {
1534ac690bbSMartin Povišer int ret;
1544ac690bbSMartin Povišer
1554ac690bbSMartin Povišer /* Start out muted */
1564ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component, SSM3515_DAC,
1574ac690bbSMartin Povišer SSM3515_DAC_MUTE, SSM3515_DAC_MUTE);
1584ac690bbSMartin Povišer if (ret < 0)
1594ac690bbSMartin Povišer return ret;
1604ac690bbSMartin Povišer
1614ac690bbSMartin Povišer /* Disable the 'master power-down' */
1624ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component, SSM3515_PWR,
1634ac690bbSMartin Povišer SSM3515_PWR_SPWDN, 0);
1644ac690bbSMartin Povišer if (ret < 0)
1654ac690bbSMartin Povišer return ret;
1664ac690bbSMartin Povišer
1674ac690bbSMartin Povišer return 0;
1684ac690bbSMartin Povišer }
1694ac690bbSMartin Povišer
ssm3515_mute(struct snd_soc_dai * dai,int mute,int direction)1704ac690bbSMartin Povišer static int ssm3515_mute(struct snd_soc_dai *dai, int mute, int direction)
1714ac690bbSMartin Povišer {
1724ac690bbSMartin Povišer int ret;
1734ac690bbSMartin Povišer
1744ac690bbSMartin Povišer ret = snd_soc_component_update_bits(dai->component,
1754ac690bbSMartin Povišer SSM3515_DAC,
1764ac690bbSMartin Povišer SSM3515_DAC_MUTE,
1774ac690bbSMartin Povišer FIELD_PREP(SSM3515_DAC_MUTE, mute));
1784ac690bbSMartin Povišer if (ret < 0)
1794ac690bbSMartin Povišer return ret;
1804ac690bbSMartin Povišer return 0;
1814ac690bbSMartin Povišer }
1824ac690bbSMartin Povišer
ssm3515_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1834ac690bbSMartin Povišer static int ssm3515_hw_params(struct snd_pcm_substream *substream,
1844ac690bbSMartin Povišer struct snd_pcm_hw_params *params,
1854ac690bbSMartin Povišer struct snd_soc_dai *dai)
1864ac690bbSMartin Povišer {
1874ac690bbSMartin Povišer struct snd_soc_component *component = dai->component;
1884ac690bbSMartin Povišer int ret, rateval;
1894ac690bbSMartin Povišer
1904ac690bbSMartin Povišer switch (params_format(params)) {
1914ac690bbSMartin Povišer case SNDRV_PCM_FORMAT_S16:
1924ac690bbSMartin Povišer case SNDRV_PCM_FORMAT_S24:
1934ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component,
1944ac690bbSMartin Povišer SSM3515_SAI2, SSM3515_SAI2_DATA_WIDTH,
1954ac690bbSMartin Povišer FIELD_PREP(SSM3515_SAI2_DATA_WIDTH,
1964ac690bbSMartin Povišer params_width(params) == 16));
1974ac690bbSMartin Povišer if (ret < 0)
1984ac690bbSMartin Povišer return ret;
1994ac690bbSMartin Povišer break;
2004ac690bbSMartin Povišer
2014ac690bbSMartin Povišer default:
2024ac690bbSMartin Povišer return -EINVAL;
2034ac690bbSMartin Povišer }
2044ac690bbSMartin Povišer
2054ac690bbSMartin Povišer switch (params_rate(params)) {
2064ac690bbSMartin Povišer case 8000 ... 12000:
2074ac690bbSMartin Povišer rateval = 0;
2084ac690bbSMartin Povišer break;
2094ac690bbSMartin Povišer case 16000 ... 24000:
2104ac690bbSMartin Povišer rateval = 1;
2114ac690bbSMartin Povišer break;
2124ac690bbSMartin Povišer case 32000 ... 48000:
2134ac690bbSMartin Povišer rateval = 2;
2144ac690bbSMartin Povišer break;
2154ac690bbSMartin Povišer case 64000 ... 96000:
2164ac690bbSMartin Povišer rateval = 3;
2174ac690bbSMartin Povišer break;
2184ac690bbSMartin Povišer case 128000 ... 192000:
2194ac690bbSMartin Povišer rateval = 4;
2204ac690bbSMartin Povišer break;
2214ac690bbSMartin Povišer case 48001 ... 63999: /* this is ...72000 but overlaps */
2224ac690bbSMartin Povišer rateval = 5;
2234ac690bbSMartin Povišer break;
2244ac690bbSMartin Povišer default:
2254ac690bbSMartin Povišer return -EINVAL;
2264ac690bbSMartin Povišer }
2274ac690bbSMartin Povišer
2284ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component,
2294ac690bbSMartin Povišer SSM3515_DAC, SSM3515_DAC_FS,
2304ac690bbSMartin Povišer FIELD_PREP(SSM3515_DAC_FS, rateval));
2314ac690bbSMartin Povišer if (ret < 0)
2324ac690bbSMartin Povišer return ret;
2334ac690bbSMartin Povišer
2344ac690bbSMartin Povišer return 0;
2354ac690bbSMartin Povišer }
2364ac690bbSMartin Povišer
ssm3515_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)2374ac690bbSMartin Povišer static int ssm3515_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2384ac690bbSMartin Povišer {
2394ac690bbSMartin Povišer struct snd_soc_component *component = dai->component;
2404ac690bbSMartin Povišer bool fpol_inv = false; /* non-inverted: frame starts with low-to-high FSYNC */
2414ac690bbSMartin Povišer int ret;
2424ac690bbSMartin Povišer u8 sai1 = 0;
2434ac690bbSMartin Povišer
2444ac690bbSMartin Povišer switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
2454ac690bbSMartin Povišer case SND_SOC_DAIFMT_IB_NF:
2464ac690bbSMartin Povišer case SND_SOC_DAIFMT_IB_IF:
2474ac690bbSMartin Povišer sai1 |= SSM3515_SAI1_BCLK_POL;
2484ac690bbSMartin Povišer break;
2494ac690bbSMartin Povišer }
2504ac690bbSMartin Povišer
2514ac690bbSMartin Povišer switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2524ac690bbSMartin Povišer case SND_SOC_DAIFMT_I2S:
2534ac690bbSMartin Povišer fpol_inv = 1;
2544ac690bbSMartin Povišer sai1 &= ~SSM3515_SAI1_SDATA_FMT; /* 1 bit start delay */
2554ac690bbSMartin Povišer break;
2564ac690bbSMartin Povišer case SND_SOC_DAIFMT_LEFT_J:
2574ac690bbSMartin Povišer fpol_inv = 0;
2584ac690bbSMartin Povišer sai1 |= SSM3515_SAI1_SDATA_FMT; /* no start delay */
2594ac690bbSMartin Povišer break;
2604ac690bbSMartin Povišer default:
2614ac690bbSMartin Povišer return -EINVAL;
2624ac690bbSMartin Povišer }
2634ac690bbSMartin Povišer
2644ac690bbSMartin Povišer switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
2654ac690bbSMartin Povišer case SND_SOC_DAIFMT_NB_IF:
2664ac690bbSMartin Povišer case SND_SOC_DAIFMT_IB_IF:
2674ac690bbSMartin Povišer fpol_inv ^= 1;
2684ac690bbSMartin Povišer break;
2694ac690bbSMartin Povišer }
2704ac690bbSMartin Povišer
2714ac690bbSMartin Povišer /* Set the serial input to 'TDM mode' */
2724ac690bbSMartin Povišer sai1 |= SSM3515_SAI1_SAI_MODE;
2734ac690bbSMartin Povišer
2744ac690bbSMartin Povišer if (fpol_inv) {
2754ac690bbSMartin Povišer /*
2764ac690bbSMartin Povišer * We configure the codec in a 'TDM mode', in which the
2774ac690bbSMartin Povišer * FSYNC_MODE bit of SAI1 is supposed to select between
2784ac690bbSMartin Povišer * what the datasheet calls 'Pulsed FSYNC mode' and '50%
2794ac690bbSMartin Povišer * FSYNC mode'.
2804ac690bbSMartin Povišer *
2814ac690bbSMartin Povišer * Experiments suggest that this bit in fact simply selects
2824ac690bbSMartin Povišer * the FSYNC polarity, so go with that.
2834ac690bbSMartin Povišer */
2844ac690bbSMartin Povišer sai1 |= SSM3515_SAI1_FSYNC_MODE;
2854ac690bbSMartin Povišer }
2864ac690bbSMartin Povišer
2874ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component, SSM3515_SAI1,
2884ac690bbSMartin Povišer SSM3515_SAI1_BCLK_POL | SSM3515_SAI1_SDATA_FMT |
2894ac690bbSMartin Povišer SSM3515_SAI1_SAI_MODE | SSM3515_SAI1_FSYNC_MODE, sai1);
2904ac690bbSMartin Povišer
2914ac690bbSMartin Povišer if (ret < 0)
2924ac690bbSMartin Povišer return ret;
2934ac690bbSMartin Povišer return 0;
2944ac690bbSMartin Povišer }
2954ac690bbSMartin Povišer
ssm3515_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)2964ac690bbSMartin Povišer static int ssm3515_set_tdm_slot(struct snd_soc_dai *dai,
2974ac690bbSMartin Povišer unsigned int tx_mask,
2984ac690bbSMartin Povišer unsigned int rx_mask,
2994ac690bbSMartin Povišer int slots, int slot_width)
3004ac690bbSMartin Povišer {
3014ac690bbSMartin Povišer struct snd_soc_component *component = dai->component;
3024ac690bbSMartin Povišer int slot, tdm_bclks_val, ret;
3034ac690bbSMartin Povišer
3044ac690bbSMartin Povišer if (tx_mask == 0 || rx_mask != 0)
3054ac690bbSMartin Povišer return -EINVAL;
3064ac690bbSMartin Povišer
3074ac690bbSMartin Povišer slot = __ffs(tx_mask);
3084ac690bbSMartin Povišer
3094ac690bbSMartin Povišer if (tx_mask & ~BIT(slot))
3104ac690bbSMartin Povišer return -EINVAL;
3114ac690bbSMartin Povišer
3124ac690bbSMartin Povišer switch (slot_width) {
3134ac690bbSMartin Povišer case 16:
3144ac690bbSMartin Povišer tdm_bclks_val = 0;
3154ac690bbSMartin Povišer break;
3164ac690bbSMartin Povišer case 24:
3174ac690bbSMartin Povišer tdm_bclks_val = 1;
3184ac690bbSMartin Povišer break;
3194ac690bbSMartin Povišer case 32:
3204ac690bbSMartin Povišer tdm_bclks_val = 2;
3214ac690bbSMartin Povišer break;
3224ac690bbSMartin Povišer case 48:
3234ac690bbSMartin Povišer tdm_bclks_val = 3;
3244ac690bbSMartin Povišer break;
3254ac690bbSMartin Povišer case 64:
3264ac690bbSMartin Povišer tdm_bclks_val = 4;
3274ac690bbSMartin Povišer break;
3284ac690bbSMartin Povišer default:
3294ac690bbSMartin Povišer return -EINVAL;
3304ac690bbSMartin Povišer }
3314ac690bbSMartin Povišer
3324ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component, SSM3515_SAI1,
3334ac690bbSMartin Povišer SSM3515_SAI1_TDM_BCLKS,
3344ac690bbSMartin Povišer FIELD_PREP(SSM3515_SAI1_TDM_BCLKS, tdm_bclks_val));
3354ac690bbSMartin Povišer if (ret < 0)
3364ac690bbSMartin Povišer return ret;
3374ac690bbSMartin Povišer
3384ac690bbSMartin Povišer ret = snd_soc_component_update_bits(component, SSM3515_SAI2,
3394ac690bbSMartin Povišer SSM3515_SAI2_TDM_SLOT,
3404ac690bbSMartin Povišer FIELD_PREP(SSM3515_SAI2_TDM_SLOT, slot));
3414ac690bbSMartin Povišer if (ret < 0)
3424ac690bbSMartin Povišer return ret;
3434ac690bbSMartin Povišer
3444ac690bbSMartin Povišer return 0;
3454ac690bbSMartin Povišer }
3464ac690bbSMartin Povišer
ssm3515_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3474ac690bbSMartin Povišer static int ssm3515_hw_free(struct snd_pcm_substream *substream,
3484ac690bbSMartin Povišer struct snd_soc_dai *dai)
3494ac690bbSMartin Povišer {
3504ac690bbSMartin Povišer /*
3514ac690bbSMartin Povišer * We don't get live notification of faults, so at least at
3524ac690bbSMartin Povišer * this time, when playback is over, check if we have tripped
3534ac690bbSMartin Povišer * over anything and if so, log it.
3544ac690bbSMartin Povišer */
3554ac690bbSMartin Povišer ssm3515_read_faults(dai->component);
3564ac690bbSMartin Povišer return 0;
3574ac690bbSMartin Povišer }
3584ac690bbSMartin Povišer
3594ac690bbSMartin Povišer static const struct snd_soc_dai_ops ssm3515_dai_ops = {
3604ac690bbSMartin Povišer .mute_stream = ssm3515_mute,
3614ac690bbSMartin Povišer .hw_params = ssm3515_hw_params,
3624ac690bbSMartin Povišer .set_fmt = ssm3515_set_fmt,
3634ac690bbSMartin Povišer .set_tdm_slot = ssm3515_set_tdm_slot,
3644ac690bbSMartin Povišer .hw_free = ssm3515_hw_free,
3654ac690bbSMartin Povišer };
3664ac690bbSMartin Povišer
3674ac690bbSMartin Povišer static struct snd_soc_dai_driver ssm3515_dai_driver = {
3684ac690bbSMartin Povišer .name = "SSM3515 SAI",
3694ac690bbSMartin Povišer .id = 0,
3704ac690bbSMartin Povišer .playback = {
3714ac690bbSMartin Povišer .stream_name = "Playback",
3724ac690bbSMartin Povišer .channels_min = 1,
3734ac690bbSMartin Povišer .channels_max = 1,
3744ac690bbSMartin Povišer .rates = SNDRV_PCM_RATE_CONTINUOUS,
3754ac690bbSMartin Povišer .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
3764ac690bbSMartin Povišer },
3774ac690bbSMartin Povišer .ops = &ssm3515_dai_ops,
3784ac690bbSMartin Povišer };
3794ac690bbSMartin Povišer
3804ac690bbSMartin Povišer static const struct snd_soc_dapm_widget ssm3515_dapm_widgets[] = {
3814ac690bbSMartin Povišer SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
3824ac690bbSMartin Povišer SND_SOC_DAPM_OUTPUT("OUT"),
3834ac690bbSMartin Povišer };
3844ac690bbSMartin Povišer
3854ac690bbSMartin Povišer static const struct snd_soc_dapm_route ssm3515_dapm_routes[] = {
3864ac690bbSMartin Povišer {"OUT", NULL, "DAC"},
3874ac690bbSMartin Povišer {"DAC", NULL, "Playback"},
3884ac690bbSMartin Povišer };
3894ac690bbSMartin Povišer
3904ac690bbSMartin Povišer static const struct snd_soc_component_driver ssm3515_asoc_component = {
3914ac690bbSMartin Povišer .probe = ssm3515_probe,
3924ac690bbSMartin Povišer .controls = ssm3515_snd_controls,
3934ac690bbSMartin Povišer .num_controls = ARRAY_SIZE(ssm3515_snd_controls),
3944ac690bbSMartin Povišer .dapm_widgets = ssm3515_dapm_widgets,
3954ac690bbSMartin Povišer .num_dapm_widgets = ARRAY_SIZE(ssm3515_dapm_widgets),
3964ac690bbSMartin Povišer .dapm_routes = ssm3515_dapm_routes,
3974ac690bbSMartin Povišer .num_dapm_routes = ARRAY_SIZE(ssm3515_dapm_routes),
3984ac690bbSMartin Povišer .endianness = 1,
3994ac690bbSMartin Povišer };
4004ac690bbSMartin Povišer
ssm3515_i2c_probe(struct i2c_client * client)4014ac690bbSMartin Povišer static int ssm3515_i2c_probe(struct i2c_client *client)
4024ac690bbSMartin Povišer {
4034ac690bbSMartin Povišer struct ssm3515_data *data;
4044ac690bbSMartin Povišer int ret;
4054ac690bbSMartin Povišer
4064ac690bbSMartin Povišer data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
4074ac690bbSMartin Povišer if (!data)
4084ac690bbSMartin Povišer return -ENOMEM;
4094ac690bbSMartin Povišer
4104ac690bbSMartin Povišer data->dev = &client->dev;
4114ac690bbSMartin Povišer i2c_set_clientdata(client, data);
4124ac690bbSMartin Povišer
4134ac690bbSMartin Povišer data->regmap = devm_regmap_init_i2c(client, &ssm3515_i2c_regmap);
4144ac690bbSMartin Povišer if (IS_ERR(data->regmap))
4154ac690bbSMartin Povišer return dev_err_probe(data->dev, PTR_ERR(data->regmap),
4164ac690bbSMartin Povišer "initializing register map\n");
4174ac690bbSMartin Povišer
4184ac690bbSMartin Povišer /* Perform a reset */
4194ac690bbSMartin Povišer ret = regmap_update_bits(data->regmap, SSM3515_PWR,
4204ac690bbSMartin Povišer SSM3515_PWR_S_RST, SSM3515_PWR_S_RST);
4214ac690bbSMartin Povišer if (ret < 0)
4224ac690bbSMartin Povišer return dev_err_probe(data->dev, ret,
4234ac690bbSMartin Povišer "performing software reset\n");
4244ac690bbSMartin Povišer regmap_reinit_cache(data->regmap, &ssm3515_i2c_regmap);
4254ac690bbSMartin Povišer
4264ac690bbSMartin Povišer return devm_snd_soc_register_component(data->dev,
4274ac690bbSMartin Povišer &ssm3515_asoc_component,
4284ac690bbSMartin Povišer &ssm3515_dai_driver, 1);
4294ac690bbSMartin Povišer }
4304ac690bbSMartin Povišer
4314ac690bbSMartin Povišer static const struct of_device_id ssm3515_of_match[] = {
4324ac690bbSMartin Povišer { .compatible = "adi,ssm3515" },
4334ac690bbSMartin Povišer {}
4344ac690bbSMartin Povišer };
4354ac690bbSMartin Povišer MODULE_DEVICE_TABLE(of, ssm3515_of_match);
4364ac690bbSMartin Povišer
4374ac690bbSMartin Povišer static struct i2c_driver ssm3515_i2c_driver = {
4384ac690bbSMartin Povišer .driver = {
4394ac690bbSMartin Povišer .name = "ssm3515",
440*6136b6a2SRuan Jinjie .of_match_table = ssm3515_of_match,
4414ac690bbSMartin Povišer },
442947e3960SUwe Kleine-König .probe = ssm3515_i2c_probe,
4434ac690bbSMartin Povišer };
4444ac690bbSMartin Povišer module_i2c_driver(ssm3515_i2c_driver);
4454ac690bbSMartin Povišer
4464ac690bbSMartin Povišer MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
4474ac690bbSMartin Povišer MODULE_DESCRIPTION("ASoC SSM3515 audio amp driver");
4484ac690bbSMartin Povišer MODULE_LICENSE("Dual MIT/GPL");
449