ASoC: codecs: add tc358749x codec driver

add tc358749x codec driver for hdmiin function

Change-Id: I819ac80ced59b5d81d547f7ba2c7ebc7bee7f845
Signed-off-by: LuoXiaoTan <lxt@rock-chips.com>
This commit is contained in:
LuoXiaoTan
2017-04-14 02:44:58 -07:00
committed by Huang, Tao
parent cd13e47893
commit 80eba80559
4 changed files with 367 additions and 0 deletions

View File

@@ -689,6 +689,10 @@ config SND_SOC_TAS571X
tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
depends on I2C
config SND_SOC_TC358749X
tristate "Toshiba TC358749X HDMI in Audio codec"
depends on I2C
config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C

View File

@@ -121,6 +121,7 @@ snd-soc-stac9766-objs := stac9766.o
snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tc358749x-objs := tc358749x.o
snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
@@ -319,6 +320,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TC358749X) += snd-soc-tc358749x.o
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o

View File

@@ -0,0 +1,308 @@
/*
* tc358749x.c TC358749XBG ALSA SoC audio codec driver
*
* Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd
* Author: Roy <luoxiaotan@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
*
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <sound/soc.h>
#include "tc358749x.h"
static int snd_tc358749x_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
unsigned int fs;
switch (params_rate(params)) {
case 32000:
fs = FS_32000;
break;
case 44100:
fs = FS_44100;
break;
case 48000:
fs = FS_48000;
break;
case 88200:
fs = FS_88200;
break;
case 96000:
fs = FS_96000;
break;
case 176400:
fs = FS_176400;
break;
case 192000:
fs = FS_192000;
break;
default:
dev_err(codec->dev, "Enter:%s, %d, Error rate=%d\n",
__func__, __LINE__, params_rate(params));
return -EINVAL;
}
snd_soc_update_bits(codec, TC358749X_FS_SET, FS_SET_MASK, fs);
return 0;
}
static int snd_tc358749x_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
if (mute)
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
FORCE_DMUTE_MASK, MUTE);
else
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
FORCE_DMUTE_MASK, !MUTE);
return 0;
}
static const struct snd_soc_dai_ops tc358749x_dai_ops = {
.hw_params = snd_tc358749x_dai_hw_params,
.digital_mute = snd_tc358749x_mute,
};
static struct snd_soc_dai_driver tc358749x_dai = {
.name = "tc358749x-audio",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &tc358749x_dai_ops,
};
static int tc358749x_probe(struct snd_soc_codec *codec)
{
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int tc358749_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
FORCE_DMUTE_MASK, !MUTE);
break;
case SND_SOC_BIAS_STANDBY:
break;
case SND_SOC_BIAS_OFF:
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
FORCE_DMUTE_MASK, MUTE);
break;
}
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_tc358749x = {
.probe = tc358749x_probe,
.set_bias_level = tc358749_set_bias_level,
};
static bool tc358749x_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case TC358749X_FORCE_MUTE:
case TC358749X_FS_SET:
return true;
default:
return false;
}
}
static const struct reg_default tc358749x_reg_defaults[] = {
{ TC358749X_FORCE_MUTE, 0xb1 },
{ TC358749X_FS_SET, 0x00 },
};
const struct regmap_config tc358749x_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.max_register = TC358749X_FS_SET,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = tc358749x_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tc358749x_reg_defaults),
.readable_reg = tc358749x_readable_register,
};
static const struct i2c_device_id tc358749x_i2c_id[] = {
{ "tc358749x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc358749x_i2c_id);
static int tc358749x_parse_dts(struct i2c_client *i2c,
struct tc358749x_priv *tc358749x)
{
int ret = 0;
struct device *dev = &i2c->dev;
tc358749x->gpio_int = devm_gpiod_get_optional(dev, "int",
GPIOD_OUT_HIGH);
if (IS_ERR(tc358749x->gpio_int)) {
ret = PTR_ERR(tc358749x->gpio_int);
dev_err(&i2c->dev, "Unable to claim gpio \"int\".\n");
return ret;
}
/* I2C Slave Address selection through boot-strap */
gpiod_direction_output(tc358749x->gpio_int, 0);
tc358749x->gpio_power = devm_gpiod_get_optional(dev, "power",
GPIOD_OUT_HIGH);
if (IS_ERR(tc358749x->gpio_power)) {
ret = PTR_ERR(tc358749x->gpio_power);
dev_err(&i2c->dev, "Unable to claim gpio \"power\".\n");
return ret;
}
gpiod_direction_output(tc358749x->gpio_power, 1);
tc358749x->gpio_power18 = devm_gpiod_get_optional(dev, "power18",
GPIOD_OUT_HIGH);
if (IS_ERR(tc358749x->gpio_power18)) {
ret = PTR_ERR(tc358749x->gpio_power18);
dev_err(&i2c->dev, "Unable to claim gpio \"power18\".\n");
return ret;
}
gpiod_direction_output(tc358749x->gpio_power18, 1);
tc358749x->gpio_power33 = devm_gpiod_get_optional(dev, "power33",
GPIOD_OUT_HIGH);
if (IS_ERR(tc358749x->gpio_power33)) {
ret = PTR_ERR(tc358749x->gpio_power33);
dev_err(&i2c->dev, "Unable to claim gpio \"power33\".\n");
return ret;
}
gpiod_direction_output(tc358749x->gpio_power33, 1);
tc358749x->gpio_csi_ctl = devm_gpiod_get_optional(dev, "csi-ctl",
GPIOD_OUT_LOW);
if (IS_ERR(tc358749x->gpio_csi_ctl)) {
ret = PTR_ERR(tc358749x->gpio_csi_ctl);
dev_err(&i2c->dev, "Unable to claim gpio \"csi-ctl\".\n");
return ret;
}
gpiod_direction_output(tc358749x->gpio_csi_ctl, 0);
tc358749x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(tc358749x->gpio_reset)) {
ret = PTR_ERR(tc358749x->gpio_reset);
dev_err(&i2c->dev, "Unable to claim gpio \"reset\".\n");
return ret;
}
gpiod_direction_output(tc358749x->gpio_reset, 1);
tc358749x->gpio_stanby = devm_gpiod_get_optional(dev, "stanby",
GPIOD_OUT_LOW);
if (IS_ERR(tc358749x->gpio_stanby)) {
ret = PTR_ERR(tc358749x->gpio_stanby);
dev_err(&i2c->dev, "Unable to claim gpio \"stanby\".\n");
return ret;
}
gpiod_direction_output(tc358749x->gpio_stanby, 1);
/* Wait 10ms tc358749x lock I2C Slave address */
usleep_range(10000, 11000);
/* after I2C address has been lock and set it input */
gpiod_direction_input(tc358749x->gpio_int);
return 0;
}
static int tc358749x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tc358749x_priv *tc358749x;
int ret;
tc358749x = devm_kzalloc(&i2c->dev, sizeof(*tc358749x),
GFP_KERNEL);
if (!tc358749x)
return -ENOMEM;
i2c_set_clientdata(i2c, tc358749x);
tc358749x_parse_dts(i2c, tc358749x);
tc358749x->regmap = devm_regmap_init_i2c(i2c, &tc358749x_regmap_config);
if (IS_ERR(tc358749x->regmap)) {
ret = PTR_ERR(tc358749x->regmap);
dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
return ret;
}
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tc358749x,
&tc358749x_dai, 1);
dev_info(&i2c->dev, "%s success\n", __func__);
return ret;
}
static int tc358749x_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
return 0;
}
static struct i2c_driver tc358749x_i2c_driver = {
.driver = {
.name = "tc358749x",
},
.probe = tc358749x_i2c_probe,
.remove = tc358749x_i2c_remove,
.id_table = tc358749x_i2c_id,
};
module_i2c_driver(tc358749x_i2c_driver);
MODULE_AUTHOR("Roy <luoxiaotan@rock-chips.com>");
MODULE_DESCRIPTION("TC358749X HDMI Audio RX ASoC Interface");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,53 @@
/*
* tc358749x.h TC358749XBG ALSA SoC audio codec driver
*
* Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd
* Author: Roy <luoxiaotan@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
*/
#ifndef _TC358749X_H
#define _TC358749X_H
#define TC358749X_FORCE_MUTE 0x8600
#define MUTE 0x1
#define FORCE_DMUTE_MASK BIT(0)
#define FORCE_AMUTE_MASK BIT(4)
#define TC358749X_FS_SET 0x8621
#define FS_SET_MASK 0xf
#define FS_44100 0x0
#define FS_48000 0x2
#define FS_32000 0x3
#define FS_22050 0x4
#define FS_24000 0x6
#define FS_88200 0x8
#define FS_96000 0xa
#define FS_176400 0xc
#define FS_192000 0xe
struct tc358749x_priv {
struct regmap *regmap;
struct i2c_client *client;
struct device *dev;
struct gpio_desc *gpio_power;
struct gpio_desc *gpio_power18;
struct gpio_desc *gpio_power33;
struct gpio_desc *gpio_csi_ctl;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_stanby;
struct gpio_desc *gpio_int;
};
#endif