Skip to content

Commit 80eba80

Browse files
LuoXiaoTanrkhuangtao
authored andcommitted
ASoC: codecs: add tc358749x codec driver
add tc358749x codec driver for hdmiin function Change-Id: I819ac80ced59b5d81d547f7ba2c7ebc7bee7f845 Signed-off-by: LuoXiaoTan <lxt@rock-chips.com>
1 parent cd13e47 commit 80eba80

4 files changed

Lines changed: 367 additions & 0 deletions

File tree

sound/soc/codecs/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,10 @@ config SND_SOC_TAS571X
689689
tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
690690
depends on I2C
691691

692+
config SND_SOC_TC358749X
693+
tristate "Toshiba TC358749X HDMI in Audio codec"
694+
depends on I2C
695+
692696
config SND_SOC_TFA9879
693697
tristate "NXP Semiconductors TFA9879 amplifier"
694698
depends on I2C

sound/soc/codecs/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ snd-soc-stac9766-objs := stac9766.o
121121
snd-soc-sti-sas-objs := sti-sas.o
122122
snd-soc-tas5086-objs := tas5086.o
123123
snd-soc-tas571x-objs := tas571x.o
124+
snd-soc-tc358749x-objs := tc358749x.o
124125
snd-soc-tfa9879-objs := tfa9879.o
125126
snd-soc-tlv320aic23-objs := tlv320aic23.o
126127
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
@@ -319,6 +320,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o
319320
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
320321
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
321322
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
323+
obj-$(CONFIG_SND_SOC_TC358749X) += snd-soc-tc358749x.o
322324
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
323325
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
324326
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o

sound/soc/codecs/tc358749x.c

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
/*
2+
* tc358749x.c TC358749XBG ALSA SoC audio codec driver
3+
*
4+
* Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd
5+
* Author: Roy <luoxiaotan@rock-chips.com>
6+
*
7+
* This program is free software; you can redistribute it and/or modify it
8+
* under the terms and conditions of the GNU General Public License,
9+
* version 2, as published by the Free Software Foundation.
10+
*
11+
* This program is distributed in the hope it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14+
* more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
18+
*
19+
*/
20+
21+
#include <linux/module.h>
22+
#include <linux/delay.h>
23+
#include <linux/gpio.h>
24+
#include <linux/gpio/consumer.h>
25+
#include <linux/init.h>
26+
#include <linux/i2c.h>
27+
#include <linux/of_gpio.h>
28+
#include <linux/regmap.h>
29+
#include <sound/soc.h>
30+
31+
#include "tc358749x.h"
32+
33+
static int snd_tc358749x_dai_hw_params(struct snd_pcm_substream *substream,
34+
struct snd_pcm_hw_params *params,
35+
struct snd_soc_dai *codec_dai)
36+
{
37+
struct snd_soc_codec *codec = codec_dai->codec;
38+
unsigned int fs;
39+
40+
switch (params_rate(params)) {
41+
case 32000:
42+
fs = FS_32000;
43+
break;
44+
case 44100:
45+
fs = FS_44100;
46+
break;
47+
case 48000:
48+
fs = FS_48000;
49+
break;
50+
case 88200:
51+
fs = FS_88200;
52+
break;
53+
case 96000:
54+
fs = FS_96000;
55+
break;
56+
case 176400:
57+
fs = FS_176400;
58+
break;
59+
case 192000:
60+
fs = FS_192000;
61+
break;
62+
default:
63+
dev_err(codec->dev, "Enter:%s, %d, Error rate=%d\n",
64+
__func__, __LINE__, params_rate(params));
65+
return -EINVAL;
66+
}
67+
snd_soc_update_bits(codec, TC358749X_FS_SET, FS_SET_MASK, fs);
68+
return 0;
69+
}
70+
71+
static int snd_tc358749x_mute(struct snd_soc_dai *dai, int mute)
72+
{
73+
struct snd_soc_codec *codec = dai->codec;
74+
75+
if (mute)
76+
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
77+
FORCE_DMUTE_MASK, MUTE);
78+
else
79+
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
80+
FORCE_DMUTE_MASK, !MUTE);
81+
82+
return 0;
83+
}
84+
85+
static const struct snd_soc_dai_ops tc358749x_dai_ops = {
86+
.hw_params = snd_tc358749x_dai_hw_params,
87+
.digital_mute = snd_tc358749x_mute,
88+
};
89+
90+
static struct snd_soc_dai_driver tc358749x_dai = {
91+
.name = "tc358749x-audio",
92+
.playback = {
93+
.stream_name = "Playback",
94+
.channels_min = 2,
95+
.channels_max = 8,
96+
.rates = SNDRV_PCM_RATE_32000 |
97+
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
98+
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
99+
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
100+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
101+
},
102+
103+
.capture = {
104+
.stream_name = "Capture",
105+
.channels_min = 2,
106+
.channels_max = 8,
107+
.rates = SNDRV_PCM_RATE_32000 |
108+
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
109+
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
110+
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
111+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
112+
},
113+
.ops = &tc358749x_dai_ops,
114+
};
115+
116+
static int tc358749x_probe(struct snd_soc_codec *codec)
117+
{
118+
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
119+
return 0;
120+
}
121+
122+
static int tc358749_set_bias_level(struct snd_soc_codec *codec,
123+
enum snd_soc_bias_level level)
124+
{
125+
switch (level) {
126+
case SND_SOC_BIAS_ON:
127+
break;
128+
129+
case SND_SOC_BIAS_PREPARE:
130+
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
131+
FORCE_DMUTE_MASK, !MUTE);
132+
break;
133+
134+
case SND_SOC_BIAS_STANDBY:
135+
break;
136+
137+
case SND_SOC_BIAS_OFF:
138+
snd_soc_update_bits(codec, TC358749X_FORCE_MUTE,
139+
FORCE_DMUTE_MASK, MUTE);
140+
break;
141+
}
142+
143+
return 0;
144+
}
145+
146+
static struct snd_soc_codec_driver soc_codec_dev_tc358749x = {
147+
.probe = tc358749x_probe,
148+
.set_bias_level = tc358749_set_bias_level,
149+
};
150+
151+
static bool tc358749x_readable_register(struct device *dev, unsigned int reg)
152+
{
153+
switch (reg) {
154+
case TC358749X_FORCE_MUTE:
155+
case TC358749X_FS_SET:
156+
return true;
157+
default:
158+
return false;
159+
}
160+
}
161+
162+
static const struct reg_default tc358749x_reg_defaults[] = {
163+
{ TC358749X_FORCE_MUTE, 0xb1 },
164+
{ TC358749X_FS_SET, 0x00 },
165+
};
166+
167+
const struct regmap_config tc358749x_regmap_config = {
168+
.reg_bits = 16,
169+
.val_bits = 8,
170+
.max_register = TC358749X_FS_SET,
171+
.cache_type = REGCACHE_RBTREE,
172+
.reg_defaults = tc358749x_reg_defaults,
173+
.num_reg_defaults = ARRAY_SIZE(tc358749x_reg_defaults),
174+
.readable_reg = tc358749x_readable_register,
175+
};
176+
177+
static const struct i2c_device_id tc358749x_i2c_id[] = {
178+
{ "tc358749x", 0 },
179+
{ }
180+
};
181+
182+
MODULE_DEVICE_TABLE(i2c, tc358749x_i2c_id);
183+
184+
static int tc358749x_parse_dts(struct i2c_client *i2c,
185+
struct tc358749x_priv *tc358749x)
186+
{
187+
int ret = 0;
188+
struct device *dev = &i2c->dev;
189+
190+
tc358749x->gpio_int = devm_gpiod_get_optional(dev, "int",
191+
GPIOD_OUT_HIGH);
192+
if (IS_ERR(tc358749x->gpio_int)) {
193+
ret = PTR_ERR(tc358749x->gpio_int);
194+
dev_err(&i2c->dev, "Unable to claim gpio \"int\".\n");
195+
return ret;
196+
}
197+
/* I2C Slave Address selection through boot-strap */
198+
gpiod_direction_output(tc358749x->gpio_int, 0);
199+
200+
tc358749x->gpio_power = devm_gpiod_get_optional(dev, "power",
201+
GPIOD_OUT_HIGH);
202+
if (IS_ERR(tc358749x->gpio_power)) {
203+
ret = PTR_ERR(tc358749x->gpio_power);
204+
dev_err(&i2c->dev, "Unable to claim gpio \"power\".\n");
205+
return ret;
206+
}
207+
gpiod_direction_output(tc358749x->gpio_power, 1);
208+
209+
tc358749x->gpio_power18 = devm_gpiod_get_optional(dev, "power18",
210+
GPIOD_OUT_HIGH);
211+
if (IS_ERR(tc358749x->gpio_power18)) {
212+
ret = PTR_ERR(tc358749x->gpio_power18);
213+
dev_err(&i2c->dev, "Unable to claim gpio \"power18\".\n");
214+
return ret;
215+
}
216+
gpiod_direction_output(tc358749x->gpio_power18, 1);
217+
218+
tc358749x->gpio_power33 = devm_gpiod_get_optional(dev, "power33",
219+
GPIOD_OUT_HIGH);
220+
if (IS_ERR(tc358749x->gpio_power33)) {
221+
ret = PTR_ERR(tc358749x->gpio_power33);
222+
dev_err(&i2c->dev, "Unable to claim gpio \"power33\".\n");
223+
return ret;
224+
}
225+
gpiod_direction_output(tc358749x->gpio_power33, 1);
226+
227+
tc358749x->gpio_csi_ctl = devm_gpiod_get_optional(dev, "csi-ctl",
228+
GPIOD_OUT_LOW);
229+
if (IS_ERR(tc358749x->gpio_csi_ctl)) {
230+
ret = PTR_ERR(tc358749x->gpio_csi_ctl);
231+
dev_err(&i2c->dev, "Unable to claim gpio \"csi-ctl\".\n");
232+
return ret;
233+
}
234+
gpiod_direction_output(tc358749x->gpio_csi_ctl, 0);
235+
236+
tc358749x->gpio_reset = devm_gpiod_get_optional(dev, "reset",
237+
GPIOD_OUT_HIGH);
238+
if (IS_ERR(tc358749x->gpio_reset)) {
239+
ret = PTR_ERR(tc358749x->gpio_reset);
240+
dev_err(&i2c->dev, "Unable to claim gpio \"reset\".\n");
241+
return ret;
242+
}
243+
gpiod_direction_output(tc358749x->gpio_reset, 1);
244+
245+
tc358749x->gpio_stanby = devm_gpiod_get_optional(dev, "stanby",
246+
GPIOD_OUT_LOW);
247+
if (IS_ERR(tc358749x->gpio_stanby)) {
248+
ret = PTR_ERR(tc358749x->gpio_stanby);
249+
dev_err(&i2c->dev, "Unable to claim gpio \"stanby\".\n");
250+
return ret;
251+
}
252+
gpiod_direction_output(tc358749x->gpio_stanby, 1);
253+
254+
/* Wait 10ms tc358749x lock I2C Slave address */
255+
usleep_range(10000, 11000);
256+
/* after I2C address has been lock and set it input */
257+
gpiod_direction_input(tc358749x->gpio_int);
258+
return 0;
259+
}
260+
261+
static int tc358749x_i2c_probe(struct i2c_client *i2c,
262+
const struct i2c_device_id *id)
263+
{
264+
struct tc358749x_priv *tc358749x;
265+
int ret;
266+
267+
tc358749x = devm_kzalloc(&i2c->dev, sizeof(*tc358749x),
268+
GFP_KERNEL);
269+
if (!tc358749x)
270+
return -ENOMEM;
271+
272+
i2c_set_clientdata(i2c, tc358749x);
273+
tc358749x_parse_dts(i2c, tc358749x);
274+
275+
tc358749x->regmap = devm_regmap_init_i2c(i2c, &tc358749x_regmap_config);
276+
if (IS_ERR(tc358749x->regmap)) {
277+
ret = PTR_ERR(tc358749x->regmap);
278+
dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
279+
return ret;
280+
}
281+
282+
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tc358749x,
283+
&tc358749x_dai, 1);
284+
285+
dev_info(&i2c->dev, "%s success\n", __func__);
286+
return ret;
287+
}
288+
289+
static int tc358749x_i2c_remove(struct i2c_client *i2c)
290+
{
291+
snd_soc_unregister_codec(&i2c->dev);
292+
293+
return 0;
294+
}
295+
296+
static struct i2c_driver tc358749x_i2c_driver = {
297+
.driver = {
298+
.name = "tc358749x",
299+
},
300+
.probe = tc358749x_i2c_probe,
301+
.remove = tc358749x_i2c_remove,
302+
.id_table = tc358749x_i2c_id,
303+
};
304+
module_i2c_driver(tc358749x_i2c_driver);
305+
306+
MODULE_AUTHOR("Roy <luoxiaotan@rock-chips.com>");
307+
MODULE_DESCRIPTION("TC358749X HDMI Audio RX ASoC Interface");
308+
MODULE_LICENSE("GPL");

sound/soc/codecs/tc358749x.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* tc358749x.h TC358749XBG ALSA SoC audio codec driver
3+
*
4+
* Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd
5+
* Author: Roy <luoxiaotan@rock-chips.com>
6+
*
7+
* This program is free software; you can redistribute it and/or modify it
8+
* under the terms and conditions of the GNU General Public License,
9+
* version 2, as published by the Free Software Foundation.
10+
*
11+
* This program is distributed in the hope it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14+
* more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
18+
*/
19+
20+
#ifndef _TC358749X_H
21+
#define _TC358749X_H
22+
23+
#define TC358749X_FORCE_MUTE 0x8600
24+
#define MUTE 0x1
25+
#define FORCE_DMUTE_MASK BIT(0)
26+
#define FORCE_AMUTE_MASK BIT(4)
27+
28+
#define TC358749X_FS_SET 0x8621
29+
#define FS_SET_MASK 0xf
30+
#define FS_44100 0x0
31+
#define FS_48000 0x2
32+
#define FS_32000 0x3
33+
#define FS_22050 0x4
34+
#define FS_24000 0x6
35+
#define FS_88200 0x8
36+
#define FS_96000 0xa
37+
#define FS_176400 0xc
38+
#define FS_192000 0xe
39+
40+
struct tc358749x_priv {
41+
struct regmap *regmap;
42+
struct i2c_client *client;
43+
struct device *dev;
44+
struct gpio_desc *gpio_power;
45+
struct gpio_desc *gpio_power18;
46+
struct gpio_desc *gpio_power33;
47+
struct gpio_desc *gpio_csi_ctl;
48+
struct gpio_desc *gpio_reset;
49+
struct gpio_desc *gpio_stanby;
50+
struct gpio_desc *gpio_int;
51+
};
52+
53+
#endif

0 commit comments

Comments
 (0)