blob: d7bbfe383f13466f7b52343930e0f8abf9e92a61 [file] [log] [blame]
/*
* sound/soc/codecs/amlogic/tas5782m.c
*
* Copyright (C) 2019 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/tas57xx.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include "tas5782m.h"
#define DEV_NAME "tas5782m"
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
static void tas5782m_early_suspend(struct early_suspend *h);
static void tas5782m_late_resume(struct early_suspend *h);
#endif
#define tas5782m_RATES (SNDRV_PCM_RATE_8000 | \
SNDRV_PCM_RATE_11025 | \
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
#define tas5782m_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define TAS5782M_REG_00 (0x00)
#define TAS5782M_REG_03 (0x03)
#define TAS5782M_REG_7F (0x7F)
#define TAS5782M_REG_28 (0x28)
#define TAS5782M_REG_29 (0x29)
#define TAS5782M_REG_3D (0x3D)
#define TAS5782M_REG_3E (0x3E)
enum BITSIZE_MODE {
BITSIZE_MODE_16BITS = 0,
BITSIZE_MODE_20BITS = 1,
BITSIZE_MODE_24BITS = 2,
BITSIZE_MODE_32BITS = 3,
};
/* codec private data */
struct tas5782m_priv {
struct i2c_client *i2c;
struct regmap *regmap;
struct snd_soc_codec *codec;
struct tas57xx_platform_data *pdata;
struct work_struct work;
unsigned int work_mode;
unsigned int chip_offset;
/*Platform provided EQ configuration */
int num_eq_conf_texts;
const char **eq_conf_texts;
int eq_cfg;
struct soc_enum eq_conf_enum;
unsigned char Ch1_vol;
unsigned char Ch2_vol;
unsigned char Ch1_mute;
unsigned char Ch2_mute;
unsigned char master_vol;
unsigned int mclk;
unsigned int EQ_enum_value;
unsigned int DRC_enum_value;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
};
static int g_sample_bitsize = 32;
static int tas5782m_ch1_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
| SNDRV_CTL_ELEM_ACCESS_READWRITE;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0xff;
uinfo->value.integer.step = 1;
return 0;
}
static int tas5782m_ch2_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
| SNDRV_CTL_ELEM_ACCESS_READWRITE;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0xff;
uinfo->value.integer.step = 1;
return 0;
}
static int tas5782m_ch1_mute_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
| SNDRV_CTL_ELEM_ACCESS_READWRITE;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
uinfo->value.integer.step = 1;
return 0;
}
static int tas5782m_ch2_mute_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
| SNDRV_CTL_ELEM_ACCESS_READWRITE;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
uinfo->value.integer.step = 1;
return 0;
}
static int tas5782m_ch1_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = tas5782m->Ch1_vol;
return 0;
}
static int tas5782m_ch2_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = tas5782m->Ch2_vol;
return 0;
}
static int tas5782m_ch1_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = tas5782m->Ch1_mute;
return 0;
}
static int tas5782m_ch2_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = tas5782m->Ch2_mute;
return 0;
}
static void tas5782m_set_volume(struct snd_soc_codec *codec,
int value, int ch_num)
{
unsigned char buf[2];
int write_count = 0;
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
if (value < 0)
value = 0;
if (value > 255)
value = 255;
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_7F, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = (ch_num == 0) ? TAS5782M_REG_3D : TAS5782M_REG_3E;
buf[1] = value;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
}
static int tas5782m_ch1_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
int value;
value = ucontrol->value.integer.value[0];
tas5782m->Ch1_vol = value;
value = 255 - value;
tas5782m_set_volume(codec, value, 0);
return 0;
}
static int tas5782m_ch2_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
int value;
value = ucontrol->value.integer.value[0];
tas5782m->Ch2_vol = value;
value = 255 - value;
tas5782m_set_volume(codec, value, 1);
return 0;
}
static void tas5782m_set_mute(struct snd_soc_codec *codec,
unsigned char left_mute,
unsigned char right_mute)
{
unsigned char buf[2];
int write_count = 0;
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_7F, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_03;
buf[1] = left_mute << 4 | right_mute;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
}
static int tas5782m_ch1_mute_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
int value;
value = ucontrol->value.integer.value[0];
tas5782m->Ch1_mute = value;
tas5782m_set_mute(codec, tas5782m->Ch1_mute, tas5782m->Ch2_mute);
return 0;
}
static int tas5782m_ch2_mute_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
int value;
value = ucontrol->value.integer.value[0];
tas5782m->Ch2_mute = value;
tas5782m_set_mute(codec, tas5782m->Ch1_mute, tas5782m->Ch2_mute);
return 0;
}
static const struct snd_kcontrol_new tas5782m_snd_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Ch1 Volume",
.info = tas5782m_ch1_vol_info,
.get = tas5782m_ch1_vol_get,
.put = tas5782m_ch1_vol_put,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Ch2 Volume",
.info = tas5782m_ch2_vol_info,
.get = tas5782m_ch2_vol_get,
.put = tas5782m_ch2_vol_put,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Ch1 Mute",
.info = tas5782m_ch1_mute_info,
.get = tas5782m_ch1_mute_get,
.put = tas5782m_ch1_mute_set,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Ch2 Mute",
.info = tas5782m_ch2_mute_info,
.get = tas5782m_ch2_mute_get,
.put = tas5782m_ch2_mute_set,
}
};
static int tas5782m_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
return 0;
}
static int tas5782m_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
return 0;//-EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_LEFT_J:
break;
default:
return 0;//-EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_NB_IF:
break;
default:
return 0;//-EINVAL;
}
return 0;
}
static int tas5782m_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
unsigned int rate;
rate = params_rate(params);
pr_debug("rate: %u\n", rate);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_BE:
pr_debug("24bit\n");
/* fall through */
case SNDRV_PCM_FORMAT_S32_LE:
case SNDRV_PCM_FORMAT_S20_3LE:
case SNDRV_PCM_FORMAT_S20_3BE:
pr_debug("20bit\n");
break;
case SNDRV_PCM_FORMAT_S16_LE:
case SNDRV_PCM_FORMAT_S16_BE:
pr_debug("16bit\n");
break;
default:
return -EINVAL;
}
return 0;
}
static int tas5782m_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
pr_debug("level = %d\n", level);
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
/* Full power on */
break;
case SND_SOC_BIAS_STANDBY:
break;
case SND_SOC_BIAS_OFF:
/* The chip runs through the power down sequence for us. */
break;
}
codec->component.dapm.bias_level = level;
return 0;
}
static const struct snd_soc_dai_ops tas5782m_dai_ops = {
.hw_params = tas5782m_hw_params,
.set_sysclk = tas5782m_set_dai_sysclk,
.set_fmt = tas5782m_set_dai_fmt,
};
static struct snd_soc_dai_driver tas5782m_dai = {
.name = DEV_NAME,
.playback = {
.stream_name = "HIFI Playback",
.channels_min = 2,
.channels_max = 8,
.rates = tas5782m_RATES,
.formats = tas5782m_FORMATS,
},
.ops = &tas5782m_dai_ops,
};
static int reset_tas5782m_GPIO(struct snd_soc_codec *codec)
{
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
struct tas57xx_platform_data *pdata = tas5782m->pdata;
int ret = 0;
if (pdata->reset_pin < 0)
return 0;
ret = devm_gpio_request_one(codec->dev, pdata->reset_pin,
GPIOF_OUT_INIT_LOW, "tas5782m-reset-pin");
if (ret < 0) {
pr_err("failed!!! devm_gpio_request_one = %d!\n", ret);
return -1;
}
gpio_direction_output(pdata->reset_pin, GPIOF_OUT_INIT_HIGH);
udelay(1000);
gpio_direction_output(pdata->reset_pin, GPIOF_OUT_INIT_LOW);
udelay(1000);
gpio_direction_output(pdata->reset_pin, GPIOF_OUT_INIT_HIGH);
msleep(20);
return 0;
}
static int tas5782m_init_i2s_tdm_mode(struct snd_soc_codec *codec, int bit_size)
{
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
int work_mod = tas5782m->work_mode;
int tdm_aofs = 0;
unsigned char buf[8] = {0};
int write_count = 0;
enum BITSIZE_MODE bit_value = BITSIZE_MODE_32BITS;
write_count = 2;
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_7F, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
if (bit_size == 16)
bit_value = BITSIZE_MODE_16BITS;
else if (bit_size == 20)
bit_value = BITSIZE_MODE_20BITS;
else if (bit_size == 24)
bit_value = BITSIZE_MODE_24BITS;
else if (bit_size == 32)
bit_value = BITSIZE_MODE_32BITS;
buf[0] = TAS5782M_REG_28, buf[1] = (work_mod << 4) | bit_value;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf, write_count)) {
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
} else {
pr_debug("%s %d reg:0x%x, chip_offset:%d reg_off:0x%x data:0x%x\n",
__func__, __LINE__, tas5782m->i2c->addr,
tas5782m->chip_offset, buf[0], buf[1]);
}
if (work_mod == WORK_MODE_TDM) {
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf,
write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_7F, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf,
write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
buf[0] = TAS5782M_REG_00, buf[1] = 0x00;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf,
write_count))
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
tdm_aofs = bit_size * 2 * (tas5782m->chip_offset - 1);
buf[0] = TAS5782M_REG_29, buf[1] = tdm_aofs;
write_count = 2;
if (write_count != i2c_master_send(tas5782m->i2c, buf,
write_count)) {
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
} else {
pr_debug("%s %d reg:0x%x, chip_offset:%d reg_off:0x%x",
__func__, __LINE__, tas5782m->i2c->addr,
tas5782m->chip_offset, buf[0]);
pr_debug("tdm_aofs:0x%x SCLKS\n", tdm_aofs);
}
}
return 0;
}
static void tas5782m_init_func(struct work_struct *p_work)
{
struct tas5782m_priv *tas5782m;
struct snd_soc_codec *codec;
struct i2c_client *i2c;
int i = 0, j = 0, k = 0;
int value_count;
unsigned char buf[64] = {0};
int write_count = 0;
int data_row = 0;
tas5782m = container_of(
p_work, struct tas5782m_priv, work);
codec = tas5782m->codec;
reset_tas5782m_GPIO(codec);
//init register
tas5782m = snd_soc_codec_get_drvdata(codec);
dev_info(codec->dev, "tas5782m_init id=%d\n", tas5782m->chip_offset);
i2c = tas5782m->i2c;
value_count = ARRAY_SIZE(tas5782m_reg_defaults);
for (i = 0; i < value_count;) {
if (tas5782m_reg_defaults[i].reg == CFG_META_BURST) {
if (tas5782m_reg_defaults[i].def == 2) {
data_row = 1;
write_count =
tas5782m_reg_defaults[i].def;
} else {
data_row =
(tas5782m_reg_defaults[i].def
+ 2) >> 1;
write_count =
tas5782m_reg_defaults[i].def
+ 1;
}
i++;
j = 0, k = 0;
for (k = 0; k < data_row; k++) {
buf[j++] =
tas5782m_reg_defaults[i+k].reg;
buf[j++] =
tas5782m_reg_defaults[i+k].def;
}
i += data_row;
//dump_buf(buf, k);
if (write_count !=
i2c_master_send(i2c, buf,
write_count)) {
pr_err("%s %d !!!!! i2c_master_send error !!!!!\n",
__func__, __LINE__);
break;
}
} else {
i++;
pr_info("%s %d warning: register value error!\n",
__func__, __LINE__);
}
}
tas5782m_init_i2s_tdm_mode(codec, g_sample_bitsize);
}
static int tas5782m_probe(struct snd_soc_codec *codec)
{
struct tas5782m_priv *tas5782m;
#ifdef CONFIG_HAS_EARLYSUSPEND
tas5782m->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
tas5782m->early_suspend.suspend = tas5782m_early_suspend;
tas5782m->early_suspend.resume = tas5782m_late_resume;
tas5782m->early_suspend.param = codec;
register_early_suspend(&(tas5782m->early_suspend));
#endif
tas5782m = snd_soc_codec_get_drvdata(codec);
tas5782m->codec = codec;
INIT_WORK(&tas5782m->work, tas5782m_init_func);
schedule_work(&tas5782m->work);
return 0;
}
static int tas5782m_remove(struct snd_soc_codec *codec)
{
struct tas5782m_priv *tas5782m;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct tas5782m_priv *tas5782m = snd_soc_codec_get_drvdata(codec);
unregister_early_suspend(&(tas5782m->early_suspend));
#endif
tas5782m = snd_soc_codec_get_drvdata(codec);
cancel_work_sync(&tas5782m->work);
return 0;
}
#ifdef CONFIG_PM
static int tas5782m_suspend(struct snd_soc_codec *codec)
{
struct tas57xx_platform_data *pdata = dev_get_platdata(codec->dev);
dev_info(codec->dev, "tas5782m_suspend!\n");
if (pdata && pdata->suspend_func)
pdata->suspend_func();
return 0;
}
static int tas5782m_resume(struct snd_soc_codec *codec)
{
struct tas57xx_platform_data *pdata = dev_get_platdata(codec->dev);
struct tas5782m_priv *tas5782m;
dev_info(codec->dev, "tas5782m_resume!\n");
if (pdata && pdata->resume_func)
pdata->resume_func();
tas5782m = snd_soc_codec_get_drvdata(codec);
tas5782m->codec = codec;
INIT_WORK(&tas5782m->work, tas5782m_init_func);
schedule_work(&tas5782m->work);
return 0;
}
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
static void tas5782m_early_suspend(struct early_suspend *h)
{
}
static void tas5782m_late_resume(struct early_suspend *h)
{
}
#endif
static const struct snd_soc_dapm_widget tas5782m_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "HIFI Playback", SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_codec_driver soc_codec_dev_tas5782m = {
.probe = tas5782m_probe,
.remove = tas5782m_remove,
#ifdef CONFIG_PM
.suspend = tas5782m_suspend,
.resume = tas5782m_resume,
#endif
.set_bias_level = tas5782m_set_bias_level,
.component_driver = {
.controls = tas5782m_snd_controls,
.num_controls = ARRAY_SIZE(tas5782m_snd_controls),
.dapm_widgets = tas5782m_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tas5782m_dapm_widgets),
}
};
/*
*static const struct regmap_config tas5782m_regmap = {
* .reg_bits = 8,
* .val_bits = 8,
*
* .max_register = tas5782m_REGISTER_COUNT,
* .reg_defaults = tas5782m_reg_defaults,
* .num_reg_defaults =
* sizeof(tas5782m_reg_defaults)/sizeof(tas5782m_reg_defaults[0]),
* .cache_type = REGCACHE_RBTREE,
*};
*/
static int tas5782m_parse_dts(struct tas5782m_priv *tas5782m,
struct device_node *np)
{
int ret = 0;
int reset_pin = -1;
reset_pin = of_get_named_gpio(np, "reset_pin", 0);
if (reset_pin < 0) {
pr_err("%s fail to get reset pin from dts!\n", __func__);
ret = -1;
} else {
pr_debug("%s pdata->reset_pin = %d!\n", __func__, reset_pin);
}
tas5782m->pdata->reset_pin = reset_pin;
ret = of_property_read_u32(np, "work_mode", &tas5782m->work_mode);
pr_debug("tas5782m->work_mode:%d(%s)!\n", tas5782m->work_mode,
(tas5782m->work_mode == WORK_MODE_I2S)?"i2s":"tdm");
ret = of_property_read_u32(np, "chip_offset", &tas5782m->chip_offset);
pr_debug("tas5782m->chip_offset:%d!\n", tas5782m->chip_offset);
return ret;
}
static int tas5782m_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tas5782m_priv *tas5782m;
struct tas57xx_platform_data *pdata;
int ret;
const char *codec_name = NULL;
pr_debug("i2c->addr=0x%x\n", i2c->addr);
tas5782m = devm_kzalloc(&i2c->dev,
sizeof(struct tas5782m_priv), GFP_KERNEL);
if (!tas5782m)
return -ENOMEM;
tas5782m->i2c = i2c;
/*
* tas5782m->regmap = devm_regmap_init_i2c(i2c, &tas5782m_regmap);
* if (IS_ERR(tas5782m->regmap)) {
* ret = PTR_ERR(tas5782m->regmap);
* dev_err(&i2c->dev,
* "Failed to allocate register map: %d\n", ret);
* return ret;
* }
*/
pdata = devm_kzalloc(&i2c->dev,
sizeof(struct tas57xx_platform_data), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
tas5782m->pdata = pdata;
tas5782m_parse_dts(tas5782m, i2c->dev.of_node);
if (of_property_read_string(i2c->dev.of_node,
"codec_name", &codec_name)) {
pr_info("no codec name\n");
ret = -1;
}
pr_debug("aux name = %s\n", codec_name);
if (codec_name)
dev_set_name(&i2c->dev, "%s", codec_name);
i2c_set_clientdata(i2c, tas5782m);
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_tas5782m, &tas5782m_dai, 1);
if (ret != 0)
dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
return ret;
}
static int tas5782m_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
return 0;
}
static const struct i2c_device_id tas5782m_i2c_id[] = {
{ "tas5782m", 0 },
{}
};
static const struct of_device_id tas5782m_of_id[] = {
{.compatible = "ti, tas5782m",},
{ /* senitel */ }
};
MODULE_DEVICE_TABLE(of, tas5782m_of_id);
static struct i2c_driver tas5782m_i2c_driver = {
.driver = {
.name = DEV_NAME,
.of_match_table = tas5782m_of_id,
.owner = THIS_MODULE,
},
.probe = tas5782m_i2c_probe,
.remove = tas5782m_i2c_remove,
.id_table = tas5782m_i2c_id,
};
module_i2c_driver(tas5782m_i2c_driver);
MODULE_DESCRIPTION("ASoC tas5782m driver");
MODULE_AUTHOR("AML MM team");
MODULE_LICENSE("GPL");